blob: 8259e693fd426e252314e273755514778bc5a364 [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
U-Lama\Lee560bd472011-12-28 19:42:49 -080024#include "tinyxml2.h"
25
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070026#include <new> // yes, this one new style header, is in the Android SDK.
Anton Indrawanf59e2d62014-11-18 20:50:42 +010027#if defined(ANDROID_NDK) || defined(__QNXNTO__)
Lee Thomasona9cf3f92012-10-11 16:56:51 -070028# include <stddef.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070029#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070030# include <cstddef>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070031#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080032
Lee Thomasone4422302012-01-20 17:59:50 -080033static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -080034static const char LF = LINE_FEED;
35static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
36static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -080037static const char SINGLE_QUOTE = '\'';
38static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -080039
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080040// Bunch of unicode info at:
41// http://www.unicode.org/faq/utf_bom.html
42// ef bb bf (Microsoft "lead bytes") - designates UTF-8
43
44static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
45static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
46static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080047
Kevin Wojniak04c22d22012-11-08 11:02:22 -080048namespace tinyxml2
49{
50
Lee Thomason8ee79892012-01-25 17:44:30 -080051struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -070052 const char* pattern;
53 int length;
54 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -080055};
56
57static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070058static const Entity entities[NUM_ENTITIES] = {
59 { "quot", 4, DOUBLE_QUOTE },
60 { "amp", 3, '&' },
61 { "apos", 4, SINGLE_QUOTE },
62 { "lt", 2, '<' },
63 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -080064};
65
Lee Thomasonfde6a752012-01-14 18:08:12 -080066
Lee Thomason1a1d4a72012-02-15 09:09:25 -080067StrPair::~StrPair()
68{
Lee Thomasona9cf3f92012-10-11 16:56:51 -070069 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -080070}
71
72
Lee Thomason29658802014-11-27 22:31:11 -080073void StrPair::TransferTo( StrPair* other )
Dmitry-Me08b40dd2014-11-10 11:17:21 +030074{
Lee Thomason29658802014-11-27 22:31:11 -080075 if ( this == other ) {
Dmitry-Me08b40dd2014-11-10 11:17:21 +030076 return;
77 }
78 // This in effect implements the assignment operator by "moving"
79 // ownership (as in auto_ptr).
80
Lee Thomason29658802014-11-27 22:31:11 -080081 TIXMLASSERT( other->_flags == 0 );
82 TIXMLASSERT( other->_start == 0 );
83 TIXMLASSERT( other->_end == 0 );
Dmitry-Me08b40dd2014-11-10 11:17:21 +030084
Lee Thomason29658802014-11-27 22:31:11 -080085 other->Reset();
Dmitry-Me08b40dd2014-11-10 11:17:21 +030086
Lee Thomason29658802014-11-27 22:31:11 -080087 other->_flags = _flags;
88 other->_start = _start;
89 other->_end = _end;
Dmitry-Me08b40dd2014-11-10 11:17:21 +030090
91 _flags = 0;
92 _start = 0;
93 _end = 0;
94}
95
Lee Thomason1a1d4a72012-02-15 09:09:25 -080096void StrPair::Reset()
97{
Lee Thomason120b3a62012-10-12 10:06:59 -070098 if ( _flags & NEEDS_DELETE ) {
99 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700100 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700101 _flags = 0;
102 _start = 0;
103 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800104}
105
106
107void StrPair::SetStr( const char* str, int flags )
108{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700109 Reset();
110 size_t len = strlen( str );
Lee Thomason120b3a62012-10-12 10:06:59 -0700111 _start = new char[ len+1 ];
112 memcpy( _start, str, len+1 );
113 _end = _start + len;
114 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800115}
116
117
118char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
119{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700120 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800121
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400122 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700123 char endChar = *endTag;
124 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800125
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700126 // Inner loop of text parsing.
127 while ( *p ) {
128 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
129 Set( start, p, strFlags );
130 return p + length;
131 }
132 ++p;
133 }
134 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800135}
136
137
138char* StrPair::ParseName( char* p )
139{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400140 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700141 return 0;
142 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800143
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400144 char* const start = p;
145
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +0200146 while( *p && ( p == start ? XMLUtil::IsNameStartChar( *p ) : XMLUtil::IsNameChar( *p ) )) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700147 ++p;
148 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800149
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700150 if ( p > start ) {
151 Set( start, p, 0 );
152 return p;
153 }
154 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800155}
156
157
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700158void StrPair::CollapseWhitespace()
159{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400160 // Adjusting _start would cause undefined behavior on delete[]
161 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700162 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700163 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700164
Lee Thomason120b3a62012-10-12 10:06:59 -0700165 if ( _start && *_start ) {
166 char* p = _start; // the read pointer
167 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700168
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700169 while( *p ) {
170 if ( XMLUtil::IsWhiteSpace( *p )) {
171 p = XMLUtil::SkipWhiteSpace( p );
172 if ( *p == 0 ) {
173 break; // don't write to q; this trims the trailing space.
174 }
175 *q = ' ';
176 ++q;
177 }
178 *q = *p;
179 ++q;
180 ++p;
181 }
182 *q = 0;
183 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700184}
185
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800186
Lee Thomasone4422302012-01-20 17:59:50 -0800187const char* StrPair::GetStr()
188{
Lee Thomason120b3a62012-10-12 10:06:59 -0700189 if ( _flags & NEEDS_FLUSH ) {
190 *_end = 0;
191 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800192
Lee Thomason120b3a62012-10-12 10:06:59 -0700193 if ( _flags ) {
194 char* p = _start; // the read pointer
195 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800196
Lee Thomason120b3a62012-10-12 10:06:59 -0700197 while( p < _end ) {
198 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700199 // CR-LF pair becomes LF
200 // CR alone becomes LF
201 // LF-CR becomes LF
202 if ( *(p+1) == LF ) {
203 p += 2;
204 }
205 else {
206 ++p;
207 }
208 *q++ = LF;
209 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700210 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700211 if ( *(p+1) == CR ) {
212 p += 2;
213 }
214 else {
215 ++p;
216 }
217 *q++ = LF;
218 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700219 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700220 // Entities handled by tinyXML2:
221 // - special entities in the entity table [in/out]
222 // - numeric character reference [in]
223 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800224
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700225 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400226 const int buflen = 10;
227 char buf[buflen] = { 0 };
228 int len = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700229 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
Dmitry-Me63f3de12014-08-21 12:33:19 +0400230 TIXMLASSERT( 0 <= len && len <= buflen );
231 TIXMLASSERT( q + len <= p );
232 memcpy( q, buf, len );
233 q += len;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700234 }
235 else {
236 int i=0;
237 for(; i<NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400238 const Entity& entity = entities[i];
239 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
240 && *( p + entity.length + 1 ) == ';' ) {
241 // Found an entity - convert.
242 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700243 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400244 p += entity.length + 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700245 break;
246 }
247 }
248 if ( i == NUM_ENTITIES ) {
249 // fixme: treat as error?
250 ++p;
251 ++q;
252 }
253 }
254 }
255 else {
256 *q = *p;
257 ++p;
258 ++q;
259 }
260 }
261 *q = 0;
262 }
263 // The loop below has plenty going on, and this
264 // is a less useful mode. Break it out.
Lee Thomason120b3a62012-10-12 10:06:59 -0700265 if ( _flags & COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700266 CollapseWhitespace();
267 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700268 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700269 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700270 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800271}
272
Lee Thomason2c85a712012-01-31 08:24:24 -0800273
Lee Thomasone4422302012-01-20 17:59:50 -0800274
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800275
Lee Thomason56bdd022012-02-09 18:16:58 -0800276// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800277
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800278const char* XMLUtil::ReadBOM( const char* p, bool* bom )
279{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700280 *bom = false;
281 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
282 // Check for BOM:
283 if ( *(pu+0) == TIXML_UTF_LEAD_0
284 && *(pu+1) == TIXML_UTF_LEAD_1
285 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
286 *bom = true;
287 p += 3;
288 }
289 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800290}
291
292
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800293void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
294{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700295 const unsigned long BYTE_MASK = 0xBF;
296 const unsigned long BYTE_MARK = 0x80;
297 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800298
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700299 if (input < 0x80) {
300 *length = 1;
301 }
302 else if ( input < 0x800 ) {
303 *length = 2;
304 }
305 else if ( input < 0x10000 ) {
306 *length = 3;
307 }
308 else if ( input < 0x200000 ) {
309 *length = 4;
310 }
311 else {
312 *length = 0; // This code won't covert this correctly anyway.
313 return;
314 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800315
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700316 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800317
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700318 // Scary scary fall throughs.
319 switch (*length) {
320 case 4:
321 --output;
322 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
323 input >>= 6;
324 case 3:
325 --output;
326 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
327 input >>= 6;
328 case 2:
329 --output;
330 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
331 input >>= 6;
332 case 1:
333 --output;
334 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100335 default:
336 break;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700337 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800338}
339
340
341const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
342{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700343 // Presume an entity, and pull it out.
344 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800345
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700346 if ( *(p+1) == '#' && *(p+2) ) {
347 unsigned long ucs = 0;
348 ptrdiff_t delta = 0;
349 unsigned mult = 1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800350
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700351 if ( *(p+2) == 'x' ) {
352 // Hexadecimal.
353 if ( !*(p+3) ) {
354 return 0;
355 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800356
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700357 const char* q = p+3;
358 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800359
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700360 if ( !q || !*q ) {
361 return 0;
362 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800363
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700364 delta = q-p;
365 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800366
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700367 while ( *q != 'x' ) {
368 if ( *q >= '0' && *q <= '9' ) {
369 ucs += mult * (*q - '0');
370 }
371 else if ( *q >= 'a' && *q <= 'f' ) {
372 ucs += mult * (*q - 'a' + 10);
373 }
374 else if ( *q >= 'A' && *q <= 'F' ) {
375 ucs += mult * (*q - 'A' + 10 );
376 }
377 else {
378 return 0;
379 }
380 mult *= 16;
381 --q;
382 }
383 }
384 else {
385 // Decimal.
386 if ( !*(p+2) ) {
387 return 0;
388 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800389
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700390 const char* q = p+2;
391 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800392
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700393 if ( !q || !*q ) {
394 return 0;
395 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800396
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700397 delta = q-p;
398 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800399
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700400 while ( *q != '#' ) {
401 if ( *q >= '0' && *q <= '9' ) {
402 ucs += mult * (*q - '0');
403 }
404 else {
405 return 0;
406 }
407 mult *= 10;
408 --q;
409 }
410 }
411 // convert the UCS to UTF-8
412 ConvertUTF32ToUTF8( ucs, value, length );
413 return p + delta + 1;
414 }
415 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800416}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800417
418
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700419void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700420{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700421 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700422}
423
424
425void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
426{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700427 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700428}
429
430
431void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
432{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700433 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700434}
435
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800436/*
437 ToStr() of a number is a very tricky topic.
438 https://github.com/leethomason/tinyxml2/issues/106
439*/
Lee Thomason21be8822012-07-15 17:27:22 -0700440void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
441{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800442 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700443}
444
445
446void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
447{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800448 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700449}
450
451
452bool XMLUtil::ToInt( const char* str, int* value )
453{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700454 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
455 return true;
456 }
457 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700458}
459
460bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
461{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700462 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
463 return true;
464 }
465 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700466}
467
468bool XMLUtil::ToBool( const char* str, bool* value )
469{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700470 int ival = 0;
471 if ( ToInt( str, &ival )) {
472 *value = (ival==0) ? false : true;
473 return true;
474 }
475 if ( StringEqual( str, "true" ) ) {
476 *value = true;
477 return true;
478 }
479 else if ( StringEqual( str, "false" ) ) {
480 *value = false;
481 return true;
482 }
483 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700484}
485
486
487bool XMLUtil::ToFloat( const char* str, float* value )
488{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700489 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
490 return true;
491 }
492 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700493}
494
495bool XMLUtil::ToDouble( const char* str, double* value )
496{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700497 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
498 return true;
499 }
500 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700501}
502
503
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700504char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800505{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400506 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700507 p = XMLUtil::SkipWhiteSpace( p );
508 if( !p || !*p ) {
509 return p;
510 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800511
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700512 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800513 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700514 static const char* xmlHeader = { "<?" };
515 static const char* commentHeader = { "<!--" };
516 static const char* dtdHeader = { "<!" };
517 static const char* cdataHeader = { "<![CDATA[" };
518 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800519
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700520 static const int xmlHeaderLen = 2;
521 static const int commentHeaderLen = 4;
522 static const int dtdHeaderLen = 2;
523 static const int cdataHeaderLen = 9;
524 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800525
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800526#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800527#pragma warning ( push )
528#pragma warning ( disable : 4127 )
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800529#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700530 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
531 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800532#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800533#pragma warning (pop)
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800534#endif
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400535 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700536 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300537 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700538 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
539 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700540 p += xmlHeaderLen;
541 }
542 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300543 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700544 returnNode = new (_commentPool.Alloc()) XMLComment( this );
545 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700546 p += commentHeaderLen;
547 }
548 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300549 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700550 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700551 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700552 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700553 p += cdataHeaderLen;
554 text->SetCData( true );
555 }
556 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300557 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700558 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
559 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700560 p += dtdHeaderLen;
561 }
562 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300563 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700564 returnNode = new (_elementPool.Alloc()) XMLElement( this );
565 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700566 p += elementHeaderLen;
567 }
568 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300569 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700570 returnNode = new (_textPool.Alloc()) XMLText( this );
571 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700572 p = start; // Back it up, all the text counts.
573 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800574
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700575 *node = returnNode;
576 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800577}
578
579
Lee Thomason751da522012-02-10 08:50:51 -0800580bool XMLDocument::Accept( XMLVisitor* visitor ) const
581{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700582 if ( visitor->VisitEnter( *this ) ) {
583 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
584 if ( !node->Accept( visitor ) ) {
585 break;
586 }
587 }
588 }
589 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800590}
Lee Thomason56bdd022012-02-09 18:16:58 -0800591
592
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800593// --------- XMLNode ----------- //
594
595XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700596 _document( doc ),
597 _parent( 0 ),
598 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200599 _prev( 0 ), _next( 0 ),
600 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800601{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800602}
603
604
605XMLNode::~XMLNode()
606{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700607 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700608 if ( _parent ) {
609 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700610 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800611}
612
Michael Daumling21626882013-10-22 17:03:37 +0200613const char* XMLNode::Value() const
614{
615 return _value.GetStr();
616}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800617
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800618void XMLNode::SetValue( const char* str, bool staticMem )
619{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700620 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700621 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700622 }
623 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700624 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700625 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800626}
627
628
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800629void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800630{
Lee Thomason624d43f2012-10-12 10:58:48 -0700631 while( _firstChild ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300632 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700633 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700634 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700635
Dmitry-Mee3225b12014-09-03 11:03:11 +0400636 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700637 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700638 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800639}
640
641
642void XMLNode::Unlink( XMLNode* child )
643{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300644 TIXMLASSERT( child->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700645 if ( child == _firstChild ) {
646 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700647 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700648 if ( child == _lastChild ) {
649 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700650 }
Lee Thomasond923c672012-01-23 08:44:25 -0800651
Lee Thomason624d43f2012-10-12 10:58:48 -0700652 if ( child->_prev ) {
653 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700654 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700655 if ( child->_next ) {
656 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700657 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700658 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800659}
660
661
U-Stream\Leeae25a442012-02-17 17:48:16 -0800662void XMLNode::DeleteChild( XMLNode* node )
663{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300664 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700665 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400666 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800667}
668
669
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800670XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
671{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300672 if ( addThis->_document != _document ) {
673 TIXMLASSERT( false );
674 return 0;
675 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700676
Michael Daumlinged523282013-10-23 07:47:29 +0200677 if (addThis->_parent)
678 addThis->_parent->Unlink( addThis );
679 else
680 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700681
Lee Thomason624d43f2012-10-12 10:58:48 -0700682 if ( _lastChild ) {
683 TIXMLASSERT( _firstChild );
684 TIXMLASSERT( _lastChild->_next == 0 );
685 _lastChild->_next = addThis;
686 addThis->_prev = _lastChild;
687 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800688
Lee Thomason624d43f2012-10-12 10:58:48 -0700689 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700690 }
691 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700692 TIXMLASSERT( _firstChild == 0 );
693 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800694
Lee Thomason624d43f2012-10-12 10:58:48 -0700695 addThis->_prev = 0;
696 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700697 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700698 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700699 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800700}
701
702
Lee Thomason1ff38e02012-02-14 18:18:16 -0800703XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
704{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300705 if ( addThis->_document != _document ) {
706 TIXMLASSERT( false );
707 return 0;
708 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700709
Michael Daumlinged523282013-10-23 07:47:29 +0200710 if (addThis->_parent)
711 addThis->_parent->Unlink( addThis );
712 else
713 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700714
Lee Thomason624d43f2012-10-12 10:58:48 -0700715 if ( _firstChild ) {
716 TIXMLASSERT( _lastChild );
717 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800718
Lee Thomason624d43f2012-10-12 10:58:48 -0700719 _firstChild->_prev = addThis;
720 addThis->_next = _firstChild;
721 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800722
Lee Thomason624d43f2012-10-12 10:58:48 -0700723 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700724 }
725 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700726 TIXMLASSERT( _lastChild == 0 );
727 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800728
Lee Thomason624d43f2012-10-12 10:58:48 -0700729 addThis->_prev = 0;
730 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700731 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700732 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400733 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800734}
735
736
737XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
738{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300739 TIXMLASSERT( addThis );
740 if ( addThis->_document != _document ) {
741 TIXMLASSERT( false );
742 return 0;
743 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700744
Dmitry-Meabb2d042014-12-09 12:59:31 +0300745 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700746
Lee Thomason624d43f2012-10-12 10:58:48 -0700747 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300748 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700749 return 0;
750 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800751
Lee Thomason624d43f2012-10-12 10:58:48 -0700752 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700753 // The last node or the only node.
754 return InsertEndChild( addThis );
755 }
Michael Daumlinged523282013-10-23 07:47:29 +0200756 if (addThis->_parent)
757 addThis->_parent->Unlink( addThis );
758 else
759 addThis->_memPool->SetTracked();
Lee Thomason624d43f2012-10-12 10:58:48 -0700760 addThis->_prev = afterThis;
761 addThis->_next = afterThis->_next;
762 afterThis->_next->_prev = addThis;
763 afterThis->_next = addThis;
764 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700765 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800766}
767
768
769
770
Lee Thomason56bdd022012-02-09 18:16:58 -0800771const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800772{
Lee Thomason624d43f2012-10-12 10:58:48 -0700773 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700774 XMLElement* element = node->ToElement();
775 if ( element ) {
776 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
777 return element;
778 }
779 }
780 }
781 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800782}
783
784
Lee Thomason56bdd022012-02-09 18:16:58 -0800785const XMLElement* XMLNode::LastChildElement( const char* value ) const
786{
Lee Thomason624d43f2012-10-12 10:58:48 -0700787 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700788 XMLElement* element = node->ToElement();
789 if ( element ) {
790 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
791 return element;
792 }
793 }
794 }
795 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800796}
797
798
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800799const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
800{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400801 for( XMLNode* node=this->_next; node; node = node->_next ) {
802 const XMLElement* element = node->ToElement();
803 if ( element
804 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
805 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700806 }
807 }
808 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800809}
810
811
812const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
813{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400814 for( XMLNode* node=_prev; node; node = node->_prev ) {
815 const XMLElement* element = node->ToElement();
816 if ( element
817 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
818 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700819 }
820 }
821 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800822}
823
824
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800825char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800826{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700827 // This is a recursive method, but thinking about it "at the current level"
828 // it is a pretty simple flat list:
829 // <foo/>
830 // <!-- comment -->
831 //
832 // With a special case:
833 // <foo>
834 // </foo>
835 // <!-- comment -->
836 //
837 // Where the closing element (/foo) *must* be the next thing after the opening
838 // element, and the names must match. BUT the tricky bit is that the closing
839 // element will be read by the child.
840 //
841 // 'endTag' is the end tag for this node, it is returned by a call to a child.
842 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800843
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700844 while( p && *p ) {
845 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800846
Lee Thomason624d43f2012-10-12 10:58:48 -0700847 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700848 if ( p == 0 || node == 0 ) {
849 break;
850 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800851
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700852 StrPair endTag;
853 p = node->ParseDeep( p, &endTag );
854 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400855 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700856 node = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -0700857 if ( !_document->Error() ) {
858 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700859 }
860 break;
861 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800862
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400863 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700864 // We read the end tag. Return it to the parent.
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400865 if ( ele && ele->ClosingType() == XMLElement::CLOSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700866 if ( parentEnd ) {
Lee Thomason29658802014-11-27 22:31:11 -0800867 ele->_value.TransferTo( parentEnd );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700868 }
Lee Thomason5b0a6772012-11-19 13:54:42 -0800869 node->_memPool->SetTracked(); // created and then immediately deleted.
Dmitry-Mee3225b12014-09-03 11:03:11 +0400870 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700871 return p;
872 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800873
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700874 // Handle an end tag returned to this level.
875 // And handle a bunch of annoying errors.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700876 if ( ele ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400877 bool mismatch = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700878 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400879 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700880 }
881 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400882 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700883 }
884 else if ( !endTag.Empty() ) {
885 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400886 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700887 }
888 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400889 if ( mismatch ) {
890 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
891 p = 0;
892 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700893 }
894 if ( p == 0 ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400895 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700896 node = 0;
897 }
898 if ( node ) {
899 this->InsertEndChild( node );
900 }
901 }
902 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800903}
904
Dmitry-Mee3225b12014-09-03 11:03:11 +0400905void XMLNode::DeleteNode( XMLNode* node )
906{
907 if ( node == 0 ) {
908 return;
909 }
910 MemPool* pool = node->_memPool;
911 node->~XMLNode();
912 pool->Free( node );
913}
914
Lee Thomason5492a1c2012-01-23 15:32:10 -0800915// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800916char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800917{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700918 const char* start = p;
919 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700920 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700921 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700922 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700923 }
924 return p;
925 }
926 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700927 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
928 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700929 flags |= StrPair::COLLAPSE_WHITESPACE;
930 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700931
Lee Thomason624d43f2012-10-12 10:58:48 -0700932 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700933 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700934 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700935 }
936 if ( p && *p ) {
937 return p-1;
938 }
939 }
940 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800941}
942
943
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800944XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
945{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700946 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700947 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700948 }
949 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
950 text->SetCData( this->CData() );
951 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800952}
953
954
955bool XMLText::ShallowEqual( const XMLNode* compare ) const
956{
Dmitry-Me6d202ff2014-09-26 14:21:00 +0400957 const XMLText* text = compare->ToText();
958 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800959}
960
961
Lee Thomason56bdd022012-02-09 18:16:58 -0800962bool XMLText::Accept( XMLVisitor* visitor ) const
963{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300964 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700965 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800966}
967
968
Lee Thomason3f57d272012-01-11 15:30:03 -0800969// --------- XMLComment ---------- //
970
Lee Thomasone4422302012-01-20 17:59:50 -0800971XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800972{
973}
974
975
Lee Thomasonce0763e2012-01-11 15:43:54 -0800976XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800977{
Lee Thomason3f57d272012-01-11 15:30:03 -0800978}
979
980
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800981char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800982{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700983 // Comment parses as text.
984 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700985 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700986 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700987 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700988 }
989 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800990}
991
992
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800993XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
994{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700995 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700996 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700997 }
998 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
999 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001000}
1001
1002
1003bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1004{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001005 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001006 const XMLComment* comment = compare->ToComment();
1007 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001008}
1009
1010
Lee Thomason751da522012-02-10 08:50:51 -08001011bool XMLComment::Accept( XMLVisitor* visitor ) const
1012{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001013 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001014 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001015}
Lee Thomason56bdd022012-02-09 18:16:58 -08001016
1017
Lee Thomason50f97b22012-02-11 16:33:40 -08001018// --------- XMLDeclaration ---------- //
1019
1020XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1021{
1022}
1023
1024
1025XMLDeclaration::~XMLDeclaration()
1026{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001027 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001028}
1029
1030
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001031char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001032{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001033 // Declaration parses as text.
1034 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001035 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001036 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001037 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001038 }
1039 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001040}
1041
1042
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001043XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1044{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001045 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001046 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001047 }
1048 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1049 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001050}
1051
1052
1053bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1054{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001055 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001056 const XMLDeclaration* declaration = compare->ToDeclaration();
1057 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001058}
1059
1060
1061
Lee Thomason50f97b22012-02-11 16:33:40 -08001062bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1063{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001064 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001065 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001066}
1067
1068// --------- XMLUnknown ---------- //
1069
1070XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1071{
1072}
1073
1074
1075XMLUnknown::~XMLUnknown()
1076{
1077}
1078
1079
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001080char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001081{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001082 // Unknown parses as text.
1083 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001084
Lee Thomason624d43f2012-10-12 10:58:48 -07001085 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001086 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001087 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001088 }
1089 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001090}
1091
1092
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001093XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1094{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001095 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001096 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001097 }
1098 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1099 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001100}
1101
1102
1103bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1104{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001105 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001106 const XMLUnknown* unknown = compare->ToUnknown();
1107 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001108}
1109
1110
Lee Thomason50f97b22012-02-11 16:33:40 -08001111bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1112{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001113 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001114 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001115}
1116
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001117// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001118
1119const char* XMLAttribute::Name() const
1120{
1121 return _name.GetStr();
1122}
1123
1124const char* XMLAttribute::Value() const
1125{
1126 return _value.GetStr();
1127}
1128
Lee Thomason6f381b72012-03-02 12:59:39 -08001129char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001130{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001131 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001132 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001133 if ( !p || !*p ) {
1134 return 0;
1135 }
Lee Thomason22aead12012-01-23 13:29:35 -08001136
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001137 // Skip white space before =
1138 p = XMLUtil::SkipWhiteSpace( p );
1139 if ( !p || *p != '=' ) {
1140 return 0;
1141 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001142
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001143 ++p; // move up to opening quote
1144 p = XMLUtil::SkipWhiteSpace( p );
1145 if ( *p != '\"' && *p != '\'' ) {
1146 return 0;
1147 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001148
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001149 char endTag[2] = { *p, 0 };
1150 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001151
Lee Thomason624d43f2012-10-12 10:58:48 -07001152 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001153 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001154}
1155
1156
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001157void XMLAttribute::SetName( const char* n )
1158{
Lee Thomason624d43f2012-10-12 10:58:48 -07001159 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001160}
1161
1162
Lee Thomason2fa81722012-11-09 12:37:46 -08001163XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001164{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001165 if ( XMLUtil::ToInt( Value(), value )) {
1166 return XML_NO_ERROR;
1167 }
1168 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001169}
1170
1171
Lee Thomason2fa81722012-11-09 12:37:46 -08001172XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001173{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001174 if ( XMLUtil::ToUnsigned( Value(), value )) {
1175 return XML_NO_ERROR;
1176 }
1177 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001178}
1179
1180
Lee Thomason2fa81722012-11-09 12:37:46 -08001181XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001182{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001183 if ( XMLUtil::ToBool( Value(), value )) {
1184 return XML_NO_ERROR;
1185 }
1186 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001187}
1188
1189
Lee Thomason2fa81722012-11-09 12:37:46 -08001190XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001191{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001192 if ( XMLUtil::ToFloat( Value(), value )) {
1193 return XML_NO_ERROR;
1194 }
1195 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001196}
1197
1198
Lee Thomason2fa81722012-11-09 12:37:46 -08001199XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001200{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001201 if ( XMLUtil::ToDouble( Value(), value )) {
1202 return XML_NO_ERROR;
1203 }
1204 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001205}
1206
1207
1208void XMLAttribute::SetAttribute( const char* v )
1209{
Lee Thomason624d43f2012-10-12 10:58:48 -07001210 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001211}
1212
1213
Lee Thomason1ff38e02012-02-14 18:18:16 -08001214void XMLAttribute::SetAttribute( int v )
1215{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001216 char buf[BUF_SIZE];
1217 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001218 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001219}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001220
1221
1222void XMLAttribute::SetAttribute( unsigned v )
1223{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001224 char buf[BUF_SIZE];
1225 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001226 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001227}
1228
1229
1230void XMLAttribute::SetAttribute( bool v )
1231{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001232 char buf[BUF_SIZE];
1233 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001234 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001235}
1236
1237void XMLAttribute::SetAttribute( double v )
1238{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001239 char buf[BUF_SIZE];
1240 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001241 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001242}
1243
1244void XMLAttribute::SetAttribute( float v )
1245{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001246 char buf[BUF_SIZE];
1247 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001248 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001249}
1250
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001251
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001252// --------- XMLElement ---------- //
1253XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001254 _closingType( 0 ),
1255 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001256{
1257}
1258
1259
1260XMLElement::~XMLElement()
1261{
Lee Thomason624d43f2012-10-12 10:58:48 -07001262 while( _rootAttribute ) {
1263 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001264 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001265 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001266 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001267}
1268
1269
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001270const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1271{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001272 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001273 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1274 return a;
1275 }
1276 }
1277 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001278}
1279
1280
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001281const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001282{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001283 const XMLAttribute* a = FindAttribute( name );
1284 if ( !a ) {
1285 return 0;
1286 }
1287 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1288 return a->Value();
1289 }
1290 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001291}
1292
1293
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001294const char* XMLElement::GetText() const
1295{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001296 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001297 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001298 }
1299 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001300}
1301
1302
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001303void XMLElement::SetText( const char* inText )
1304{
Uli Kusterer869bb592014-01-21 01:36:16 +01001305 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001306 FirstChild()->SetValue( inText );
1307 else {
1308 XMLText* theText = GetDocument()->NewText( inText );
1309 InsertFirstChild( theText );
1310 }
1311}
1312
Lee Thomason5bb2d802014-01-24 10:42:57 -08001313
1314void XMLElement::SetText( int v )
1315{
1316 char buf[BUF_SIZE];
1317 XMLUtil::ToStr( v, buf, BUF_SIZE );
1318 SetText( buf );
1319}
1320
1321
1322void XMLElement::SetText( unsigned v )
1323{
1324 char buf[BUF_SIZE];
1325 XMLUtil::ToStr( v, buf, BUF_SIZE );
1326 SetText( buf );
1327}
1328
1329
1330void XMLElement::SetText( bool v )
1331{
1332 char buf[BUF_SIZE];
1333 XMLUtil::ToStr( v, buf, BUF_SIZE );
1334 SetText( buf );
1335}
1336
1337
1338void XMLElement::SetText( float v )
1339{
1340 char buf[BUF_SIZE];
1341 XMLUtil::ToStr( v, buf, BUF_SIZE );
1342 SetText( buf );
1343}
1344
1345
1346void XMLElement::SetText( double v )
1347{
1348 char buf[BUF_SIZE];
1349 XMLUtil::ToStr( v, buf, BUF_SIZE );
1350 SetText( buf );
1351}
1352
1353
MortenMacFly4ee49f12013-01-14 20:03:14 +01001354XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001355{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001356 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001357 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001358 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001359 return XML_SUCCESS;
1360 }
1361 return XML_CAN_NOT_CONVERT_TEXT;
1362 }
1363 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001364}
1365
1366
MortenMacFly4ee49f12013-01-14 20:03:14 +01001367XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001368{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001369 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001370 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001371 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001372 return XML_SUCCESS;
1373 }
1374 return XML_CAN_NOT_CONVERT_TEXT;
1375 }
1376 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001377}
1378
1379
MortenMacFly4ee49f12013-01-14 20:03:14 +01001380XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001381{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001382 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001383 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001384 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001385 return XML_SUCCESS;
1386 }
1387 return XML_CAN_NOT_CONVERT_TEXT;
1388 }
1389 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001390}
1391
1392
MortenMacFly4ee49f12013-01-14 20:03:14 +01001393XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001394{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001395 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001396 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001397 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001398 return XML_SUCCESS;
1399 }
1400 return XML_CAN_NOT_CONVERT_TEXT;
1401 }
1402 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001403}
1404
1405
MortenMacFly4ee49f12013-01-14 20:03:14 +01001406XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001407{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001408 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001409 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001410 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001411 return XML_SUCCESS;
1412 }
1413 return XML_CAN_NOT_CONVERT_TEXT;
1414 }
1415 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001416}
1417
1418
1419
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001420XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1421{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001422 XMLAttribute* last = 0;
1423 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001424 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001425 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001426 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001427 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1428 break;
1429 }
1430 }
1431 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001432 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001433 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1434 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001435 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001436 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001437 }
1438 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001439 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001440 }
1441 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001442 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001443 }
1444 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001445}
1446
1447
U-Stream\Leeae25a442012-02-17 17:48:16 -08001448void XMLElement::DeleteAttribute( const char* name )
1449{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001450 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001451 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001452 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1453 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001454 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001455 }
1456 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001457 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001458 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001459 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001460 break;
1461 }
1462 prev = a;
1463 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001464}
1465
1466
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001467char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001468{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001469 const char* start = p;
1470 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001471
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001472 // Read the attributes.
1473 while( p ) {
1474 p = XMLUtil::SkipWhiteSpace( p );
1475 if ( !p || !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001476 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001477 return 0;
1478 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001479
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001480 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001481 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001482 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001483 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1484 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001485 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001486
Lee Thomason624d43f2012-10-12 10:58:48 -07001487 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001488 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001489 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001490 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001491 return 0;
1492 }
1493 // There is a minor bug here: if the attribute in the source xml
1494 // document is duplicated, it will not be detected and the
1495 // attribute will be doubly added. However, tracking the 'prevAttribute'
1496 // avoids re-scanning the attribute list. Preferring performance for
1497 // now, may reconsider in the future.
1498 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001499 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001500 }
1501 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001502 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001503 }
1504 prevAttribute = attrib;
1505 }
1506 // end of the tag
1507 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001508 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001509 return p+2; // done; sealed element.
1510 }
1511 // end of the tag
1512 else if ( *p == '>' ) {
1513 ++p;
1514 break;
1515 }
1516 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001517 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001518 return 0;
1519 }
1520 }
1521 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001522}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001523
Dmitry-Mee3225b12014-09-03 11:03:11 +04001524void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1525{
1526 if ( attribute == 0 ) {
1527 return;
1528 }
1529 MemPool* pool = attribute->_memPool;
1530 attribute->~XMLAttribute();
1531 pool->Free( attribute );
1532}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001533
Lee Thomason67d61312012-01-24 16:01:51 -08001534//
1535// <ele></ele>
1536// <ele>foo<b>bar</b></ele>
1537//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001538char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001539{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001540 // Read the element name.
1541 p = XMLUtil::SkipWhiteSpace( p );
1542 if ( !p ) {
1543 return 0;
1544 }
Lee Thomason67d61312012-01-24 16:01:51 -08001545
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001546 // The closing element is the </element> form. It is
1547 // parsed just like a regular element then deleted from
1548 // the DOM.
1549 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001550 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001551 ++p;
1552 }
Lee Thomason67d61312012-01-24 16:01:51 -08001553
Lee Thomason624d43f2012-10-12 10:58:48 -07001554 p = _value.ParseName( p );
1555 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001556 return 0;
1557 }
Lee Thomason67d61312012-01-24 16:01:51 -08001558
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001559 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001560 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001561 return p;
1562 }
Lee Thomason67d61312012-01-24 16:01:51 -08001563
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001564 p = XMLNode::ParseDeep( p, strPair );
1565 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001566}
1567
1568
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001569
1570XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1571{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001572 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001573 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001574 }
1575 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1576 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1577 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1578 }
1579 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001580}
1581
1582
1583bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1584{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001585 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001586 const XMLElement* other = compare->ToElement();
1587 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001588
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001589 const XMLAttribute* a=FirstAttribute();
1590 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001591
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001592 while ( a && b ) {
1593 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1594 return false;
1595 }
1596 a = a->Next();
1597 b = b->Next();
1598 }
1599 if ( a || b ) {
1600 // different count
1601 return false;
1602 }
1603 return true;
1604 }
1605 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001606}
1607
1608
Lee Thomason751da522012-02-10 08:50:51 -08001609bool XMLElement::Accept( XMLVisitor* visitor ) const
1610{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001611 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001612 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001613 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1614 if ( !node->Accept( visitor ) ) {
1615 break;
1616 }
1617 }
1618 }
1619 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001620}
Lee Thomason56bdd022012-02-09 18:16:58 -08001621
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001622
Lee Thomason3f57d272012-01-11 15:30:03 -08001623// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001624
1625// Warning: List must match 'enum XMLError'
1626const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1627 "XML_SUCCESS",
1628 "XML_NO_ATTRIBUTE",
1629 "XML_WRONG_ATTRIBUTE_TYPE",
1630 "XML_ERROR_FILE_NOT_FOUND",
1631 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1632 "XML_ERROR_FILE_READ_ERROR",
1633 "XML_ERROR_ELEMENT_MISMATCH",
1634 "XML_ERROR_PARSING_ELEMENT",
1635 "XML_ERROR_PARSING_ATTRIBUTE",
1636 "XML_ERROR_IDENTIFYING_TAG",
1637 "XML_ERROR_PARSING_TEXT",
1638 "XML_ERROR_PARSING_CDATA",
1639 "XML_ERROR_PARSING_COMMENT",
1640 "XML_ERROR_PARSING_DECLARATION",
1641 "XML_ERROR_PARSING_UNKNOWN",
1642 "XML_ERROR_EMPTY_DOCUMENT",
1643 "XML_ERROR_MISMATCHED_ELEMENT",
1644 "XML_ERROR_PARSING",
1645 "XML_CAN_NOT_CONVERT_TEXT",
1646 "XML_NO_TEXT_NODE"
1647};
1648
1649
Lee Thomason624d43f2012-10-12 10:58:48 -07001650XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001651 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001652 _writeBOM( false ),
1653 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001654 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001655 _whitespace( whitespace ),
1656 _errorStr1( 0 ),
1657 _errorStr2( 0 ),
1658 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001659{
Lee Thomason624d43f2012-10-12 10:58:48 -07001660 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001661}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001662
1663
Lee Thomason3f57d272012-01-11 15:30:03 -08001664XMLDocument::~XMLDocument()
1665{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001666 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001667}
1668
1669
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001670void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001671{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001672 DeleteChildren();
1673
Dmitry-Meab37df82014-11-28 12:08:36 +03001674#ifdef DEBUG
1675 const bool hadError = Error();
1676#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001677 _errorID = XML_NO_ERROR;
1678 _errorStr1 = 0;
1679 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001680
Lee Thomason624d43f2012-10-12 10:58:48 -07001681 delete [] _charBuffer;
1682 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001683
1684#if 0
1685 _textPool.Trace( "text" );
1686 _elementPool.Trace( "element" );
1687 _commentPool.Trace( "comment" );
1688 _attributePool.Trace( "attribute" );
1689#endif
1690
1691#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001692 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001693 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1694 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1695 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1696 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1697 }
1698#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001699}
1700
Lee Thomason3f57d272012-01-11 15:30:03 -08001701
Lee Thomason2c85a712012-01-31 08:24:24 -08001702XMLElement* XMLDocument::NewElement( const char* name )
1703{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001704 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001705 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1706 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001707 ele->SetName( name );
1708 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001709}
1710
1711
Lee Thomason1ff38e02012-02-14 18:18:16 -08001712XMLComment* XMLDocument::NewComment( const char* str )
1713{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001714 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001715 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1716 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001717 comment->SetValue( str );
1718 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001719}
1720
1721
1722XMLText* XMLDocument::NewText( const char* str )
1723{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001724 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001725 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1726 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001727 text->SetValue( str );
1728 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001729}
1730
1731
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001732XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1733{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001734 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001735 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1736 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001737 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1738 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001739}
1740
1741
1742XMLUnknown* XMLDocument::NewUnknown( const char* str )
1743{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001744 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001745 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1746 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001747 unk->SetValue( str );
1748 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001749}
1750
Dmitry-Me01578db2014-08-19 10:18:48 +04001751static FILE* callfopen( const char* filepath, const char* mode )
1752{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001753 TIXMLASSERT( filepath );
1754 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001755#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1756 FILE* fp = 0;
1757 errno_t err = fopen_s( &fp, filepath, mode );
1758 if ( err ) {
1759 return 0;
1760 }
1761#else
1762 FILE* fp = fopen( filepath, mode );
1763#endif
1764 return fp;
1765}
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001766
Lee Thomason2fa81722012-11-09 12:37:46 -08001767XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001768{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001769 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001770 FILE* fp = callfopen( filename, "rb" );
1771 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001772 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001773 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001774 }
1775 LoadFile( fp );
1776 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001777 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001778}
1779
1780
Lee Thomason2fa81722012-11-09 12:37:46 -08001781XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001782{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001783 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001784
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001785 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001786 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001787 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1788 return _errorID;
1789 }
1790
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001791 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001792 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001793 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001794 if ( filelength == -1L ) {
1795 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1796 return _errorID;
1797 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001798
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001799 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001800 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001801 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001802 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001803 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001804
Lee Thomason624d43f2012-10-12 10:58:48 -07001805 _charBuffer = new char[size+1];
1806 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001807 if ( read != size ) {
1808 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001809 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001810 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001811
Lee Thomason624d43f2012-10-12 10:58:48 -07001812 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001813
Lee Thomason624d43f2012-10-12 10:58:48 -07001814 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001815 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001816 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001817 if ( !p || !*p ) {
1818 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001819 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001820 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001821
Lee Thomason624d43f2012-10-12 10:58:48 -07001822 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1823 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001824}
1825
1826
Lee Thomason2fa81722012-11-09 12:37:46 -08001827XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001828{
Dmitry-Me01578db2014-08-19 10:18:48 +04001829 FILE* fp = callfopen( filename, "w" );
1830 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001831 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001832 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001833 }
1834 SaveFile(fp, compact);
1835 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001836 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001837}
1838
1839
Lee Thomason2fa81722012-11-09 12:37:46 -08001840XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001841{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001842 XMLPrinter stream( fp, compact );
1843 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001844 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001845}
1846
Lee Thomason1ff38e02012-02-14 18:18:16 -08001847
Lee Thomason2fa81722012-11-09 12:37:46 -08001848XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001849{
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001850 const char* start = p;
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001851 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001852
Lee Thomason82d32002014-02-21 22:47:18 -08001853 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001854 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001855 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001856 }
1857 if ( len == (size_t)(-1) ) {
1858 len = strlen( p );
1859 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001860 _charBuffer = new char[ len+1 ];
1861 memcpy( _charBuffer, p, len );
1862 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001863
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001864 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001865 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001866 if ( !p || !*p ) {
1867 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001868 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001869 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001870
Thomas Roß1470edc2013-05-10 15:44:12 +02001871 ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001872 ParseDeep( _charBuffer+delta, 0 );
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001873 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001874 // clean up now essentially dangling memory.
1875 // and the parse fail can put objects in the
1876 // pools that are dead and inaccessible.
1877 DeleteChildren();
1878 _elementPool.Clear();
1879 _attributePool.Clear();
1880 _textPool.Clear();
1881 _commentPool.Clear();
1882 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001883 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001884}
1885
1886
PKEuS1c5f99e2013-07-06 11:28:39 +02001887void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001888{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001889 XMLPrinter stdStreamer( stdout );
1890 if ( !streamer ) {
1891 streamer = &stdStreamer;
1892 }
1893 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001894}
1895
1896
Lee Thomason2fa81722012-11-09 12:37:46 -08001897void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001898{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001899 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07001900 _errorID = error;
1901 _errorStr1 = str1;
1902 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001903}
1904
Lee Thomason331596e2014-09-11 14:56:43 -07001905const char* XMLDocument::ErrorName() const
1906{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001907 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Lee Thomason331596e2014-09-11 14:56:43 -07001908 return _errorNames[_errorID];
1909}
Lee Thomason5cae8972012-01-24 18:03:07 -08001910
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001911void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001912{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001913 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001914 static const int LEN = 20;
1915 char buf1[LEN] = { 0 };
1916 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001917
Lee Thomason624d43f2012-10-12 10:58:48 -07001918 if ( _errorStr1 ) {
1919 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001920 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001921 if ( _errorStr2 ) {
1922 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001923 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001924
Lee Thomason331596e2014-09-11 14:56:43 -07001925 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
1926 _errorID, ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001927 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001928}
1929
1930
PKEuS1bfb9542013-08-04 13:51:17 +02001931XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001932 _elementJustOpened( false ),
1933 _firstElement( true ),
1934 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001935 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001936 _textDepth( -1 ),
1937 _processEntities( true ),
1938 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001939{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001940 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001941 _entityFlag[i] = false;
1942 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001943 }
1944 for( int i=0; i<NUM_ENTITIES; ++i ) {
1945 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1946 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001947 _entityFlag[ (int)entities[i].value ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001948 }
1949 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001950 _restrictedEntityFlag[(int)'&'] = true;
1951 _restrictedEntityFlag[(int)'<'] = true;
1952 _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
1953 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001954}
1955
1956
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001957void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001958{
1959 va_list va;
1960 va_start( va, format );
1961
Lee Thomason624d43f2012-10-12 10:58:48 -07001962 if ( _fp ) {
1963 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001964 }
1965 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001966#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001967 #if defined(WINCE)
1968 int len = 512;
1969 do {
1970 len = len*2;
1971 char* str = new char[len]();
1972 len = _vsnprintf(str, len, format, va);
1973 delete[] str;
1974 }while (len < 0);
1975 #else
Thomas Roß268c6832014-03-13 23:35:16 +01001976 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08001977 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001978#else
1979 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01001980#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001981 // Close out and re-start the va-args
1982 va_end( va );
1983 va_start( va, format );
Lee Thomasona0744c82014-03-16 10:32:27 -07001984 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
1985#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001986 #if defined(WINCE)
1987 _vsnprintf( p, len+1, format, va );
1988 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07001989 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08001990 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07001991#else
1992 vsnprintf( p, len+1, format, va );
1993#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001994 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001995 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001996}
1997
1998
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001999void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002000{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002001 for( int i=0; i<depth; ++i ) {
2002 Print( " " );
2003 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002004}
2005
2006
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002007void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002008{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002009 // Look for runs of bytes between entities to print.
2010 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07002011 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08002012
Lee Thomason624d43f2012-10-12 10:58:48 -07002013 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002014 while ( *q ) {
2015 // Remember, char is sometimes signed. (How many times has that bitten me?)
2016 if ( *q > 0 && *q < ENTITY_RANGE ) {
2017 // Check for entities. If one is found, flush
2018 // the stream up until the entity, write the
2019 // entity, and keep looking.
2020 if ( flag[(unsigned)(*q)] ) {
2021 while ( p < q ) {
2022 Print( "%c", *p );
2023 ++p;
2024 }
2025 for( int i=0; i<NUM_ENTITIES; ++i ) {
2026 if ( entities[i].value == *q ) {
2027 Print( "&%s;", entities[i].pattern );
2028 break;
2029 }
2030 }
2031 ++p;
2032 }
2033 }
2034 ++q;
2035 }
2036 }
2037 // Flush the remaining string. This will be the entire
2038 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07002039 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002040 Print( "%s", p );
2041 }
Lee Thomason857b8682012-01-25 17:50:25 -08002042}
2043
U-Stream\Leeae25a442012-02-17 17:48:16 -08002044
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002045void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002046{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002047 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002048 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 -07002049 Print( "%s", bom );
2050 }
2051 if ( writeDec ) {
2052 PushDeclaration( "xml version=\"1.0\"" );
2053 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002054}
2055
2056
Uli Kusterer593a33d2014-02-01 12:48:51 +01002057void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002058{
Lee Thomason624d43f2012-10-12 10:58:48 -07002059 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002060 SealElement();
2061 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002062 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002063
Uli Kusterer593a33d2014-02-01 12:48:51 +01002064 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002065 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002066 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002067 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002068 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002069 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002070
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002071 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002072 _elementJustOpened = true;
2073 _firstElement = false;
2074 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002075}
2076
2077
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002078void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002079{
Lee Thomason624d43f2012-10-12 10:58:48 -07002080 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002081 Print( " %s=\"", name );
2082 PrintString( value, false );
2083 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002084}
2085
2086
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002087void XMLPrinter::PushAttribute( const char* name, int v )
2088{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002089 char buf[BUF_SIZE];
2090 XMLUtil::ToStr( v, buf, BUF_SIZE );
2091 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002092}
2093
2094
2095void XMLPrinter::PushAttribute( const char* name, unsigned v )
2096{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002097 char buf[BUF_SIZE];
2098 XMLUtil::ToStr( v, buf, BUF_SIZE );
2099 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002100}
2101
2102
2103void XMLPrinter::PushAttribute( const char* name, bool v )
2104{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002105 char buf[BUF_SIZE];
2106 XMLUtil::ToStr( v, buf, BUF_SIZE );
2107 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002108}
2109
2110
2111void XMLPrinter::PushAttribute( const char* name, double v )
2112{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002113 char buf[BUF_SIZE];
2114 XMLUtil::ToStr( v, buf, BUF_SIZE );
2115 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002116}
2117
2118
Uli Kustererca412e82014-02-01 13:35:05 +01002119void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002120{
Lee Thomason624d43f2012-10-12 10:58:48 -07002121 --_depth;
2122 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002123
Lee Thomason624d43f2012-10-12 10:58:48 -07002124 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002125 Print( "/>" );
2126 }
2127 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002128 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002129 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002130 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002131 }
2132 Print( "</%s>", name );
2133 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002134
Lee Thomason624d43f2012-10-12 10:58:48 -07002135 if ( _textDepth == _depth ) {
2136 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002137 }
Uli Kustererca412e82014-02-01 13:35:05 +01002138 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002139 Print( "\n" );
2140 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002141 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002142}
2143
2144
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002145void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08002146{
Lee Thomason624d43f2012-10-12 10:58:48 -07002147 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002148 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002149}
2150
2151
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002152void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002153{
Lee Thomason624d43f2012-10-12 10:58:48 -07002154 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002155
Lee Thomason624d43f2012-10-12 10:58:48 -07002156 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002157 SealElement();
2158 }
2159 if ( cdata ) {
2160 Print( "<![CDATA[" );
2161 Print( "%s", text );
2162 Print( "]]>" );
2163 }
2164 else {
2165 PrintString( text, true );
2166 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002167}
2168
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002169void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002170{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002171 char buf[BUF_SIZE];
2172 XMLUtil::ToStr( value, buf, BUF_SIZE );
2173 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002174}
2175
2176
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002177void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002178{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002179 char buf[BUF_SIZE];
2180 XMLUtil::ToStr( value, buf, BUF_SIZE );
2181 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002182}
2183
2184
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002185void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002186{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002187 char buf[BUF_SIZE];
2188 XMLUtil::ToStr( value, buf, BUF_SIZE );
2189 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002190}
2191
2192
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002193void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002194{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002195 char buf[BUF_SIZE];
2196 XMLUtil::ToStr( value, buf, BUF_SIZE );
2197 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002198}
2199
2200
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002201void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002202{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002203 char buf[BUF_SIZE];
2204 XMLUtil::ToStr( value, buf, BUF_SIZE );
2205 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002206}
2207
Lee Thomason5cae8972012-01-24 18:03:07 -08002208
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002209void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002210{
Lee Thomason624d43f2012-10-12 10:58:48 -07002211 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002212 SealElement();
2213 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002214 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002215 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002216 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002217 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002218 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002219 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002220}
Lee Thomason751da522012-02-10 08:50:51 -08002221
2222
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002223void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002224{
Lee Thomason624d43f2012-10-12 10:58:48 -07002225 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002226 SealElement();
2227 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002228 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002229 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002230 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002231 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002232 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002233 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002234}
2235
2236
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002237void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002238{
Lee Thomason624d43f2012-10-12 10:58:48 -07002239 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002240 SealElement();
2241 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002242 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002243 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002244 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002245 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002246 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002247 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002248}
2249
2250
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002251bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002252{
Lee Thomason624d43f2012-10-12 10:58:48 -07002253 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002254 if ( doc.HasBOM() ) {
2255 PushHeader( true, false );
2256 }
2257 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002258}
2259
2260
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002261bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002262{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002263 const XMLElement* parentElem = element.Parent()->ToElement();
2264 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2265 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002266 while ( attribute ) {
2267 PushAttribute( attribute->Name(), attribute->Value() );
2268 attribute = attribute->Next();
2269 }
2270 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002271}
2272
2273
Uli Kustererca412e82014-02-01 13:35:05 +01002274bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002275{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002276 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002277 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002278}
2279
2280
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002281bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002282{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002283 PushText( text.Value(), text.CData() );
2284 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002285}
2286
2287
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002288bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002289{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002290 PushComment( comment.Value() );
2291 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002292}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002293
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002294bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002295{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002296 PushDeclaration( declaration.Value() );
2297 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002298}
2299
2300
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002301bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002302{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002303 PushUnknown( unknown.Value() );
2304 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002305}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002306
Lee Thomason685b8952012-11-12 13:00:06 -08002307} // namespace tinyxml2
2308