blob: 57a82c1e6afe4681342e961d85fab23dd33b46ae [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 ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700537 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
538 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700539 p += xmlHeaderLen;
540 }
541 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700542 returnNode = new (_commentPool.Alloc()) XMLComment( this );
543 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700544 p += commentHeaderLen;
545 }
546 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700547 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700548 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700549 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700550 p += cdataHeaderLen;
551 text->SetCData( true );
552 }
553 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700554 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
555 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700556 p += dtdHeaderLen;
557 }
558 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700559 returnNode = new (_elementPool.Alloc()) XMLElement( this );
560 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700561 p += elementHeaderLen;
562 }
563 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700564 returnNode = new (_textPool.Alloc()) XMLText( this );
565 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700566 p = start; // Back it up, all the text counts.
567 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800568
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700569 *node = returnNode;
570 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800571}
572
573
Lee Thomason751da522012-02-10 08:50:51 -0800574bool XMLDocument::Accept( XMLVisitor* visitor ) const
575{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700576 if ( visitor->VisitEnter( *this ) ) {
577 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
578 if ( !node->Accept( visitor ) ) {
579 break;
580 }
581 }
582 }
583 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800584}
Lee Thomason56bdd022012-02-09 18:16:58 -0800585
586
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800587// --------- XMLNode ----------- //
588
589XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700590 _document( doc ),
591 _parent( 0 ),
592 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200593 _prev( 0 ), _next( 0 ),
594 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800595{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800596}
597
598
599XMLNode::~XMLNode()
600{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700601 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700602 if ( _parent ) {
603 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700604 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800605}
606
Michael Daumling21626882013-10-22 17:03:37 +0200607const char* XMLNode::Value() const
608{
609 return _value.GetStr();
610}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800611
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800612void XMLNode::SetValue( const char* str, bool staticMem )
613{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700614 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700615 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700616 }
617 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700618 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700619 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800620}
621
622
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800623void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800624{
Lee Thomason624d43f2012-10-12 10:58:48 -0700625 while( _firstChild ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300626 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700627 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700628 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700629
Dmitry-Mee3225b12014-09-03 11:03:11 +0400630 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700631 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700632 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800633}
634
635
636void XMLNode::Unlink( XMLNode* child )
637{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300638 TIXMLASSERT( child->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700639 if ( child == _firstChild ) {
640 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700641 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700642 if ( child == _lastChild ) {
643 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700644 }
Lee Thomasond923c672012-01-23 08:44:25 -0800645
Lee Thomason624d43f2012-10-12 10:58:48 -0700646 if ( child->_prev ) {
647 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700648 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700649 if ( child->_next ) {
650 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700651 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700652 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800653}
654
655
U-Stream\Leeae25a442012-02-17 17:48:16 -0800656void XMLNode::DeleteChild( XMLNode* node )
657{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300658 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700659 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400660 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800661}
662
663
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800664XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
665{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300666 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300667 if ( addThis->_document != _document ) {
668 TIXMLASSERT( false );
669 return 0;
670 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700671
Michael Daumlinged523282013-10-23 07:47:29 +0200672 if (addThis->_parent)
673 addThis->_parent->Unlink( addThis );
674 else
675 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700676
Lee Thomason624d43f2012-10-12 10:58:48 -0700677 if ( _lastChild ) {
678 TIXMLASSERT( _firstChild );
679 TIXMLASSERT( _lastChild->_next == 0 );
680 _lastChild->_next = addThis;
681 addThis->_prev = _lastChild;
682 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800683
Lee Thomason624d43f2012-10-12 10:58:48 -0700684 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700685 }
686 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700687 TIXMLASSERT( _firstChild == 0 );
688 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800689
Lee Thomason624d43f2012-10-12 10:58:48 -0700690 addThis->_prev = 0;
691 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700692 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700693 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700694 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800695}
696
697
Lee Thomason1ff38e02012-02-14 18:18:16 -0800698XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
699{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300700 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300701 if ( addThis->_document != _document ) {
702 TIXMLASSERT( false );
703 return 0;
704 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700705
Michael Daumlinged523282013-10-23 07:47:29 +0200706 if (addThis->_parent)
707 addThis->_parent->Unlink( addThis );
708 else
709 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700710
Lee Thomason624d43f2012-10-12 10:58:48 -0700711 if ( _firstChild ) {
712 TIXMLASSERT( _lastChild );
713 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800714
Lee Thomason624d43f2012-10-12 10:58:48 -0700715 _firstChild->_prev = addThis;
716 addThis->_next = _firstChild;
717 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800718
Lee Thomason624d43f2012-10-12 10:58:48 -0700719 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700720 }
721 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700722 TIXMLASSERT( _lastChild == 0 );
723 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800724
Lee Thomason624d43f2012-10-12 10:58:48 -0700725 addThis->_prev = 0;
726 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700727 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700728 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400729 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800730}
731
732
733XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
734{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300735 TIXMLASSERT( addThis );
736 if ( addThis->_document != _document ) {
737 TIXMLASSERT( false );
738 return 0;
739 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700740
Dmitry-Meabb2d042014-12-09 12:59:31 +0300741 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700742
Lee Thomason624d43f2012-10-12 10:58:48 -0700743 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300744 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700745 return 0;
746 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800747
Lee Thomason624d43f2012-10-12 10:58:48 -0700748 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700749 // The last node or the only node.
750 return InsertEndChild( addThis );
751 }
Michael Daumlinged523282013-10-23 07:47:29 +0200752 if (addThis->_parent)
753 addThis->_parent->Unlink( addThis );
754 else
755 addThis->_memPool->SetTracked();
Lee Thomason624d43f2012-10-12 10:58:48 -0700756 addThis->_prev = afterThis;
757 addThis->_next = afterThis->_next;
758 afterThis->_next->_prev = addThis;
759 afterThis->_next = addThis;
760 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700761 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800762}
763
764
765
766
Lee Thomason56bdd022012-02-09 18:16:58 -0800767const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800768{
Lee Thomason624d43f2012-10-12 10:58:48 -0700769 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700770 XMLElement* element = node->ToElement();
771 if ( element ) {
772 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
773 return element;
774 }
775 }
776 }
777 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800778}
779
780
Lee Thomason56bdd022012-02-09 18:16:58 -0800781const XMLElement* XMLNode::LastChildElement( const char* value ) const
782{
Lee Thomason624d43f2012-10-12 10:58:48 -0700783 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700784 XMLElement* element = node->ToElement();
785 if ( element ) {
786 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
787 return element;
788 }
789 }
790 }
791 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800792}
793
794
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800795const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
796{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400797 for( XMLNode* node=this->_next; node; node = node->_next ) {
798 const XMLElement* element = node->ToElement();
799 if ( element
800 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
801 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700802 }
803 }
804 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800805}
806
807
808const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
809{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400810 for( XMLNode* node=_prev; node; node = node->_prev ) {
811 const XMLElement* element = node->ToElement();
812 if ( element
813 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
814 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700815 }
816 }
817 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800818}
819
820
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800821char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800822{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700823 // This is a recursive method, but thinking about it "at the current level"
824 // it is a pretty simple flat list:
825 // <foo/>
826 // <!-- comment -->
827 //
828 // With a special case:
829 // <foo>
830 // </foo>
831 // <!-- comment -->
832 //
833 // Where the closing element (/foo) *must* be the next thing after the opening
834 // element, and the names must match. BUT the tricky bit is that the closing
835 // element will be read by the child.
836 //
837 // 'endTag' is the end tag for this node, it is returned by a call to a child.
838 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800839
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700840 while( p && *p ) {
841 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800842
Lee Thomason624d43f2012-10-12 10:58:48 -0700843 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700844 if ( p == 0 || node == 0 ) {
845 break;
846 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800847
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700848 StrPair endTag;
849 p = node->ParseDeep( p, &endTag );
850 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400851 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700852 node = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -0700853 if ( !_document->Error() ) {
854 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700855 }
856 break;
857 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800858
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400859 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700860 // We read the end tag. Return it to the parent.
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400861 if ( ele && ele->ClosingType() == XMLElement::CLOSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700862 if ( parentEnd ) {
Lee Thomason29658802014-11-27 22:31:11 -0800863 ele->_value.TransferTo( parentEnd );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700864 }
Lee Thomason5b0a6772012-11-19 13:54:42 -0800865 node->_memPool->SetTracked(); // created and then immediately deleted.
Dmitry-Mee3225b12014-09-03 11:03:11 +0400866 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700867 return p;
868 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800869
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700870 // Handle an end tag returned to this level.
871 // And handle a bunch of annoying errors.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700872 if ( ele ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400873 bool mismatch = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700874 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400875 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700876 }
877 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400878 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700879 }
880 else if ( !endTag.Empty() ) {
881 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400882 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700883 }
884 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400885 if ( mismatch ) {
886 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
887 p = 0;
888 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700889 }
890 if ( p == 0 ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400891 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700892 node = 0;
893 }
894 if ( node ) {
895 this->InsertEndChild( node );
896 }
897 }
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 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001428 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1429 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001430 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001431 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001432 }
1433 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001434 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001435 }
1436 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001437 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001438 }
1439 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001440}
1441
1442
U-Stream\Leeae25a442012-02-17 17:48:16 -08001443void XMLElement::DeleteAttribute( const char* name )
1444{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001445 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001446 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001447 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1448 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001449 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001450 }
1451 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001452 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001453 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001454 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001455 break;
1456 }
1457 prev = a;
1458 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001459}
1460
1461
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001462char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001463{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001464 const char* start = p;
1465 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001466
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001467 // Read the attributes.
1468 while( p ) {
1469 p = XMLUtil::SkipWhiteSpace( p );
1470 if ( !p || !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001471 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001472 return 0;
1473 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001474
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001475 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001476 if (XMLUtil::IsNameStartChar( *p ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001477 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1478 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001479 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001480
Lee Thomason624d43f2012-10-12 10:58:48 -07001481 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001482 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001483 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001484 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001485 return 0;
1486 }
1487 // There is a minor bug here: if the attribute in the source xml
1488 // document is duplicated, it will not be detected and the
1489 // attribute will be doubly added. However, tracking the 'prevAttribute'
1490 // avoids re-scanning the attribute list. Preferring performance for
1491 // now, may reconsider in the future.
1492 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001493 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001494 }
1495 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001496 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001497 }
1498 prevAttribute = attrib;
1499 }
1500 // end of the tag
1501 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001502 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001503 return p+2; // done; sealed element.
1504 }
1505 // end of the tag
1506 else if ( *p == '>' ) {
1507 ++p;
1508 break;
1509 }
1510 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001511 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001512 return 0;
1513 }
1514 }
1515 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001516}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001517
Dmitry-Mee3225b12014-09-03 11:03:11 +04001518void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1519{
1520 if ( attribute == 0 ) {
1521 return;
1522 }
1523 MemPool* pool = attribute->_memPool;
1524 attribute->~XMLAttribute();
1525 pool->Free( attribute );
1526}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001527
Lee Thomason67d61312012-01-24 16:01:51 -08001528//
1529// <ele></ele>
1530// <ele>foo<b>bar</b></ele>
1531//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001532char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001533{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001534 // Read the element name.
1535 p = XMLUtil::SkipWhiteSpace( p );
1536 if ( !p ) {
1537 return 0;
1538 }
Lee Thomason67d61312012-01-24 16:01:51 -08001539
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001540 // The closing element is the </element> form. It is
1541 // parsed just like a regular element then deleted from
1542 // the DOM.
1543 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001544 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001545 ++p;
1546 }
Lee Thomason67d61312012-01-24 16:01:51 -08001547
Lee Thomason624d43f2012-10-12 10:58:48 -07001548 p = _value.ParseName( p );
1549 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001550 return 0;
1551 }
Lee Thomason67d61312012-01-24 16:01:51 -08001552
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001553 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001554 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001555 return p;
1556 }
Lee Thomason67d61312012-01-24 16:01:51 -08001557
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001558 p = XMLNode::ParseDeep( p, strPair );
1559 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001560}
1561
1562
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001563
1564XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1565{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001566 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001567 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001568 }
1569 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1570 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1571 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1572 }
1573 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001574}
1575
1576
1577bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1578{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001579 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001580 const XMLElement* other = compare->ToElement();
1581 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001582
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001583 const XMLAttribute* a=FirstAttribute();
1584 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001585
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001586 while ( a && b ) {
1587 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1588 return false;
1589 }
1590 a = a->Next();
1591 b = b->Next();
1592 }
1593 if ( a || b ) {
1594 // different count
1595 return false;
1596 }
1597 return true;
1598 }
1599 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001600}
1601
1602
Lee Thomason751da522012-02-10 08:50:51 -08001603bool XMLElement::Accept( XMLVisitor* visitor ) const
1604{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001605 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001606 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001607 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1608 if ( !node->Accept( visitor ) ) {
1609 break;
1610 }
1611 }
1612 }
1613 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001614}
Lee Thomason56bdd022012-02-09 18:16:58 -08001615
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001616
Lee Thomason3f57d272012-01-11 15:30:03 -08001617// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001618
1619// Warning: List must match 'enum XMLError'
1620const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1621 "XML_SUCCESS",
1622 "XML_NO_ATTRIBUTE",
1623 "XML_WRONG_ATTRIBUTE_TYPE",
1624 "XML_ERROR_FILE_NOT_FOUND",
1625 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1626 "XML_ERROR_FILE_READ_ERROR",
1627 "XML_ERROR_ELEMENT_MISMATCH",
1628 "XML_ERROR_PARSING_ELEMENT",
1629 "XML_ERROR_PARSING_ATTRIBUTE",
1630 "XML_ERROR_IDENTIFYING_TAG",
1631 "XML_ERROR_PARSING_TEXT",
1632 "XML_ERROR_PARSING_CDATA",
1633 "XML_ERROR_PARSING_COMMENT",
1634 "XML_ERROR_PARSING_DECLARATION",
1635 "XML_ERROR_PARSING_UNKNOWN",
1636 "XML_ERROR_EMPTY_DOCUMENT",
1637 "XML_ERROR_MISMATCHED_ELEMENT",
1638 "XML_ERROR_PARSING",
1639 "XML_CAN_NOT_CONVERT_TEXT",
1640 "XML_NO_TEXT_NODE"
1641};
1642
1643
Lee Thomason624d43f2012-10-12 10:58:48 -07001644XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001645 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001646 _writeBOM( false ),
1647 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001648 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001649 _whitespace( whitespace ),
1650 _errorStr1( 0 ),
1651 _errorStr2( 0 ),
1652 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001653{
Lee Thomason624d43f2012-10-12 10:58:48 -07001654 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001655}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001656
1657
Lee Thomason3f57d272012-01-11 15:30:03 -08001658XMLDocument::~XMLDocument()
1659{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001660 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001661}
1662
1663
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001664void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001665{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001666 DeleteChildren();
1667
Dmitry-Meab37df82014-11-28 12:08:36 +03001668#ifdef DEBUG
1669 const bool hadError = Error();
1670#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001671 _errorID = XML_NO_ERROR;
1672 _errorStr1 = 0;
1673 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001674
Lee Thomason624d43f2012-10-12 10:58:48 -07001675 delete [] _charBuffer;
1676 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001677
1678#if 0
1679 _textPool.Trace( "text" );
1680 _elementPool.Trace( "element" );
1681 _commentPool.Trace( "comment" );
1682 _attributePool.Trace( "attribute" );
1683#endif
1684
1685#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001686 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001687 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1688 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1689 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1690 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1691 }
1692#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001693}
1694
Lee Thomason3f57d272012-01-11 15:30:03 -08001695
Lee Thomason2c85a712012-01-31 08:24:24 -08001696XMLElement* XMLDocument::NewElement( const char* name )
1697{
Lee Thomason624d43f2012-10-12 10:58:48 -07001698 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1699 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001700 ele->SetName( name );
1701 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001702}
1703
1704
Lee Thomason1ff38e02012-02-14 18:18:16 -08001705XMLComment* XMLDocument::NewComment( const char* str )
1706{
Lee Thomason624d43f2012-10-12 10:58:48 -07001707 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1708 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001709 comment->SetValue( str );
1710 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001711}
1712
1713
1714XMLText* XMLDocument::NewText( const char* str )
1715{
Lee Thomason624d43f2012-10-12 10:58:48 -07001716 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1717 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001718 text->SetValue( str );
1719 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001720}
1721
1722
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001723XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1724{
Lee Thomason624d43f2012-10-12 10:58:48 -07001725 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1726 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001727 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1728 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001729}
1730
1731
1732XMLUnknown* XMLDocument::NewUnknown( const char* str )
1733{
Lee Thomason624d43f2012-10-12 10:58:48 -07001734 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1735 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001736 unk->SetValue( str );
1737 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001738}
1739
Dmitry-Me01578db2014-08-19 10:18:48 +04001740static FILE* callfopen( const char* filepath, const char* mode )
1741{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001742 TIXMLASSERT( filepath );
1743 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001744#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1745 FILE* fp = 0;
1746 errno_t err = fopen_s( &fp, filepath, mode );
1747 if ( err ) {
1748 return 0;
1749 }
1750#else
1751 FILE* fp = fopen( filepath, mode );
1752#endif
1753 return fp;
1754}
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001755
Lee Thomason2fa81722012-11-09 12:37:46 -08001756XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001757{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001758 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001759 FILE* fp = callfopen( filename, "rb" );
1760 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001761 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001762 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001763 }
1764 LoadFile( fp );
1765 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001766 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001767}
1768
1769
Lee Thomason2fa81722012-11-09 12:37:46 -08001770XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001771{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001772 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001773
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001774 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001775 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001776 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1777 return _errorID;
1778 }
1779
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001780 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001781 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001782 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001783 if ( filelength == -1L ) {
1784 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1785 return _errorID;
1786 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001787
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001788 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001789 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001790 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001791 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001792 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001793
Lee Thomason624d43f2012-10-12 10:58:48 -07001794 _charBuffer = new char[size+1];
1795 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001796 if ( read != size ) {
1797 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001798 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001799 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001800
Lee Thomason624d43f2012-10-12 10:58:48 -07001801 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001802
Lee Thomason624d43f2012-10-12 10:58:48 -07001803 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001804 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001805 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001806 if ( !p || !*p ) {
1807 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001808 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001809 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001810
Lee Thomason624d43f2012-10-12 10:58:48 -07001811 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1812 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001813}
1814
1815
Lee Thomason2fa81722012-11-09 12:37:46 -08001816XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001817{
Dmitry-Me01578db2014-08-19 10:18:48 +04001818 FILE* fp = callfopen( filename, "w" );
1819 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001820 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001821 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001822 }
1823 SaveFile(fp, compact);
1824 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001825 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001826}
1827
1828
Lee Thomason2fa81722012-11-09 12:37:46 -08001829XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001830{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001831 XMLPrinter stream( fp, compact );
1832 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001833 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001834}
1835
Lee Thomason1ff38e02012-02-14 18:18:16 -08001836
Lee Thomason2fa81722012-11-09 12:37:46 -08001837XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001838{
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001839 const char* start = p;
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001840 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001841
Lee Thomason82d32002014-02-21 22:47:18 -08001842 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001843 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001844 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001845 }
1846 if ( len == (size_t)(-1) ) {
1847 len = strlen( p );
1848 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001849 _charBuffer = new char[ len+1 ];
1850 memcpy( _charBuffer, p, len );
1851 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001852
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001853 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001854 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001855 if ( !p || !*p ) {
1856 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001857 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001858 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001859
Thomas Roß1470edc2013-05-10 15:44:12 +02001860 ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001861 ParseDeep( _charBuffer+delta, 0 );
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001862 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001863 // clean up now essentially dangling memory.
1864 // and the parse fail can put objects in the
1865 // pools that are dead and inaccessible.
1866 DeleteChildren();
1867 _elementPool.Clear();
1868 _attributePool.Clear();
1869 _textPool.Clear();
1870 _commentPool.Clear();
1871 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001872 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001873}
1874
1875
PKEuS1c5f99e2013-07-06 11:28:39 +02001876void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001877{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001878 XMLPrinter stdStreamer( stdout );
1879 if ( !streamer ) {
1880 streamer = &stdStreamer;
1881 }
1882 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001883}
1884
1885
Lee Thomason2fa81722012-11-09 12:37:46 -08001886void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001887{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001888 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07001889 _errorID = error;
1890 _errorStr1 = str1;
1891 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001892}
1893
Lee Thomason331596e2014-09-11 14:56:43 -07001894const char* XMLDocument::ErrorName() const
1895{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001896 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Lee Thomason331596e2014-09-11 14:56:43 -07001897 return _errorNames[_errorID];
1898}
Lee Thomason5cae8972012-01-24 18:03:07 -08001899
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001900void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001901{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001902 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001903 static const int LEN = 20;
1904 char buf1[LEN] = { 0 };
1905 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001906
Lee Thomason624d43f2012-10-12 10:58:48 -07001907 if ( _errorStr1 ) {
1908 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001909 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001910 if ( _errorStr2 ) {
1911 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001912 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001913
Lee Thomason331596e2014-09-11 14:56:43 -07001914 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
1915 _errorID, ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001916 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001917}
1918
1919
PKEuS1bfb9542013-08-04 13:51:17 +02001920XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001921 _elementJustOpened( false ),
1922 _firstElement( true ),
1923 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001924 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001925 _textDepth( -1 ),
1926 _processEntities( true ),
1927 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001928{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001929 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001930 _entityFlag[i] = false;
1931 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001932 }
1933 for( int i=0; i<NUM_ENTITIES; ++i ) {
1934 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1935 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001936 _entityFlag[ (int)entities[i].value ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001937 }
1938 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001939 _restrictedEntityFlag[(int)'&'] = true;
1940 _restrictedEntityFlag[(int)'<'] = true;
1941 _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
1942 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001943}
1944
1945
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001946void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001947{
1948 va_list va;
1949 va_start( va, format );
1950
Lee Thomason624d43f2012-10-12 10:58:48 -07001951 if ( _fp ) {
1952 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001953 }
1954 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001955#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001956 #if defined(WINCE)
1957 int len = 512;
1958 do {
1959 len = len*2;
1960 char* str = new char[len]();
1961 len = _vsnprintf(str, len, format, va);
1962 delete[] str;
1963 }while (len < 0);
1964 #else
Thomas Roß268c6832014-03-13 23:35:16 +01001965 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08001966 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001967#else
1968 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01001969#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001970 // Close out and re-start the va-args
1971 va_end( va );
1972 va_start( va, format );
Lee Thomasona0744c82014-03-16 10:32:27 -07001973 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
1974#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001975 #if defined(WINCE)
1976 _vsnprintf( p, len+1, format, va );
1977 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07001978 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08001979 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07001980#else
1981 vsnprintf( p, len+1, format, va );
1982#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001983 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001984 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001985}
1986
1987
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001988void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001989{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001990 for( int i=0; i<depth; ++i ) {
1991 Print( " " );
1992 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001993}
1994
1995
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001996void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001997{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001998 // Look for runs of bytes between entities to print.
1999 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07002000 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08002001
Lee Thomason624d43f2012-10-12 10:58:48 -07002002 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002003 while ( *q ) {
2004 // Remember, char is sometimes signed. (How many times has that bitten me?)
2005 if ( *q > 0 && *q < ENTITY_RANGE ) {
2006 // Check for entities. If one is found, flush
2007 // the stream up until the entity, write the
2008 // entity, and keep looking.
2009 if ( flag[(unsigned)(*q)] ) {
2010 while ( p < q ) {
2011 Print( "%c", *p );
2012 ++p;
2013 }
2014 for( int i=0; i<NUM_ENTITIES; ++i ) {
2015 if ( entities[i].value == *q ) {
2016 Print( "&%s;", entities[i].pattern );
2017 break;
2018 }
2019 }
2020 ++p;
2021 }
2022 }
2023 ++q;
2024 }
2025 }
2026 // Flush the remaining string. This will be the entire
2027 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07002028 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002029 Print( "%s", p );
2030 }
Lee Thomason857b8682012-01-25 17:50:25 -08002031}
2032
U-Stream\Leeae25a442012-02-17 17:48:16 -08002033
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002034void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002035{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002036 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002037 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 -07002038 Print( "%s", bom );
2039 }
2040 if ( writeDec ) {
2041 PushDeclaration( "xml version=\"1.0\"" );
2042 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002043}
2044
2045
Uli Kusterer593a33d2014-02-01 12:48:51 +01002046void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002047{
Lee Thomason624d43f2012-10-12 10:58:48 -07002048 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002049 SealElement();
2050 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002051 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002052
Uli Kusterer593a33d2014-02-01 12:48:51 +01002053 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002054 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002055 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002056 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002057 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002058 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002059
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002060 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002061 _elementJustOpened = true;
2062 _firstElement = false;
2063 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002064}
2065
2066
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002067void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002068{
Lee Thomason624d43f2012-10-12 10:58:48 -07002069 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002070 Print( " %s=\"", name );
2071 PrintString( value, false );
2072 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002073}
2074
2075
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002076void XMLPrinter::PushAttribute( const char* name, int v )
2077{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002078 char buf[BUF_SIZE];
2079 XMLUtil::ToStr( v, buf, BUF_SIZE );
2080 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002081}
2082
2083
2084void XMLPrinter::PushAttribute( const char* name, unsigned v )
2085{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002086 char buf[BUF_SIZE];
2087 XMLUtil::ToStr( v, buf, BUF_SIZE );
2088 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002089}
2090
2091
2092void XMLPrinter::PushAttribute( const char* name, bool v )
2093{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002094 char buf[BUF_SIZE];
2095 XMLUtil::ToStr( v, buf, BUF_SIZE );
2096 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002097}
2098
2099
2100void XMLPrinter::PushAttribute( const char* name, double v )
2101{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002102 char buf[BUF_SIZE];
2103 XMLUtil::ToStr( v, buf, BUF_SIZE );
2104 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002105}
2106
2107
Uli Kustererca412e82014-02-01 13:35:05 +01002108void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002109{
Lee Thomason624d43f2012-10-12 10:58:48 -07002110 --_depth;
2111 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002112
Lee Thomason624d43f2012-10-12 10:58:48 -07002113 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002114 Print( "/>" );
2115 }
2116 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002117 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002118 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002119 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002120 }
2121 Print( "</%s>", name );
2122 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002123
Lee Thomason624d43f2012-10-12 10:58:48 -07002124 if ( _textDepth == _depth ) {
2125 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002126 }
Uli Kustererca412e82014-02-01 13:35:05 +01002127 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002128 Print( "\n" );
2129 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002130 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002131}
2132
2133
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002134void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08002135{
Lee Thomason624d43f2012-10-12 10:58:48 -07002136 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002137 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002138}
2139
2140
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002141void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002142{
Lee Thomason624d43f2012-10-12 10:58:48 -07002143 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002144
Lee Thomason624d43f2012-10-12 10:58:48 -07002145 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002146 SealElement();
2147 }
2148 if ( cdata ) {
2149 Print( "<![CDATA[" );
2150 Print( "%s", text );
2151 Print( "]]>" );
2152 }
2153 else {
2154 PrintString( text, true );
2155 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002156}
2157
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002158void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002159{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002160 char buf[BUF_SIZE];
2161 XMLUtil::ToStr( value, buf, BUF_SIZE );
2162 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002163}
2164
2165
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002166void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002167{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002168 char buf[BUF_SIZE];
2169 XMLUtil::ToStr( value, buf, BUF_SIZE );
2170 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002171}
2172
2173
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002174void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002175{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002176 char buf[BUF_SIZE];
2177 XMLUtil::ToStr( value, buf, BUF_SIZE );
2178 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002179}
2180
2181
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002182void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002183{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002184 char buf[BUF_SIZE];
2185 XMLUtil::ToStr( value, buf, BUF_SIZE );
2186 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002187}
2188
2189
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002190void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002191{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002192 char buf[BUF_SIZE];
2193 XMLUtil::ToStr( value, buf, BUF_SIZE );
2194 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002195}
2196
Lee Thomason5cae8972012-01-24 18:03:07 -08002197
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002198void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002199{
Lee Thomason624d43f2012-10-12 10:58:48 -07002200 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002201 SealElement();
2202 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002203 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002204 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002205 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002206 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002207 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002208 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002209}
Lee Thomason751da522012-02-10 08:50:51 -08002210
2211
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002212void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002213{
Lee Thomason624d43f2012-10-12 10:58:48 -07002214 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002215 SealElement();
2216 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002217 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002218 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002219 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002220 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002221 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002222 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002223}
2224
2225
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002226void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002227{
Lee Thomason624d43f2012-10-12 10:58:48 -07002228 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002229 SealElement();
2230 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002231 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002232 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002233 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002234 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002235 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002236 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002237}
2238
2239
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002240bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002241{
Lee Thomason624d43f2012-10-12 10:58:48 -07002242 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002243 if ( doc.HasBOM() ) {
2244 PushHeader( true, false );
2245 }
2246 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002247}
2248
2249
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002250bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002251{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002252 const XMLElement* parentElem = element.Parent()->ToElement();
2253 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2254 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002255 while ( attribute ) {
2256 PushAttribute( attribute->Name(), attribute->Value() );
2257 attribute = attribute->Next();
2258 }
2259 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002260}
2261
2262
Uli Kustererca412e82014-02-01 13:35:05 +01002263bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002264{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002265 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002266 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002267}
2268
2269
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002270bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002271{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002272 PushText( text.Value(), text.CData() );
2273 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 XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002278{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002279 PushComment( comment.Value() );
2280 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002281}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002282
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002283bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002284{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002285 PushDeclaration( declaration.Value() );
2286 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002287}
2288
2289
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002290bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002291{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002292 PushUnknown( unknown.Value() );
2293 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002294}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002295
Lee Thomason685b8952012-11-12 13:00:06 -08002296} // namespace tinyxml2
2297