blob: 9ca1100afa15b1d3e8cd74846ea0991c5b76227d [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 Thomason624d43f2012-10-12 10:58:48 -0700858 if ( !_document->Error() ) {
859 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700860 }
861 break;
862 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800863
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400864 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700865 // We read the end tag. Return it to the parent.
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400866 if ( ele && ele->ClosingType() == XMLElement::CLOSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700867 if ( parentEnd ) {
Lee Thomason29658802014-11-27 22:31:11 -0800868 ele->_value.TransferTo( parentEnd );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700869 }
Lee Thomason5b0a6772012-11-19 13:54:42 -0800870 node->_memPool->SetTracked(); // created and then immediately deleted.
Dmitry-Mee3225b12014-09-03 11:03:11 +0400871 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700872 return p;
873 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800874
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700875 // Handle an end tag returned to this level.
876 // And handle a bunch of annoying errors.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700877 if ( ele ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400878 bool mismatch = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700879 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400880 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700881 }
882 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400883 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700884 }
885 else if ( !endTag.Empty() ) {
886 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400887 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700888 }
889 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400890 if ( mismatch ) {
891 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -0500892 DeleteNode( node );
893 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400894 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700895 }
JayXondbfdd8f2014-12-12 20:07:14 -0500896 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700897 }
898 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800899}
900
Dmitry-Mee3225b12014-09-03 11:03:11 +0400901void XMLNode::DeleteNode( XMLNode* node )
902{
903 if ( node == 0 ) {
904 return;
905 }
906 MemPool* pool = node->_memPool;
907 node->~XMLNode();
908 pool->Free( node );
909}
910
Lee Thomason5492a1c2012-01-23 15:32:10 -0800911// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800912char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800913{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700914 const char* start = p;
915 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700916 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700917 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700918 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700919 }
920 return p;
921 }
922 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700923 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
924 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700925 flags |= StrPair::COLLAPSE_WHITESPACE;
926 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700927
Lee Thomason624d43f2012-10-12 10:58:48 -0700928 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700929 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700930 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700931 }
932 if ( p && *p ) {
933 return p-1;
934 }
935 }
936 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800937}
938
939
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800940XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
941{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700942 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700943 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700944 }
945 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
946 text->SetCData( this->CData() );
947 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800948}
949
950
951bool XMLText::ShallowEqual( const XMLNode* compare ) const
952{
Dmitry-Me6d202ff2014-09-26 14:21:00 +0400953 const XMLText* text = compare->ToText();
954 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800955}
956
957
Lee Thomason56bdd022012-02-09 18:16:58 -0800958bool XMLText::Accept( XMLVisitor* visitor ) const
959{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300960 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700961 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800962}
963
964
Lee Thomason3f57d272012-01-11 15:30:03 -0800965// --------- XMLComment ---------- //
966
Lee Thomasone4422302012-01-20 17:59:50 -0800967XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800968{
969}
970
971
Lee Thomasonce0763e2012-01-11 15:43:54 -0800972XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800973{
Lee Thomason3f57d272012-01-11 15:30:03 -0800974}
975
976
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800977char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800978{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700979 // Comment parses as text.
980 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700981 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700982 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700983 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700984 }
985 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800986}
987
988
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800989XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
990{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700991 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700992 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700993 }
994 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
995 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800996}
997
998
999bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1000{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001001 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001002 const XMLComment* comment = compare->ToComment();
1003 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001004}
1005
1006
Lee Thomason751da522012-02-10 08:50:51 -08001007bool XMLComment::Accept( XMLVisitor* visitor ) const
1008{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001009 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001010 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001011}
Lee Thomason56bdd022012-02-09 18:16:58 -08001012
1013
Lee Thomason50f97b22012-02-11 16:33:40 -08001014// --------- XMLDeclaration ---------- //
1015
1016XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1017{
1018}
1019
1020
1021XMLDeclaration::~XMLDeclaration()
1022{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001023 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001024}
1025
1026
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001027char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001028{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001029 // Declaration parses as text.
1030 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001031 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001032 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001033 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001034 }
1035 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001036}
1037
1038
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001039XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1040{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001041 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001042 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001043 }
1044 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1045 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001046}
1047
1048
1049bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1050{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001051 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001052 const XMLDeclaration* declaration = compare->ToDeclaration();
1053 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001054}
1055
1056
1057
Lee Thomason50f97b22012-02-11 16:33:40 -08001058bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1059{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001060 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001061 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001062}
1063
1064// --------- XMLUnknown ---------- //
1065
1066XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1067{
1068}
1069
1070
1071XMLUnknown::~XMLUnknown()
1072{
1073}
1074
1075
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001076char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001077{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001078 // Unknown parses as text.
1079 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001080
Lee Thomason624d43f2012-10-12 10:58:48 -07001081 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001082 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001083 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001084 }
1085 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001086}
1087
1088
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001089XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1090{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001091 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001092 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001093 }
1094 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1095 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001096}
1097
1098
1099bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1100{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001101 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001102 const XMLUnknown* unknown = compare->ToUnknown();
1103 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001104}
1105
1106
Lee Thomason50f97b22012-02-11 16:33:40 -08001107bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1108{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001109 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001110 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001111}
1112
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001113// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001114
1115const char* XMLAttribute::Name() const
1116{
1117 return _name.GetStr();
1118}
1119
1120const char* XMLAttribute::Value() const
1121{
1122 return _value.GetStr();
1123}
1124
Lee Thomason6f381b72012-03-02 12:59:39 -08001125char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001126{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001127 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001128 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001129 if ( !p || !*p ) {
1130 return 0;
1131 }
Lee Thomason22aead12012-01-23 13:29:35 -08001132
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001133 // Skip white space before =
1134 p = XMLUtil::SkipWhiteSpace( p );
1135 if ( !p || *p != '=' ) {
1136 return 0;
1137 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001138
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001139 ++p; // move up to opening quote
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 char endTag[2] = { *p, 0 };
1146 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001147
Lee Thomason624d43f2012-10-12 10:58:48 -07001148 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001149 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001150}
1151
1152
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001153void XMLAttribute::SetName( const char* n )
1154{
Lee Thomason624d43f2012-10-12 10:58:48 -07001155 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001156}
1157
1158
Lee Thomason2fa81722012-11-09 12:37:46 -08001159XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001160{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001161 if ( XMLUtil::ToInt( Value(), value )) {
1162 return XML_NO_ERROR;
1163 }
1164 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001165}
1166
1167
Lee Thomason2fa81722012-11-09 12:37:46 -08001168XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001169{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001170 if ( XMLUtil::ToUnsigned( Value(), value )) {
1171 return XML_NO_ERROR;
1172 }
1173 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001174}
1175
1176
Lee Thomason2fa81722012-11-09 12:37:46 -08001177XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001178{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001179 if ( XMLUtil::ToBool( Value(), value )) {
1180 return XML_NO_ERROR;
1181 }
1182 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001183}
1184
1185
Lee Thomason2fa81722012-11-09 12:37:46 -08001186XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001187{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001188 if ( XMLUtil::ToFloat( Value(), value )) {
1189 return XML_NO_ERROR;
1190 }
1191 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001192}
1193
1194
Lee Thomason2fa81722012-11-09 12:37:46 -08001195XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001196{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001197 if ( XMLUtil::ToDouble( Value(), value )) {
1198 return XML_NO_ERROR;
1199 }
1200 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001201}
1202
1203
1204void XMLAttribute::SetAttribute( const char* v )
1205{
Lee Thomason624d43f2012-10-12 10:58:48 -07001206 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001207}
1208
1209
Lee Thomason1ff38e02012-02-14 18:18:16 -08001210void XMLAttribute::SetAttribute( int v )
1211{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001212 char buf[BUF_SIZE];
1213 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001214 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001215}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001216
1217
1218void XMLAttribute::SetAttribute( unsigned v )
1219{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001220 char buf[BUF_SIZE];
1221 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001222 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001223}
1224
1225
1226void XMLAttribute::SetAttribute( bool v )
1227{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001228 char buf[BUF_SIZE];
1229 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001230 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001231}
1232
1233void XMLAttribute::SetAttribute( double v )
1234{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001235 char buf[BUF_SIZE];
1236 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001237 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001238}
1239
1240void XMLAttribute::SetAttribute( float v )
1241{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001242 char buf[BUF_SIZE];
1243 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001244 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001245}
1246
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001247
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001248// --------- XMLElement ---------- //
1249XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001250 _closingType( 0 ),
1251 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001252{
1253}
1254
1255
1256XMLElement::~XMLElement()
1257{
Lee Thomason624d43f2012-10-12 10:58:48 -07001258 while( _rootAttribute ) {
1259 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001260 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001261 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001262 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001263}
1264
1265
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001266const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1267{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001268 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001269 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1270 return a;
1271 }
1272 }
1273 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001274}
1275
1276
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001277const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001278{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001279 const XMLAttribute* a = FindAttribute( name );
1280 if ( !a ) {
1281 return 0;
1282 }
1283 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1284 return a->Value();
1285 }
1286 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001287}
1288
1289
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001290const char* XMLElement::GetText() const
1291{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001292 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001293 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001294 }
1295 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001296}
1297
1298
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001299void XMLElement::SetText( const char* inText )
1300{
Uli Kusterer869bb592014-01-21 01:36:16 +01001301 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001302 FirstChild()->SetValue( inText );
1303 else {
1304 XMLText* theText = GetDocument()->NewText( inText );
1305 InsertFirstChild( theText );
1306 }
1307}
1308
Lee Thomason5bb2d802014-01-24 10:42:57 -08001309
1310void XMLElement::SetText( int v )
1311{
1312 char buf[BUF_SIZE];
1313 XMLUtil::ToStr( v, buf, BUF_SIZE );
1314 SetText( buf );
1315}
1316
1317
1318void XMLElement::SetText( unsigned v )
1319{
1320 char buf[BUF_SIZE];
1321 XMLUtil::ToStr( v, buf, BUF_SIZE );
1322 SetText( buf );
1323}
1324
1325
1326void XMLElement::SetText( bool v )
1327{
1328 char buf[BUF_SIZE];
1329 XMLUtil::ToStr( v, buf, BUF_SIZE );
1330 SetText( buf );
1331}
1332
1333
1334void XMLElement::SetText( float v )
1335{
1336 char buf[BUF_SIZE];
1337 XMLUtil::ToStr( v, buf, BUF_SIZE );
1338 SetText( buf );
1339}
1340
1341
1342void XMLElement::SetText( double v )
1343{
1344 char buf[BUF_SIZE];
1345 XMLUtil::ToStr( v, buf, BUF_SIZE );
1346 SetText( buf );
1347}
1348
1349
MortenMacFly4ee49f12013-01-14 20:03:14 +01001350XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001351{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001352 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001353 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001354 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001355 return XML_SUCCESS;
1356 }
1357 return XML_CAN_NOT_CONVERT_TEXT;
1358 }
1359 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001360}
1361
1362
MortenMacFly4ee49f12013-01-14 20:03:14 +01001363XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001364{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001365 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001366 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001367 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001368 return XML_SUCCESS;
1369 }
1370 return XML_CAN_NOT_CONVERT_TEXT;
1371 }
1372 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001373}
1374
1375
MortenMacFly4ee49f12013-01-14 20:03:14 +01001376XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001377{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001378 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001379 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001380 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001381 return XML_SUCCESS;
1382 }
1383 return XML_CAN_NOT_CONVERT_TEXT;
1384 }
1385 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001386}
1387
1388
MortenMacFly4ee49f12013-01-14 20:03:14 +01001389XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001390{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001391 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001392 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001393 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001394 return XML_SUCCESS;
1395 }
1396 return XML_CAN_NOT_CONVERT_TEXT;
1397 }
1398 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001399}
1400
1401
MortenMacFly4ee49f12013-01-14 20:03:14 +01001402XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001403{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001404 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001405 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001406 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001407 return XML_SUCCESS;
1408 }
1409 return XML_CAN_NOT_CONVERT_TEXT;
1410 }
1411 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001412}
1413
1414
1415
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001416XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1417{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001418 XMLAttribute* last = 0;
1419 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001420 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001421 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001422 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001423 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1424 break;
1425 }
1426 }
1427 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001428 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001429 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1430 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001431 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001432 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001433 }
1434 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001435 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001436 }
1437 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001438 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001439 }
1440 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001441}
1442
1443
U-Stream\Leeae25a442012-02-17 17:48:16 -08001444void XMLElement::DeleteAttribute( const char* name )
1445{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001446 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001447 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001448 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1449 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001450 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001451 }
1452 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001453 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001454 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001455 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001456 break;
1457 }
1458 prev = a;
1459 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001460}
1461
1462
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001463char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001464{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001465 const char* start = p;
1466 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001467
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001468 // Read the attributes.
1469 while( p ) {
1470 p = XMLUtil::SkipWhiteSpace( p );
1471 if ( !p || !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001472 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001473 return 0;
1474 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001475
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001476 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001477 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001478 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001479 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1480 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001481 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001482
Lee Thomason624d43f2012-10-12 10:58:48 -07001483 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001484 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001485 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001486 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001487 return 0;
1488 }
1489 // There is a minor bug here: if the attribute in the source xml
1490 // document is duplicated, it will not be detected and the
1491 // attribute will be doubly added. However, tracking the 'prevAttribute'
1492 // avoids re-scanning the attribute list. Preferring performance for
1493 // now, may reconsider in the future.
1494 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001495 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001496 }
1497 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001498 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001499 }
1500 prevAttribute = attrib;
1501 }
1502 // end of the tag
1503 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001504 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001505 return p+2; // done; sealed element.
1506 }
1507 // end of the tag
1508 else if ( *p == '>' ) {
1509 ++p;
1510 break;
1511 }
1512 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001513 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001514 return 0;
1515 }
1516 }
1517 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001518}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001519
Dmitry-Mee3225b12014-09-03 11:03:11 +04001520void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1521{
1522 if ( attribute == 0 ) {
1523 return;
1524 }
1525 MemPool* pool = attribute->_memPool;
1526 attribute->~XMLAttribute();
1527 pool->Free( attribute );
1528}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001529
Lee Thomason67d61312012-01-24 16:01:51 -08001530//
1531// <ele></ele>
1532// <ele>foo<b>bar</b></ele>
1533//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001534char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001535{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001536 // Read the element name.
1537 p = XMLUtil::SkipWhiteSpace( p );
1538 if ( !p ) {
1539 return 0;
1540 }
Lee Thomason67d61312012-01-24 16:01:51 -08001541
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001542 // The closing element is the </element> form. It is
1543 // parsed just like a regular element then deleted from
1544 // the DOM.
1545 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001546 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001547 ++p;
1548 }
Lee Thomason67d61312012-01-24 16:01:51 -08001549
Lee Thomason624d43f2012-10-12 10:58:48 -07001550 p = _value.ParseName( p );
1551 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001552 return 0;
1553 }
Lee Thomason67d61312012-01-24 16:01:51 -08001554
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001555 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001556 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001557 return p;
1558 }
Lee Thomason67d61312012-01-24 16:01:51 -08001559
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001560 p = XMLNode::ParseDeep( p, strPair );
1561 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001562}
1563
1564
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001565
1566XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1567{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001568 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001569 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001570 }
1571 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1572 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1573 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1574 }
1575 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001576}
1577
1578
1579bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1580{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001581 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001582 const XMLElement* other = compare->ToElement();
1583 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001584
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001585 const XMLAttribute* a=FirstAttribute();
1586 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001587
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001588 while ( a && b ) {
1589 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1590 return false;
1591 }
1592 a = a->Next();
1593 b = b->Next();
1594 }
1595 if ( a || b ) {
1596 // different count
1597 return false;
1598 }
1599 return true;
1600 }
1601 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001602}
1603
1604
Lee Thomason751da522012-02-10 08:50:51 -08001605bool XMLElement::Accept( XMLVisitor* visitor ) const
1606{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001607 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001608 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001609 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1610 if ( !node->Accept( visitor ) ) {
1611 break;
1612 }
1613 }
1614 }
1615 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001616}
Lee Thomason56bdd022012-02-09 18:16:58 -08001617
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001618
Lee Thomason3f57d272012-01-11 15:30:03 -08001619// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001620
1621// Warning: List must match 'enum XMLError'
1622const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1623 "XML_SUCCESS",
1624 "XML_NO_ATTRIBUTE",
1625 "XML_WRONG_ATTRIBUTE_TYPE",
1626 "XML_ERROR_FILE_NOT_FOUND",
1627 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1628 "XML_ERROR_FILE_READ_ERROR",
1629 "XML_ERROR_ELEMENT_MISMATCH",
1630 "XML_ERROR_PARSING_ELEMENT",
1631 "XML_ERROR_PARSING_ATTRIBUTE",
1632 "XML_ERROR_IDENTIFYING_TAG",
1633 "XML_ERROR_PARSING_TEXT",
1634 "XML_ERROR_PARSING_CDATA",
1635 "XML_ERROR_PARSING_COMMENT",
1636 "XML_ERROR_PARSING_DECLARATION",
1637 "XML_ERROR_PARSING_UNKNOWN",
1638 "XML_ERROR_EMPTY_DOCUMENT",
1639 "XML_ERROR_MISMATCHED_ELEMENT",
1640 "XML_ERROR_PARSING",
1641 "XML_CAN_NOT_CONVERT_TEXT",
1642 "XML_NO_TEXT_NODE"
1643};
1644
1645
Lee Thomason624d43f2012-10-12 10:58:48 -07001646XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001647 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001648 _writeBOM( false ),
1649 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001650 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001651 _whitespace( whitespace ),
1652 _errorStr1( 0 ),
1653 _errorStr2( 0 ),
1654 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001655{
Lee Thomason624d43f2012-10-12 10:58:48 -07001656 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001657}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001658
1659
Lee Thomason3f57d272012-01-11 15:30:03 -08001660XMLDocument::~XMLDocument()
1661{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001662 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001663}
1664
1665
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001666void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001667{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001668 DeleteChildren();
1669
Dmitry-Meab37df82014-11-28 12:08:36 +03001670#ifdef DEBUG
1671 const bool hadError = Error();
1672#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001673 _errorID = XML_NO_ERROR;
1674 _errorStr1 = 0;
1675 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001676
Lee Thomason624d43f2012-10-12 10:58:48 -07001677 delete [] _charBuffer;
1678 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001679
1680#if 0
1681 _textPool.Trace( "text" );
1682 _elementPool.Trace( "element" );
1683 _commentPool.Trace( "comment" );
1684 _attributePool.Trace( "attribute" );
1685#endif
1686
1687#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001688 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001689 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1690 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1691 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1692 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1693 }
1694#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001695}
1696
Lee Thomason3f57d272012-01-11 15:30:03 -08001697
Lee Thomason2c85a712012-01-31 08:24:24 -08001698XMLElement* XMLDocument::NewElement( const char* name )
1699{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001700 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001701 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1702 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001703 ele->SetName( name );
1704 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001705}
1706
1707
Lee Thomason1ff38e02012-02-14 18:18:16 -08001708XMLComment* XMLDocument::NewComment( const char* str )
1709{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001710 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001711 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1712 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001713 comment->SetValue( str );
1714 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001715}
1716
1717
1718XMLText* XMLDocument::NewText( const char* str )
1719{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001720 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001721 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1722 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001723 text->SetValue( str );
1724 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001725}
1726
1727
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001728XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1729{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001730 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001731 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1732 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001733 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1734 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001735}
1736
1737
1738XMLUnknown* XMLDocument::NewUnknown( const char* str )
1739{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001740 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001741 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1742 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001743 unk->SetValue( str );
1744 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001745}
1746
Dmitry-Me01578db2014-08-19 10:18:48 +04001747static FILE* callfopen( const char* filepath, const char* mode )
1748{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001749 TIXMLASSERT( filepath );
1750 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001751#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1752 FILE* fp = 0;
1753 errno_t err = fopen_s( &fp, filepath, mode );
1754 if ( err ) {
1755 return 0;
1756 }
1757#else
1758 FILE* fp = fopen( filepath, mode );
1759#endif
1760 return fp;
1761}
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001762
Lee Thomason2fa81722012-11-09 12:37:46 -08001763XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001764{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001765 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001766 FILE* fp = callfopen( filename, "rb" );
1767 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001768 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001769 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001770 }
1771 LoadFile( fp );
1772 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001773 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001774}
1775
1776
Lee Thomason2fa81722012-11-09 12:37:46 -08001777XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001778{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001779 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001780
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001781 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001782 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001783 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1784 return _errorID;
1785 }
1786
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001787 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001788 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001789 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001790 if ( filelength == -1L ) {
1791 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1792 return _errorID;
1793 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001794
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001795 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001796 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001797 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001798 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001799 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001800
Lee Thomason624d43f2012-10-12 10:58:48 -07001801 _charBuffer = new char[size+1];
1802 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001803 if ( read != size ) {
1804 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001805 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001806 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001807
Lee Thomason624d43f2012-10-12 10:58:48 -07001808 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001809
Lee Thomason624d43f2012-10-12 10:58:48 -07001810 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001811 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001812 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001813 if ( !p || !*p ) {
1814 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001815 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001816 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001817
Lee Thomason624d43f2012-10-12 10:58:48 -07001818 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1819 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001820}
1821
1822
Lee Thomason2fa81722012-11-09 12:37:46 -08001823XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001824{
Dmitry-Me01578db2014-08-19 10:18:48 +04001825 FILE* fp = callfopen( filename, "w" );
1826 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001827 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001828 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001829 }
1830 SaveFile(fp, compact);
1831 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001832 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001833}
1834
1835
Lee Thomason2fa81722012-11-09 12:37:46 -08001836XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001837{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001838 XMLPrinter stream( fp, compact );
1839 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001840 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001841}
1842
Lee Thomason1ff38e02012-02-14 18:18:16 -08001843
Lee Thomason2fa81722012-11-09 12:37:46 -08001844XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001845{
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001846 const char* start = p;
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001847 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001848
Lee Thomason82d32002014-02-21 22:47:18 -08001849 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001850 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001851 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001852 }
1853 if ( len == (size_t)(-1) ) {
1854 len = strlen( p );
1855 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001856 _charBuffer = new char[ len+1 ];
1857 memcpy( _charBuffer, p, len );
1858 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001859
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001860 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001861 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001862 if ( !p || !*p ) {
1863 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001864 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001865 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001866
Thomas Roß1470edc2013-05-10 15:44:12 +02001867 ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001868 ParseDeep( _charBuffer+delta, 0 );
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001869 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001870 // clean up now essentially dangling memory.
1871 // and the parse fail can put objects in the
1872 // pools that are dead and inaccessible.
1873 DeleteChildren();
1874 _elementPool.Clear();
1875 _attributePool.Clear();
1876 _textPool.Clear();
1877 _commentPool.Clear();
1878 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001879 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001880}
1881
1882
PKEuS1c5f99e2013-07-06 11:28:39 +02001883void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001884{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001885 XMLPrinter stdStreamer( stdout );
1886 if ( !streamer ) {
1887 streamer = &stdStreamer;
1888 }
1889 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001890}
1891
1892
Lee Thomason2fa81722012-11-09 12:37:46 -08001893void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001894{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001895 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07001896 _errorID = error;
1897 _errorStr1 = str1;
1898 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001899}
1900
Lee Thomason331596e2014-09-11 14:56:43 -07001901const char* XMLDocument::ErrorName() const
1902{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001903 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Lee Thomason331596e2014-09-11 14:56:43 -07001904 return _errorNames[_errorID];
1905}
Lee Thomason5cae8972012-01-24 18:03:07 -08001906
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001907void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001908{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001909 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001910 static const int LEN = 20;
1911 char buf1[LEN] = { 0 };
1912 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001913
Lee Thomason624d43f2012-10-12 10:58:48 -07001914 if ( _errorStr1 ) {
1915 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001916 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001917 if ( _errorStr2 ) {
1918 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001919 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001920
Lee Thomason331596e2014-09-11 14:56:43 -07001921 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
1922 _errorID, ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001923 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001924}
1925
1926
PKEuS1bfb9542013-08-04 13:51:17 +02001927XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001928 _elementJustOpened( false ),
1929 _firstElement( true ),
1930 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001931 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001932 _textDepth( -1 ),
1933 _processEntities( true ),
1934 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001935{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001936 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001937 _entityFlag[i] = false;
1938 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001939 }
1940 for( int i=0; i<NUM_ENTITIES; ++i ) {
1941 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1942 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001943 _entityFlag[ (int)entities[i].value ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001944 }
1945 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001946 _restrictedEntityFlag[(int)'&'] = true;
1947 _restrictedEntityFlag[(int)'<'] = true;
1948 _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
1949 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001950}
1951
1952
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001953void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001954{
1955 va_list va;
1956 va_start( va, format );
1957
Lee Thomason624d43f2012-10-12 10:58:48 -07001958 if ( _fp ) {
1959 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001960 }
1961 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001962#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001963 #if defined(WINCE)
1964 int len = 512;
1965 do {
1966 len = len*2;
1967 char* str = new char[len]();
1968 len = _vsnprintf(str, len, format, va);
1969 delete[] str;
1970 }while (len < 0);
1971 #else
Thomas Roß268c6832014-03-13 23:35:16 +01001972 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08001973 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001974#else
1975 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01001976#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001977 // Close out and re-start the va-args
1978 va_end( va );
1979 va_start( va, format );
Lee Thomasona0744c82014-03-16 10:32:27 -07001980 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
1981#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001982 #if defined(WINCE)
1983 _vsnprintf( p, len+1, format, va );
1984 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07001985 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08001986 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07001987#else
1988 vsnprintf( p, len+1, format, va );
1989#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001990 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001991 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001992}
1993
1994
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001995void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001996{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001997 for( int i=0; i<depth; ++i ) {
1998 Print( " " );
1999 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002000}
2001
2002
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002003void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002004{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002005 // Look for runs of bytes between entities to print.
2006 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07002007 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08002008
Lee Thomason624d43f2012-10-12 10:58:48 -07002009 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002010 while ( *q ) {
2011 // Remember, char is sometimes signed. (How many times has that bitten me?)
2012 if ( *q > 0 && *q < ENTITY_RANGE ) {
2013 // Check for entities. If one is found, flush
2014 // the stream up until the entity, write the
2015 // entity, and keep looking.
2016 if ( flag[(unsigned)(*q)] ) {
2017 while ( p < q ) {
2018 Print( "%c", *p );
2019 ++p;
2020 }
2021 for( int i=0; i<NUM_ENTITIES; ++i ) {
2022 if ( entities[i].value == *q ) {
2023 Print( "&%s;", entities[i].pattern );
2024 break;
2025 }
2026 }
2027 ++p;
2028 }
2029 }
2030 ++q;
2031 }
2032 }
2033 // Flush the remaining string. This will be the entire
2034 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07002035 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002036 Print( "%s", p );
2037 }
Lee Thomason857b8682012-01-25 17:50:25 -08002038}
2039
U-Stream\Leeae25a442012-02-17 17:48:16 -08002040
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002041void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002042{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002043 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002044 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 -07002045 Print( "%s", bom );
2046 }
2047 if ( writeDec ) {
2048 PushDeclaration( "xml version=\"1.0\"" );
2049 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002050}
2051
2052
Uli Kusterer593a33d2014-02-01 12:48:51 +01002053void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002054{
Lee Thomason624d43f2012-10-12 10:58:48 -07002055 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002056 SealElement();
2057 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002058 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002059
Uli Kusterer593a33d2014-02-01 12:48:51 +01002060 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002061 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002062 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002063 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002064 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002065 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002066
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002067 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002068 _elementJustOpened = true;
2069 _firstElement = false;
2070 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002071}
2072
2073
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002074void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002075{
Lee Thomason624d43f2012-10-12 10:58:48 -07002076 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002077 Print( " %s=\"", name );
2078 PrintString( value, false );
2079 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002080}
2081
2082
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002083void XMLPrinter::PushAttribute( const char* name, int v )
2084{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002085 char buf[BUF_SIZE];
2086 XMLUtil::ToStr( v, buf, BUF_SIZE );
2087 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002088}
2089
2090
2091void XMLPrinter::PushAttribute( const char* name, unsigned v )
2092{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002093 char buf[BUF_SIZE];
2094 XMLUtil::ToStr( v, buf, BUF_SIZE );
2095 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002096}
2097
2098
2099void XMLPrinter::PushAttribute( const char* name, bool v )
2100{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002101 char buf[BUF_SIZE];
2102 XMLUtil::ToStr( v, buf, BUF_SIZE );
2103 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002104}
2105
2106
2107void XMLPrinter::PushAttribute( const char* name, double v )
2108{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002109 char buf[BUF_SIZE];
2110 XMLUtil::ToStr( v, buf, BUF_SIZE );
2111 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002112}
2113
2114
Uli Kustererca412e82014-02-01 13:35:05 +01002115void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002116{
Lee Thomason624d43f2012-10-12 10:58:48 -07002117 --_depth;
2118 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002119
Lee Thomason624d43f2012-10-12 10:58:48 -07002120 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002121 Print( "/>" );
2122 }
2123 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002124 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002125 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002126 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002127 }
2128 Print( "</%s>", name );
2129 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002130
Lee Thomason624d43f2012-10-12 10:58:48 -07002131 if ( _textDepth == _depth ) {
2132 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002133 }
Uli Kustererca412e82014-02-01 13:35:05 +01002134 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002135 Print( "\n" );
2136 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002137 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002138}
2139
2140
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002141void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08002142{
Lee Thomason624d43f2012-10-12 10:58:48 -07002143 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002144 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002145}
2146
2147
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002148void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002149{
Lee Thomason624d43f2012-10-12 10:58:48 -07002150 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002151
Lee Thomason624d43f2012-10-12 10:58:48 -07002152 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002153 SealElement();
2154 }
2155 if ( cdata ) {
2156 Print( "<![CDATA[" );
2157 Print( "%s", text );
2158 Print( "]]>" );
2159 }
2160 else {
2161 PrintString( text, true );
2162 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002163}
2164
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002165void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002166{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002167 char buf[BUF_SIZE];
2168 XMLUtil::ToStr( value, buf, BUF_SIZE );
2169 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002170}
2171
2172
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002173void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002174{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002175 char buf[BUF_SIZE];
2176 XMLUtil::ToStr( value, buf, BUF_SIZE );
2177 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002178}
2179
2180
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002181void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002182{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002183 char buf[BUF_SIZE];
2184 XMLUtil::ToStr( value, buf, BUF_SIZE );
2185 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002186}
2187
2188
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002189void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002190{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002191 char buf[BUF_SIZE];
2192 XMLUtil::ToStr( value, buf, BUF_SIZE );
2193 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002194}
2195
2196
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002197void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002198{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002199 char buf[BUF_SIZE];
2200 XMLUtil::ToStr( value, buf, BUF_SIZE );
2201 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002202}
2203
Lee Thomason5cae8972012-01-24 18:03:07 -08002204
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002205void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002206{
Lee Thomason624d43f2012-10-12 10:58:48 -07002207 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002208 SealElement();
2209 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002210 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002211 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002212 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002213 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002214 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002215 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002216}
Lee Thomason751da522012-02-10 08:50:51 -08002217
2218
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002219void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002220{
Lee Thomason624d43f2012-10-12 10:58:48 -07002221 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002222 SealElement();
2223 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002224 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002225 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002226 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002227 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002228 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002229 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002230}
2231
2232
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002233void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002234{
Lee Thomason624d43f2012-10-12 10:58:48 -07002235 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002236 SealElement();
2237 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002238 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002239 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002240 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002241 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002242 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002243 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002244}
2245
2246
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002247bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002248{
Lee Thomason624d43f2012-10-12 10:58:48 -07002249 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002250 if ( doc.HasBOM() ) {
2251 PushHeader( true, false );
2252 }
2253 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002254}
2255
2256
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002257bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002258{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002259 const XMLElement* parentElem = element.Parent()->ToElement();
2260 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2261 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002262 while ( attribute ) {
2263 PushAttribute( attribute->Name(), attribute->Value() );
2264 attribute = attribute->Next();
2265 }
2266 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002267}
2268
2269
Uli Kustererca412e82014-02-01 13:35:05 +01002270bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002271{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002272 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002273 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002274}
2275
2276
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002277bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002278{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002279 PushText( text.Value(), text.CData() );
2280 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002281}
2282
2283
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002284bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002285{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002286 PushComment( comment.Value() );
2287 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002288}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002289
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002290bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002291{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002292 PushDeclaration( declaration.Value() );
2293 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002294}
2295
2296
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002297bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002298{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002299 PushUnknown( unknown.Value() );
2300 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002301}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002302
Lee Thomason685b8952012-11-12 13:00:06 -08002303} // namespace tinyxml2
2304