blob: 6248f2c869bd2b30ccd23b7f94e4c5e9c8656683 [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
U-Lama\Lee560bd472011-12-28 19:42:49 -080024#include "tinyxml2.h"
25
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070026#include <new> // yes, this one new style header, is in the Android SDK.
Anton Indrawanf59e2d62014-11-18 20:50:42 +010027#if defined(ANDROID_NDK) || defined(__QNXNTO__)
Lee Thomasona9cf3f92012-10-11 16:56:51 -070028# include <stddef.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070029#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070030# include <cstddef>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070031#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080032
Lee Thomasone4422302012-01-20 17:59:50 -080033static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -080034static const char LF = LINE_FEED;
35static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
36static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -080037static const char SINGLE_QUOTE = '\'';
38static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -080039
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080040// Bunch of unicode info at:
41// http://www.unicode.org/faq/utf_bom.html
42// ef bb bf (Microsoft "lead bytes") - designates UTF-8
43
44static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
45static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
46static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080047
Kevin Wojniak04c22d22012-11-08 11:02:22 -080048namespace tinyxml2
49{
50
Lee Thomason8ee79892012-01-25 17:44:30 -080051struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -070052 const char* pattern;
53 int length;
54 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -080055};
56
57static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070058static const Entity entities[NUM_ENTITIES] = {
59 { "quot", 4, DOUBLE_QUOTE },
60 { "amp", 3, '&' },
61 { "apos", 4, SINGLE_QUOTE },
62 { "lt", 2, '<' },
63 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -080064};
65
Lee Thomasonfde6a752012-01-14 18:08:12 -080066
Lee Thomason1a1d4a72012-02-15 09:09:25 -080067StrPair::~StrPair()
68{
Lee Thomasona9cf3f92012-10-11 16:56:51 -070069 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -080070}
71
72
Lee Thomason29658802014-11-27 22:31:11 -080073void StrPair::TransferTo( StrPair* other )
Dmitry-Me08b40dd2014-11-10 11:17:21 +030074{
Lee Thomason29658802014-11-27 22:31:11 -080075 if ( this == other ) {
Dmitry-Me08b40dd2014-11-10 11:17:21 +030076 return;
77 }
78 // This in effect implements the assignment operator by "moving"
79 // ownership (as in auto_ptr).
80
Lee Thomason29658802014-11-27 22:31:11 -080081 TIXMLASSERT( other->_flags == 0 );
82 TIXMLASSERT( other->_start == 0 );
83 TIXMLASSERT( other->_end == 0 );
Dmitry-Me08b40dd2014-11-10 11:17:21 +030084
Lee Thomason29658802014-11-27 22:31:11 -080085 other->Reset();
Dmitry-Me08b40dd2014-11-10 11:17:21 +030086
Lee Thomason29658802014-11-27 22:31:11 -080087 other->_flags = _flags;
88 other->_start = _start;
89 other->_end = _end;
Dmitry-Me08b40dd2014-11-10 11:17:21 +030090
91 _flags = 0;
92 _start = 0;
93 _end = 0;
94}
95
Lee Thomason1a1d4a72012-02-15 09:09:25 -080096void StrPair::Reset()
97{
Lee Thomason120b3a62012-10-12 10:06:59 -070098 if ( _flags & NEEDS_DELETE ) {
99 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700100 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700101 _flags = 0;
102 _start = 0;
103 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800104}
105
106
107void StrPair::SetStr( const char* str, int flags )
108{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700109 Reset();
110 size_t len = strlen( str );
Lee Thomason120b3a62012-10-12 10:06:59 -0700111 _start = new char[ len+1 ];
112 memcpy( _start, str, len+1 );
113 _end = _start + len;
114 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800115}
116
117
118char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
119{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700120 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800121
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400122 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700123 char endChar = *endTag;
124 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800125
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700126 // Inner loop of text parsing.
127 while ( *p ) {
128 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
129 Set( start, p, strFlags );
130 return p + length;
131 }
132 ++p;
133 }
134 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800135}
136
137
138char* StrPair::ParseName( char* p )
139{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400140 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700141 return 0;
142 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800143
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400144 char* const start = p;
145
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +0200146 while( *p && ( p == start ? XMLUtil::IsNameStartChar( *p ) : XMLUtil::IsNameChar( *p ) )) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700147 ++p;
148 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800149
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700150 if ( p > start ) {
151 Set( start, p, 0 );
152 return p;
153 }
154 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800155}
156
157
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700158void StrPair::CollapseWhitespace()
159{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400160 // Adjusting _start would cause undefined behavior on delete[]
161 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700162 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700163 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700164
Lee Thomason120b3a62012-10-12 10:06:59 -0700165 if ( _start && *_start ) {
166 char* p = _start; // the read pointer
167 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700168
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700169 while( *p ) {
170 if ( XMLUtil::IsWhiteSpace( *p )) {
171 p = XMLUtil::SkipWhiteSpace( p );
172 if ( *p == 0 ) {
173 break; // don't write to q; this trims the trailing space.
174 }
175 *q = ' ';
176 ++q;
177 }
178 *q = *p;
179 ++q;
180 ++p;
181 }
182 *q = 0;
183 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700184}
185
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800186
Lee Thomasone4422302012-01-20 17:59:50 -0800187const char* StrPair::GetStr()
188{
Lee Thomason120b3a62012-10-12 10:06:59 -0700189 if ( _flags & NEEDS_FLUSH ) {
190 *_end = 0;
191 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800192
Lee Thomason120b3a62012-10-12 10:06:59 -0700193 if ( _flags ) {
194 char* p = _start; // the read pointer
195 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800196
Lee Thomason120b3a62012-10-12 10:06:59 -0700197 while( p < _end ) {
198 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700199 // CR-LF pair becomes LF
200 // CR alone becomes LF
201 // LF-CR becomes LF
202 if ( *(p+1) == LF ) {
203 p += 2;
204 }
205 else {
206 ++p;
207 }
208 *q++ = LF;
209 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700210 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700211 if ( *(p+1) == CR ) {
212 p += 2;
213 }
214 else {
215 ++p;
216 }
217 *q++ = LF;
218 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700219 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700220 // Entities handled by tinyXML2:
221 // - special entities in the entity table [in/out]
222 // - numeric character reference [in]
223 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800224
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700225 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400226 const int buflen = 10;
227 char buf[buflen] = { 0 };
228 int len = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700229 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
Dmitry-Me63f3de12014-08-21 12:33:19 +0400230 TIXMLASSERT( 0 <= len && len <= buflen );
231 TIXMLASSERT( q + len <= p );
232 memcpy( q, buf, len );
233 q += len;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700234 }
235 else {
236 int i=0;
237 for(; i<NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400238 const Entity& entity = entities[i];
239 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
240 && *( p + entity.length + 1 ) == ';' ) {
241 // Found an entity - convert.
242 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700243 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400244 p += entity.length + 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700245 break;
246 }
247 }
248 if ( i == NUM_ENTITIES ) {
249 // fixme: treat as error?
250 ++p;
251 ++q;
252 }
253 }
254 }
255 else {
256 *q = *p;
257 ++p;
258 ++q;
259 }
260 }
261 *q = 0;
262 }
263 // The loop below has plenty going on, and this
264 // is a less useful mode. Break it out.
Lee Thomason120b3a62012-10-12 10:06:59 -0700265 if ( _flags & COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700266 CollapseWhitespace();
267 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700268 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700269 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700270 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800271}
272
Lee Thomason2c85a712012-01-31 08:24:24 -0800273
Lee Thomasone4422302012-01-20 17:59:50 -0800274
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800275
Lee Thomason56bdd022012-02-09 18:16:58 -0800276// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800277
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800278const char* XMLUtil::ReadBOM( const char* p, bool* bom )
279{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700280 *bom = false;
281 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
282 // Check for BOM:
283 if ( *(pu+0) == TIXML_UTF_LEAD_0
284 && *(pu+1) == TIXML_UTF_LEAD_1
285 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
286 *bom = true;
287 p += 3;
288 }
289 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800290}
291
292
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800293void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
294{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700295 const unsigned long BYTE_MASK = 0xBF;
296 const unsigned long BYTE_MARK = 0x80;
297 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800298
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700299 if (input < 0x80) {
300 *length = 1;
301 }
302 else if ( input < 0x800 ) {
303 *length = 2;
304 }
305 else if ( input < 0x10000 ) {
306 *length = 3;
307 }
308 else if ( input < 0x200000 ) {
309 *length = 4;
310 }
311 else {
312 *length = 0; // This code won't covert this correctly anyway.
313 return;
314 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800315
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700316 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800317
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700318 // Scary scary fall throughs.
319 switch (*length) {
320 case 4:
321 --output;
322 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
323 input >>= 6;
324 case 3:
325 --output;
326 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
327 input >>= 6;
328 case 2:
329 --output;
330 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
331 input >>= 6;
332 case 1:
333 --output;
334 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100335 default:
336 break;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700337 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800338}
339
340
341const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
342{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700343 // Presume an entity, and pull it out.
344 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800345
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700346 if ( *(p+1) == '#' && *(p+2) ) {
347 unsigned long ucs = 0;
348 ptrdiff_t delta = 0;
349 unsigned mult = 1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800350
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700351 if ( *(p+2) == 'x' ) {
352 // Hexadecimal.
353 if ( !*(p+3) ) {
354 return 0;
355 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800356
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700357 const char* q = p+3;
358 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800359
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700360 if ( !q || !*q ) {
361 return 0;
362 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800363
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700364 delta = q-p;
365 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800366
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700367 while ( *q != 'x' ) {
368 if ( *q >= '0' && *q <= '9' ) {
369 ucs += mult * (*q - '0');
370 }
371 else if ( *q >= 'a' && *q <= 'f' ) {
372 ucs += mult * (*q - 'a' + 10);
373 }
374 else if ( *q >= 'A' && *q <= 'F' ) {
375 ucs += mult * (*q - 'A' + 10 );
376 }
377 else {
378 return 0;
379 }
380 mult *= 16;
381 --q;
382 }
383 }
384 else {
385 // Decimal.
386 if ( !*(p+2) ) {
387 return 0;
388 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800389
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700390 const char* q = p+2;
391 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800392
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700393 if ( !q || !*q ) {
394 return 0;
395 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800396
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700397 delta = q-p;
398 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800399
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700400 while ( *q != '#' ) {
401 if ( *q >= '0' && *q <= '9' ) {
402 ucs += mult * (*q - '0');
403 }
404 else {
405 return 0;
406 }
407 mult *= 10;
408 --q;
409 }
410 }
411 // convert the UCS to UTF-8
412 ConvertUTF32ToUTF8( ucs, value, length );
413 return p + delta + 1;
414 }
415 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800416}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800417
418
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700419void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700420{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700421 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700422}
423
424
425void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
426{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700427 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700428}
429
430
431void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
432{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700433 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700434}
435
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800436/*
437 ToStr() of a number is a very tricky topic.
438 https://github.com/leethomason/tinyxml2/issues/106
439*/
Lee Thomason21be8822012-07-15 17:27:22 -0700440void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
441{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800442 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700443}
444
445
446void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
447{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800448 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700449}
450
451
452bool XMLUtil::ToInt( const char* str, int* value )
453{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700454 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
455 return true;
456 }
457 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700458}
459
460bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
461{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700462 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
463 return true;
464 }
465 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700466}
467
468bool XMLUtil::ToBool( const char* str, bool* value )
469{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700470 int ival = 0;
471 if ( ToInt( str, &ival )) {
472 *value = (ival==0) ? false : true;
473 return true;
474 }
475 if ( StringEqual( str, "true" ) ) {
476 *value = true;
477 return true;
478 }
479 else if ( StringEqual( str, "false" ) ) {
480 *value = false;
481 return true;
482 }
483 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700484}
485
486
487bool XMLUtil::ToFloat( const char* str, float* value )
488{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700489 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
490 return true;
491 }
492 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700493}
494
495bool XMLUtil::ToDouble( const char* str, double* value )
496{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700497 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
498 return true;
499 }
500 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700501}
502
503
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700504char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800505{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400506 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700507 p = XMLUtil::SkipWhiteSpace( p );
508 if( !p || !*p ) {
509 return p;
510 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800511
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700512 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800513 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700514 static const char* xmlHeader = { "<?" };
515 static const char* commentHeader = { "<!--" };
516 static const char* dtdHeader = { "<!" };
517 static const char* cdataHeader = { "<![CDATA[" };
518 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800519
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700520 static const int xmlHeaderLen = 2;
521 static const int commentHeaderLen = 4;
522 static const int dtdHeaderLen = 2;
523 static const int cdataHeaderLen = 9;
524 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800525
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800526#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800527#pragma warning ( push )
528#pragma warning ( disable : 4127 )
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800529#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700530 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
531 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800532#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800533#pragma warning (pop)
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800534#endif
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400535 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700536 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700537 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
538 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700539 p += xmlHeaderLen;
540 }
541 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700542 returnNode = new (_commentPool.Alloc()) XMLComment( this );
543 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700544 p += commentHeaderLen;
545 }
546 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700547 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700548 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700549 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700550 p += cdataHeaderLen;
551 text->SetCData( true );
552 }
553 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700554 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
555 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700556 p += dtdHeaderLen;
557 }
558 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700559 returnNode = new (_elementPool.Alloc()) XMLElement( this );
560 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700561 p += elementHeaderLen;
562 }
563 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700564 returnNode = new (_textPool.Alloc()) XMLText( this );
565 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700566 p = start; // Back it up, all the text counts.
567 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800568
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700569 *node = returnNode;
570 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800571}
572
573
Lee Thomason751da522012-02-10 08:50:51 -0800574bool XMLDocument::Accept( XMLVisitor* visitor ) const
575{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700576 if ( visitor->VisitEnter( *this ) ) {
577 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
578 if ( !node->Accept( visitor ) ) {
579 break;
580 }
581 }
582 }
583 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800584}
Lee Thomason56bdd022012-02-09 18:16:58 -0800585
586
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800587// --------- XMLNode ----------- //
588
589XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700590 _document( doc ),
591 _parent( 0 ),
592 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200593 _prev( 0 ), _next( 0 ),
594 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800595{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800596}
597
598
599XMLNode::~XMLNode()
600{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700601 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700602 if ( _parent ) {
603 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700604 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800605}
606
Michael Daumling21626882013-10-22 17:03:37 +0200607const char* XMLNode::Value() const
608{
609 return _value.GetStr();
610}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800611
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800612void XMLNode::SetValue( const char* str, bool staticMem )
613{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700614 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700615 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700616 }
617 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700618 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700619 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800620}
621
622
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800623void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800624{
Lee Thomason624d43f2012-10-12 10:58:48 -0700625 while( _firstChild ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300626 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700627 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700628 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700629
Dmitry-Mee3225b12014-09-03 11:03:11 +0400630 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700631 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700632 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800633}
634
635
636void XMLNode::Unlink( XMLNode* child )
637{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300638 TIXMLASSERT( child->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700639 if ( child == _firstChild ) {
640 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700641 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700642 if ( child == _lastChild ) {
643 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700644 }
Lee Thomasond923c672012-01-23 08:44:25 -0800645
Lee Thomason624d43f2012-10-12 10:58:48 -0700646 if ( child->_prev ) {
647 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700648 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700649 if ( child->_next ) {
650 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700651 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700652 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800653}
654
655
U-Stream\Leeae25a442012-02-17 17:48:16 -0800656void XMLNode::DeleteChild( XMLNode* node )
657{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300658 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700659 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400660 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800661}
662
663
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800664XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
665{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300666 if ( addThis->_document != _document ) {
667 TIXMLASSERT( false );
668 return 0;
669 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700670
Michael Daumlinged523282013-10-23 07:47:29 +0200671 if (addThis->_parent)
672 addThis->_parent->Unlink( addThis );
673 else
674 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700675
Lee Thomason624d43f2012-10-12 10:58:48 -0700676 if ( _lastChild ) {
677 TIXMLASSERT( _firstChild );
678 TIXMLASSERT( _lastChild->_next == 0 );
679 _lastChild->_next = addThis;
680 addThis->_prev = _lastChild;
681 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800682
Lee Thomason624d43f2012-10-12 10:58:48 -0700683 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700684 }
685 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700686 TIXMLASSERT( _firstChild == 0 );
687 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800688
Lee Thomason624d43f2012-10-12 10:58:48 -0700689 addThis->_prev = 0;
690 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700691 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700692 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700693 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800694}
695
696
Lee Thomason1ff38e02012-02-14 18:18:16 -0800697XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
698{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300699 if ( addThis->_document != _document ) {
700 TIXMLASSERT( false );
701 return 0;
702 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700703
Michael Daumlinged523282013-10-23 07:47:29 +0200704 if (addThis->_parent)
705 addThis->_parent->Unlink( addThis );
706 else
707 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700708
Lee Thomason624d43f2012-10-12 10:58:48 -0700709 if ( _firstChild ) {
710 TIXMLASSERT( _lastChild );
711 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800712
Lee Thomason624d43f2012-10-12 10:58:48 -0700713 _firstChild->_prev = addThis;
714 addThis->_next = _firstChild;
715 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800716
Lee Thomason624d43f2012-10-12 10:58:48 -0700717 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700718 }
719 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700720 TIXMLASSERT( _lastChild == 0 );
721 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800722
Lee Thomason624d43f2012-10-12 10:58:48 -0700723 addThis->_prev = 0;
724 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700725 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700726 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400727 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800728}
729
730
731XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
732{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300733 TIXMLASSERT( addThis );
734 if ( addThis->_document != _document ) {
735 TIXMLASSERT( false );
736 return 0;
737 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700738
Dmitry-Meabb2d042014-12-09 12:59:31 +0300739 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700740
Lee Thomason624d43f2012-10-12 10:58:48 -0700741 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300742 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700743 return 0;
744 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800745
Lee Thomason624d43f2012-10-12 10:58:48 -0700746 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700747 // The last node or the only node.
748 return InsertEndChild( addThis );
749 }
Michael Daumlinged523282013-10-23 07:47:29 +0200750 if (addThis->_parent)
751 addThis->_parent->Unlink( addThis );
752 else
753 addThis->_memPool->SetTracked();
Lee Thomason624d43f2012-10-12 10:58:48 -0700754 addThis->_prev = afterThis;
755 addThis->_next = afterThis->_next;
756 afterThis->_next->_prev = addThis;
757 afterThis->_next = addThis;
758 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700759 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800760}
761
762
763
764
Lee Thomason56bdd022012-02-09 18:16:58 -0800765const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800766{
Lee Thomason624d43f2012-10-12 10:58:48 -0700767 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700768 XMLElement* element = node->ToElement();
769 if ( element ) {
770 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
771 return element;
772 }
773 }
774 }
775 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800776}
777
778
Lee Thomason56bdd022012-02-09 18:16:58 -0800779const XMLElement* XMLNode::LastChildElement( const char* value ) const
780{
Lee Thomason624d43f2012-10-12 10:58:48 -0700781 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700782 XMLElement* element = node->ToElement();
783 if ( element ) {
784 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
785 return element;
786 }
787 }
788 }
789 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800790}
791
792
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800793const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
794{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400795 for( XMLNode* node=this->_next; node; node = node->_next ) {
796 const XMLElement* element = node->ToElement();
797 if ( element
798 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
799 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700800 }
801 }
802 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800803}
804
805
806const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
807{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400808 for( XMLNode* node=_prev; node; node = node->_prev ) {
809 const XMLElement* element = node->ToElement();
810 if ( element
811 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
812 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700813 }
814 }
815 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800816}
817
818
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800819char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800820{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700821 // This is a recursive method, but thinking about it "at the current level"
822 // it is a pretty simple flat list:
823 // <foo/>
824 // <!-- comment -->
825 //
826 // With a special case:
827 // <foo>
828 // </foo>
829 // <!-- comment -->
830 //
831 // Where the closing element (/foo) *must* be the next thing after the opening
832 // element, and the names must match. BUT the tricky bit is that the closing
833 // element will be read by the child.
834 //
835 // 'endTag' is the end tag for this node, it is returned by a call to a child.
836 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800837
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700838 while( p && *p ) {
839 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800840
Lee Thomason624d43f2012-10-12 10:58:48 -0700841 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700842 if ( p == 0 || node == 0 ) {
843 break;
844 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800845
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700846 StrPair endTag;
847 p = node->ParseDeep( p, &endTag );
848 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400849 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700850 node = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -0700851 if ( !_document->Error() ) {
852 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700853 }
854 break;
855 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800856
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400857 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700858 // We read the end tag. Return it to the parent.
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400859 if ( ele && ele->ClosingType() == XMLElement::CLOSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700860 if ( parentEnd ) {
Lee Thomason29658802014-11-27 22:31:11 -0800861 ele->_value.TransferTo( parentEnd );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700862 }
Lee Thomason5b0a6772012-11-19 13:54:42 -0800863 node->_memPool->SetTracked(); // created and then immediately deleted.
Dmitry-Mee3225b12014-09-03 11:03:11 +0400864 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700865 return p;
866 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800867
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700868 // Handle an end tag returned to this level.
869 // And handle a bunch of annoying errors.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700870 if ( ele ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400871 bool mismatch = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700872 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400873 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700874 }
875 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400876 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700877 }
878 else if ( !endTag.Empty() ) {
879 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400880 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700881 }
882 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400883 if ( mismatch ) {
884 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
885 p = 0;
886 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700887 }
888 if ( p == 0 ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400889 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700890 node = 0;
891 }
892 if ( node ) {
893 this->InsertEndChild( node );
894 }
895 }
896 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800897}
898
Dmitry-Mee3225b12014-09-03 11:03:11 +0400899void XMLNode::DeleteNode( XMLNode* node )
900{
901 if ( node == 0 ) {
902 return;
903 }
904 MemPool* pool = node->_memPool;
905 node->~XMLNode();
906 pool->Free( node );
907}
908
Lee Thomason5492a1c2012-01-23 15:32:10 -0800909// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800910char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800911{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700912 const char* start = p;
913 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700914 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700915 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700916 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700917 }
918 return p;
919 }
920 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700921 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
922 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700923 flags |= StrPair::COLLAPSE_WHITESPACE;
924 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700925
Lee Thomason624d43f2012-10-12 10:58:48 -0700926 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700927 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700928 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700929 }
930 if ( p && *p ) {
931 return p-1;
932 }
933 }
934 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800935}
936
937
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800938XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
939{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700940 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700941 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700942 }
943 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
944 text->SetCData( this->CData() );
945 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800946}
947
948
949bool XMLText::ShallowEqual( const XMLNode* compare ) const
950{
Dmitry-Me6d202ff2014-09-26 14:21:00 +0400951 const XMLText* text = compare->ToText();
952 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800953}
954
955
Lee Thomason56bdd022012-02-09 18:16:58 -0800956bool XMLText::Accept( XMLVisitor* visitor ) const
957{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300958 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700959 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800960}
961
962
Lee Thomason3f57d272012-01-11 15:30:03 -0800963// --------- XMLComment ---------- //
964
Lee Thomasone4422302012-01-20 17:59:50 -0800965XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800966{
967}
968
969
Lee Thomasonce0763e2012-01-11 15:43:54 -0800970XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800971{
Lee Thomason3f57d272012-01-11 15:30:03 -0800972}
973
974
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800975char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800976{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700977 // Comment parses as text.
978 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700979 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700980 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700981 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700982 }
983 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800984}
985
986
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800987XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
988{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700989 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700990 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700991 }
992 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
993 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800994}
995
996
997bool XMLComment::ShallowEqual( const XMLNode* compare ) const
998{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300999 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001000 const XMLComment* comment = compare->ToComment();
1001 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001002}
1003
1004
Lee Thomason751da522012-02-10 08:50:51 -08001005bool XMLComment::Accept( XMLVisitor* visitor ) const
1006{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001007 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001008 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001009}
Lee Thomason56bdd022012-02-09 18:16:58 -08001010
1011
Lee Thomason50f97b22012-02-11 16:33:40 -08001012// --------- XMLDeclaration ---------- //
1013
1014XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1015{
1016}
1017
1018
1019XMLDeclaration::~XMLDeclaration()
1020{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001021 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001022}
1023
1024
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001025char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001026{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001027 // Declaration parses as text.
1028 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001029 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001030 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001031 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001032 }
1033 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001034}
1035
1036
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001037XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1038{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001039 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001040 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001041 }
1042 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1043 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001044}
1045
1046
1047bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1048{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001049 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001050 const XMLDeclaration* declaration = compare->ToDeclaration();
1051 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001052}
1053
1054
1055
Lee Thomason50f97b22012-02-11 16:33:40 -08001056bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1057{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001058 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001059 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001060}
1061
1062// --------- XMLUnknown ---------- //
1063
1064XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1065{
1066}
1067
1068
1069XMLUnknown::~XMLUnknown()
1070{
1071}
1072
1073
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001074char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001075{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001076 // Unknown parses as text.
1077 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001078
Lee Thomason624d43f2012-10-12 10:58:48 -07001079 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001080 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001081 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001082 }
1083 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001084}
1085
1086
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001087XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1088{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001089 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001090 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001091 }
1092 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1093 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001094}
1095
1096
1097bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1098{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001099 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001100 const XMLUnknown* unknown = compare->ToUnknown();
1101 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001102}
1103
1104
Lee Thomason50f97b22012-02-11 16:33:40 -08001105bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1106{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001107 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001108 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001109}
1110
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001111// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001112
1113const char* XMLAttribute::Name() const
1114{
1115 return _name.GetStr();
1116}
1117
1118const char* XMLAttribute::Value() const
1119{
1120 return _value.GetStr();
1121}
1122
Lee Thomason6f381b72012-03-02 12:59:39 -08001123char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001124{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001125 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001126 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001127 if ( !p || !*p ) {
1128 return 0;
1129 }
Lee Thomason22aead12012-01-23 13:29:35 -08001130
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001131 // Skip white space before =
1132 p = XMLUtil::SkipWhiteSpace( p );
1133 if ( !p || *p != '=' ) {
1134 return 0;
1135 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001136
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001137 ++p; // move up to opening quote
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 char endTag[2] = { *p, 0 };
1144 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001145
Lee Thomason624d43f2012-10-12 10:58:48 -07001146 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001147 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001148}
1149
1150
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001151void XMLAttribute::SetName( const char* n )
1152{
Lee Thomason624d43f2012-10-12 10:58:48 -07001153 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001154}
1155
1156
Lee Thomason2fa81722012-11-09 12:37:46 -08001157XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001158{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001159 if ( XMLUtil::ToInt( Value(), value )) {
1160 return XML_NO_ERROR;
1161 }
1162 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001163}
1164
1165
Lee Thomason2fa81722012-11-09 12:37:46 -08001166XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001167{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001168 if ( XMLUtil::ToUnsigned( Value(), value )) {
1169 return XML_NO_ERROR;
1170 }
1171 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001172}
1173
1174
Lee Thomason2fa81722012-11-09 12:37:46 -08001175XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001176{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001177 if ( XMLUtil::ToBool( Value(), value )) {
1178 return XML_NO_ERROR;
1179 }
1180 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001181}
1182
1183
Lee Thomason2fa81722012-11-09 12:37:46 -08001184XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001185{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001186 if ( XMLUtil::ToFloat( Value(), value )) {
1187 return XML_NO_ERROR;
1188 }
1189 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001190}
1191
1192
Lee Thomason2fa81722012-11-09 12:37:46 -08001193XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001194{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001195 if ( XMLUtil::ToDouble( Value(), value )) {
1196 return XML_NO_ERROR;
1197 }
1198 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001199}
1200
1201
1202void XMLAttribute::SetAttribute( const char* v )
1203{
Lee Thomason624d43f2012-10-12 10:58:48 -07001204 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001205}
1206
1207
Lee Thomason1ff38e02012-02-14 18:18:16 -08001208void XMLAttribute::SetAttribute( int v )
1209{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001210 char buf[BUF_SIZE];
1211 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001212 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001213}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001214
1215
1216void XMLAttribute::SetAttribute( unsigned v )
1217{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001218 char buf[BUF_SIZE];
1219 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001220 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001221}
1222
1223
1224void XMLAttribute::SetAttribute( bool v )
1225{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001226 char buf[BUF_SIZE];
1227 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001228 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001229}
1230
1231void XMLAttribute::SetAttribute( double v )
1232{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001233 char buf[BUF_SIZE];
1234 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001235 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001236}
1237
1238void XMLAttribute::SetAttribute( float v )
1239{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001240 char buf[BUF_SIZE];
1241 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001242 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001243}
1244
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001245
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001246// --------- XMLElement ---------- //
1247XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001248 _closingType( 0 ),
1249 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001250{
1251}
1252
1253
1254XMLElement::~XMLElement()
1255{
Lee Thomason624d43f2012-10-12 10:58:48 -07001256 while( _rootAttribute ) {
1257 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001258 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001259 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001260 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001261}
1262
1263
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001264const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1265{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001266 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001267 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1268 return a;
1269 }
1270 }
1271 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001272}
1273
1274
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001275const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001276{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001277 const XMLAttribute* a = FindAttribute( name );
1278 if ( !a ) {
1279 return 0;
1280 }
1281 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1282 return a->Value();
1283 }
1284 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001285}
1286
1287
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001288const char* XMLElement::GetText() const
1289{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001290 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001291 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001292 }
1293 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001294}
1295
1296
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001297void XMLElement::SetText( const char* inText )
1298{
Uli Kusterer869bb592014-01-21 01:36:16 +01001299 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001300 FirstChild()->SetValue( inText );
1301 else {
1302 XMLText* theText = GetDocument()->NewText( inText );
1303 InsertFirstChild( theText );
1304 }
1305}
1306
Lee Thomason5bb2d802014-01-24 10:42:57 -08001307
1308void XMLElement::SetText( int v )
1309{
1310 char buf[BUF_SIZE];
1311 XMLUtil::ToStr( v, buf, BUF_SIZE );
1312 SetText( buf );
1313}
1314
1315
1316void XMLElement::SetText( unsigned v )
1317{
1318 char buf[BUF_SIZE];
1319 XMLUtil::ToStr( v, buf, BUF_SIZE );
1320 SetText( buf );
1321}
1322
1323
1324void XMLElement::SetText( bool v )
1325{
1326 char buf[BUF_SIZE];
1327 XMLUtil::ToStr( v, buf, BUF_SIZE );
1328 SetText( buf );
1329}
1330
1331
1332void XMLElement::SetText( float v )
1333{
1334 char buf[BUF_SIZE];
1335 XMLUtil::ToStr( v, buf, BUF_SIZE );
1336 SetText( buf );
1337}
1338
1339
1340void XMLElement::SetText( double v )
1341{
1342 char buf[BUF_SIZE];
1343 XMLUtil::ToStr( v, buf, BUF_SIZE );
1344 SetText( buf );
1345}
1346
1347
MortenMacFly4ee49f12013-01-14 20:03:14 +01001348XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001349{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001350 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001351 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001352 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001353 return XML_SUCCESS;
1354 }
1355 return XML_CAN_NOT_CONVERT_TEXT;
1356 }
1357 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001358}
1359
1360
MortenMacFly4ee49f12013-01-14 20:03:14 +01001361XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001362{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001363 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001364 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001365 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001366 return XML_SUCCESS;
1367 }
1368 return XML_CAN_NOT_CONVERT_TEXT;
1369 }
1370 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001371}
1372
1373
MortenMacFly4ee49f12013-01-14 20:03:14 +01001374XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001375{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001376 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001377 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001378 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001379 return XML_SUCCESS;
1380 }
1381 return XML_CAN_NOT_CONVERT_TEXT;
1382 }
1383 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001384}
1385
1386
MortenMacFly4ee49f12013-01-14 20:03:14 +01001387XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001388{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001389 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001390 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001391 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001392 return XML_SUCCESS;
1393 }
1394 return XML_CAN_NOT_CONVERT_TEXT;
1395 }
1396 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001397}
1398
1399
MortenMacFly4ee49f12013-01-14 20:03:14 +01001400XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001401{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001402 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001403 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001404 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001405 return XML_SUCCESS;
1406 }
1407 return XML_CAN_NOT_CONVERT_TEXT;
1408 }
1409 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001410}
1411
1412
1413
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001414XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1415{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001416 XMLAttribute* last = 0;
1417 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001418 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001419 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001420 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001421 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1422 break;
1423 }
1424 }
1425 if ( !attrib ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001426 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1427 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001428 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001429 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001430 }
1431 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001432 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001433 }
1434 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001435 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001436 }
1437 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001438}
1439
1440
U-Stream\Leeae25a442012-02-17 17:48:16 -08001441void XMLElement::DeleteAttribute( const char* name )
1442{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001443 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001444 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001445 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1446 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001447 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001448 }
1449 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001450 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001451 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001452 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001453 break;
1454 }
1455 prev = a;
1456 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001457}
1458
1459
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001460char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001461{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001462 const char* start = p;
1463 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001464
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001465 // Read the attributes.
1466 while( p ) {
1467 p = XMLUtil::SkipWhiteSpace( p );
1468 if ( !p || !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001469 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001470 return 0;
1471 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001472
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001473 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001474 if (XMLUtil::IsNameStartChar( *p ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001475 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1476 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001477 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001478
Lee Thomason624d43f2012-10-12 10:58:48 -07001479 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001480 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001481 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001482 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001483 return 0;
1484 }
1485 // There is a minor bug here: if the attribute in the source xml
1486 // document is duplicated, it will not be detected and the
1487 // attribute will be doubly added. However, tracking the 'prevAttribute'
1488 // avoids re-scanning the attribute list. Preferring performance for
1489 // now, may reconsider in the future.
1490 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001491 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001492 }
1493 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001494 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001495 }
1496 prevAttribute = attrib;
1497 }
1498 // end of the tag
1499 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001500 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001501 return p+2; // done; sealed element.
1502 }
1503 // end of the tag
1504 else if ( *p == '>' ) {
1505 ++p;
1506 break;
1507 }
1508 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001509 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001510 return 0;
1511 }
1512 }
1513 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001514}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001515
Dmitry-Mee3225b12014-09-03 11:03:11 +04001516void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1517{
1518 if ( attribute == 0 ) {
1519 return;
1520 }
1521 MemPool* pool = attribute->_memPool;
1522 attribute->~XMLAttribute();
1523 pool->Free( attribute );
1524}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001525
Lee Thomason67d61312012-01-24 16:01:51 -08001526//
1527// <ele></ele>
1528// <ele>foo<b>bar</b></ele>
1529//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001530char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001531{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001532 // Read the element name.
1533 p = XMLUtil::SkipWhiteSpace( p );
1534 if ( !p ) {
1535 return 0;
1536 }
Lee Thomason67d61312012-01-24 16:01:51 -08001537
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001538 // The closing element is the </element> form. It is
1539 // parsed just like a regular element then deleted from
1540 // the DOM.
1541 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001542 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001543 ++p;
1544 }
Lee Thomason67d61312012-01-24 16:01:51 -08001545
Lee Thomason624d43f2012-10-12 10:58:48 -07001546 p = _value.ParseName( p );
1547 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001548 return 0;
1549 }
Lee Thomason67d61312012-01-24 16:01:51 -08001550
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001551 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001552 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001553 return p;
1554 }
Lee Thomason67d61312012-01-24 16:01:51 -08001555
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001556 p = XMLNode::ParseDeep( p, strPair );
1557 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001558}
1559
1560
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001561
1562XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1563{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001564 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001565 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001566 }
1567 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1568 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1569 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1570 }
1571 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001572}
1573
1574
1575bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1576{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001577 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001578 const XMLElement* other = compare->ToElement();
1579 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001580
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001581 const XMLAttribute* a=FirstAttribute();
1582 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001583
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001584 while ( a && b ) {
1585 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1586 return false;
1587 }
1588 a = a->Next();
1589 b = b->Next();
1590 }
1591 if ( a || b ) {
1592 // different count
1593 return false;
1594 }
1595 return true;
1596 }
1597 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001598}
1599
1600
Lee Thomason751da522012-02-10 08:50:51 -08001601bool XMLElement::Accept( XMLVisitor* visitor ) const
1602{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001603 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001604 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001605 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1606 if ( !node->Accept( visitor ) ) {
1607 break;
1608 }
1609 }
1610 }
1611 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001612}
Lee Thomason56bdd022012-02-09 18:16:58 -08001613
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001614
Lee Thomason3f57d272012-01-11 15:30:03 -08001615// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001616
1617// Warning: List must match 'enum XMLError'
1618const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1619 "XML_SUCCESS",
1620 "XML_NO_ATTRIBUTE",
1621 "XML_WRONG_ATTRIBUTE_TYPE",
1622 "XML_ERROR_FILE_NOT_FOUND",
1623 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1624 "XML_ERROR_FILE_READ_ERROR",
1625 "XML_ERROR_ELEMENT_MISMATCH",
1626 "XML_ERROR_PARSING_ELEMENT",
1627 "XML_ERROR_PARSING_ATTRIBUTE",
1628 "XML_ERROR_IDENTIFYING_TAG",
1629 "XML_ERROR_PARSING_TEXT",
1630 "XML_ERROR_PARSING_CDATA",
1631 "XML_ERROR_PARSING_COMMENT",
1632 "XML_ERROR_PARSING_DECLARATION",
1633 "XML_ERROR_PARSING_UNKNOWN",
1634 "XML_ERROR_EMPTY_DOCUMENT",
1635 "XML_ERROR_MISMATCHED_ELEMENT",
1636 "XML_ERROR_PARSING",
1637 "XML_CAN_NOT_CONVERT_TEXT",
1638 "XML_NO_TEXT_NODE"
1639};
1640
1641
Lee Thomason624d43f2012-10-12 10:58:48 -07001642XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001643 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001644 _writeBOM( false ),
1645 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001646 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001647 _whitespace( whitespace ),
1648 _errorStr1( 0 ),
1649 _errorStr2( 0 ),
1650 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001651{
Lee Thomason624d43f2012-10-12 10:58:48 -07001652 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001653}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001654
1655
Lee Thomason3f57d272012-01-11 15:30:03 -08001656XMLDocument::~XMLDocument()
1657{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001658 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001659}
1660
1661
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001662void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001663{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001664 DeleteChildren();
1665
Dmitry-Meab37df82014-11-28 12:08:36 +03001666#ifdef DEBUG
1667 const bool hadError = Error();
1668#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001669 _errorID = XML_NO_ERROR;
1670 _errorStr1 = 0;
1671 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001672
Lee Thomason624d43f2012-10-12 10:58:48 -07001673 delete [] _charBuffer;
1674 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001675
1676#if 0
1677 _textPool.Trace( "text" );
1678 _elementPool.Trace( "element" );
1679 _commentPool.Trace( "comment" );
1680 _attributePool.Trace( "attribute" );
1681#endif
1682
1683#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001684 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001685 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1686 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1687 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1688 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1689 }
1690#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001691}
1692
Lee Thomason3f57d272012-01-11 15:30:03 -08001693
Lee Thomason2c85a712012-01-31 08:24:24 -08001694XMLElement* XMLDocument::NewElement( const char* name )
1695{
Lee Thomason624d43f2012-10-12 10:58:48 -07001696 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1697 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001698 ele->SetName( name );
1699 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001700}
1701
1702
Lee Thomason1ff38e02012-02-14 18:18:16 -08001703XMLComment* XMLDocument::NewComment( const char* str )
1704{
Lee Thomason624d43f2012-10-12 10:58:48 -07001705 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1706 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001707 comment->SetValue( str );
1708 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001709}
1710
1711
1712XMLText* XMLDocument::NewText( const char* str )
1713{
Lee Thomason624d43f2012-10-12 10:58:48 -07001714 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1715 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001716 text->SetValue( str );
1717 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001718}
1719
1720
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001721XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1722{
Lee Thomason624d43f2012-10-12 10:58:48 -07001723 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1724 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001725 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1726 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001727}
1728
1729
1730XMLUnknown* XMLDocument::NewUnknown( const char* str )
1731{
Lee Thomason624d43f2012-10-12 10:58:48 -07001732 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1733 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001734 unk->SetValue( str );
1735 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001736}
1737
Dmitry-Me01578db2014-08-19 10:18:48 +04001738static FILE* callfopen( const char* filepath, const char* mode )
1739{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001740 TIXMLASSERT( filepath );
1741 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001742#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1743 FILE* fp = 0;
1744 errno_t err = fopen_s( &fp, filepath, mode );
1745 if ( err ) {
1746 return 0;
1747 }
1748#else
1749 FILE* fp = fopen( filepath, mode );
1750#endif
1751 return fp;
1752}
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001753
Lee Thomason2fa81722012-11-09 12:37:46 -08001754XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001755{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001756 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001757 FILE* fp = callfopen( filename, "rb" );
1758 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001759 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001760 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001761 }
1762 LoadFile( fp );
1763 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001764 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001765}
1766
1767
Lee Thomason2fa81722012-11-09 12:37:46 -08001768XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001769{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001770 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001771
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001772 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001773 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001774 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1775 return _errorID;
1776 }
1777
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001778 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001779 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001780 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001781 if ( filelength == -1L ) {
1782 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1783 return _errorID;
1784 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001785
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001786 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001787 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001788 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001789 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001790 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001791
Lee Thomason624d43f2012-10-12 10:58:48 -07001792 _charBuffer = new char[size+1];
1793 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001794 if ( read != size ) {
1795 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001796 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001797 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001798
Lee Thomason624d43f2012-10-12 10:58:48 -07001799 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001800
Lee Thomason624d43f2012-10-12 10:58:48 -07001801 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001802 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001803 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001804 if ( !p || !*p ) {
1805 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001806 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001807 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001808
Lee Thomason624d43f2012-10-12 10:58:48 -07001809 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1810 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001811}
1812
1813
Lee Thomason2fa81722012-11-09 12:37:46 -08001814XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001815{
Dmitry-Me01578db2014-08-19 10:18:48 +04001816 FILE* fp = callfopen( filename, "w" );
1817 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001818 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001819 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001820 }
1821 SaveFile(fp, compact);
1822 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001823 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001824}
1825
1826
Lee Thomason2fa81722012-11-09 12:37:46 -08001827XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001828{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001829 XMLPrinter stream( fp, compact );
1830 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001831 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001832}
1833
Lee Thomason1ff38e02012-02-14 18:18:16 -08001834
Lee Thomason2fa81722012-11-09 12:37:46 -08001835XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001836{
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001837 const char* start = p;
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001838 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001839
Lee Thomason82d32002014-02-21 22:47:18 -08001840 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001841 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001842 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001843 }
1844 if ( len == (size_t)(-1) ) {
1845 len = strlen( p );
1846 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001847 _charBuffer = new char[ len+1 ];
1848 memcpy( _charBuffer, p, len );
1849 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001850
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001851 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001852 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001853 if ( !p || !*p ) {
1854 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 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001857
Thomas Roß1470edc2013-05-10 15:44:12 +02001858 ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001859 ParseDeep( _charBuffer+delta, 0 );
Lee Thomasonf07b9522014-10-30 13:25:12 -07001860 if (_errorID) {
1861 // clean up now essentially dangling memory.
1862 // and the parse fail can put objects in the
1863 // pools that are dead and inaccessible.
1864 DeleteChildren();
1865 _elementPool.Clear();
1866 _attributePool.Clear();
1867 _textPool.Clear();
1868 _commentPool.Clear();
1869 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001870 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001871}
1872
1873
PKEuS1c5f99e2013-07-06 11:28:39 +02001874void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001875{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001876 XMLPrinter stdStreamer( stdout );
1877 if ( !streamer ) {
1878 streamer = &stdStreamer;
1879 }
1880 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001881}
1882
1883
Lee Thomason2fa81722012-11-09 12:37:46 -08001884void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001885{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001886 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07001887 _errorID = error;
1888 _errorStr1 = str1;
1889 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001890}
1891
Lee Thomason331596e2014-09-11 14:56:43 -07001892const char* XMLDocument::ErrorName() const
1893{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001894 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Lee Thomason331596e2014-09-11 14:56:43 -07001895 return _errorNames[_errorID];
1896}
Lee Thomason5cae8972012-01-24 18:03:07 -08001897
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001898void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001899{
Lee Thomason624d43f2012-10-12 10:58:48 -07001900 if ( _errorID ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001901 static const int LEN = 20;
1902 char buf1[LEN] = { 0 };
1903 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001904
Lee Thomason624d43f2012-10-12 10:58:48 -07001905 if ( _errorStr1 ) {
1906 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001907 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001908 if ( _errorStr2 ) {
1909 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001910 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001911
Lee Thomason331596e2014-09-11 14:56:43 -07001912 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
1913 _errorID, ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001914 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001915}
1916
1917
PKEuS1bfb9542013-08-04 13:51:17 +02001918XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001919 _elementJustOpened( false ),
1920 _firstElement( true ),
1921 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001922 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001923 _textDepth( -1 ),
1924 _processEntities( true ),
1925 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001926{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001927 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001928 _entityFlag[i] = false;
1929 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001930 }
1931 for( int i=0; i<NUM_ENTITIES; ++i ) {
1932 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1933 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001934 _entityFlag[ (int)entities[i].value ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001935 }
1936 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001937 _restrictedEntityFlag[(int)'&'] = true;
1938 _restrictedEntityFlag[(int)'<'] = true;
1939 _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
1940 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001941}
1942
1943
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001944void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001945{
1946 va_list va;
1947 va_start( va, format );
1948
Lee Thomason624d43f2012-10-12 10:58:48 -07001949 if ( _fp ) {
1950 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001951 }
1952 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001953#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001954 #if defined(WINCE)
1955 int len = 512;
1956 do {
1957 len = len*2;
1958 char* str = new char[len]();
1959 len = _vsnprintf(str, len, format, va);
1960 delete[] str;
1961 }while (len < 0);
1962 #else
Thomas Roß268c6832014-03-13 23:35:16 +01001963 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08001964 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001965#else
1966 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01001967#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001968 // Close out and re-start the va-args
1969 va_end( va );
1970 va_start( va, format );
Lee Thomasona0744c82014-03-16 10:32:27 -07001971 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
1972#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001973 #if defined(WINCE)
1974 _vsnprintf( p, len+1, format, va );
1975 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07001976 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08001977 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07001978#else
1979 vsnprintf( p, len+1, format, va );
1980#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001981 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001982 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001983}
1984
1985
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001986void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001987{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001988 for( int i=0; i<depth; ++i ) {
1989 Print( " " );
1990 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001991}
1992
1993
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001994void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001995{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001996 // Look for runs of bytes between entities to print.
1997 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001998 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001999
Lee Thomason624d43f2012-10-12 10:58:48 -07002000 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002001 while ( *q ) {
2002 // Remember, char is sometimes signed. (How many times has that bitten me?)
2003 if ( *q > 0 && *q < ENTITY_RANGE ) {
2004 // Check for entities. If one is found, flush
2005 // the stream up until the entity, write the
2006 // entity, and keep looking.
2007 if ( flag[(unsigned)(*q)] ) {
2008 while ( p < q ) {
2009 Print( "%c", *p );
2010 ++p;
2011 }
2012 for( int i=0; i<NUM_ENTITIES; ++i ) {
2013 if ( entities[i].value == *q ) {
2014 Print( "&%s;", entities[i].pattern );
2015 break;
2016 }
2017 }
2018 ++p;
2019 }
2020 }
2021 ++q;
2022 }
2023 }
2024 // Flush the remaining string. This will be the entire
2025 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07002026 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002027 Print( "%s", p );
2028 }
Lee Thomason857b8682012-01-25 17:50:25 -08002029}
2030
U-Stream\Leeae25a442012-02-17 17:48:16 -08002031
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002032void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002033{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002034 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002035 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 -07002036 Print( "%s", bom );
2037 }
2038 if ( writeDec ) {
2039 PushDeclaration( "xml version=\"1.0\"" );
2040 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002041}
2042
2043
Uli Kusterer593a33d2014-02-01 12:48:51 +01002044void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002045{
Lee Thomason624d43f2012-10-12 10:58:48 -07002046 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002047 SealElement();
2048 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002049 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002050
Uli Kusterer593a33d2014-02-01 12:48:51 +01002051 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002052 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002053 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002054 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002055 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002056 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002057
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002058 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002059 _elementJustOpened = true;
2060 _firstElement = false;
2061 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002062}
2063
2064
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002065void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002066{
Lee Thomason624d43f2012-10-12 10:58:48 -07002067 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002068 Print( " %s=\"", name );
2069 PrintString( value, false );
2070 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002071}
2072
2073
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002074void XMLPrinter::PushAttribute( const char* name, int v )
2075{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002076 char buf[BUF_SIZE];
2077 XMLUtil::ToStr( v, buf, BUF_SIZE );
2078 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002079}
2080
2081
2082void XMLPrinter::PushAttribute( const char* name, unsigned v )
2083{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002084 char buf[BUF_SIZE];
2085 XMLUtil::ToStr( v, buf, BUF_SIZE );
2086 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002087}
2088
2089
2090void XMLPrinter::PushAttribute( const char* name, bool v )
2091{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002092 char buf[BUF_SIZE];
2093 XMLUtil::ToStr( v, buf, BUF_SIZE );
2094 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002095}
2096
2097
2098void XMLPrinter::PushAttribute( const char* name, double v )
2099{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002100 char buf[BUF_SIZE];
2101 XMLUtil::ToStr( v, buf, BUF_SIZE );
2102 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002103}
2104
2105
Uli Kustererca412e82014-02-01 13:35:05 +01002106void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002107{
Lee Thomason624d43f2012-10-12 10:58:48 -07002108 --_depth;
2109 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002110
Lee Thomason624d43f2012-10-12 10:58:48 -07002111 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002112 Print( "/>" );
2113 }
2114 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002115 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002116 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002117 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002118 }
2119 Print( "</%s>", name );
2120 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002121
Lee Thomason624d43f2012-10-12 10:58:48 -07002122 if ( _textDepth == _depth ) {
2123 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002124 }
Uli Kustererca412e82014-02-01 13:35:05 +01002125 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002126 Print( "\n" );
2127 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002128 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002129}
2130
2131
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002132void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08002133{
Lee Thomason624d43f2012-10-12 10:58:48 -07002134 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002135 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002136}
2137
2138
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002139void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002140{
Lee Thomason624d43f2012-10-12 10:58:48 -07002141 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002142
Lee Thomason624d43f2012-10-12 10:58:48 -07002143 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002144 SealElement();
2145 }
2146 if ( cdata ) {
2147 Print( "<![CDATA[" );
2148 Print( "%s", text );
2149 Print( "]]>" );
2150 }
2151 else {
2152 PrintString( text, true );
2153 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002154}
2155
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002156void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002157{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002158 char buf[BUF_SIZE];
2159 XMLUtil::ToStr( value, buf, BUF_SIZE );
2160 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002161}
2162
2163
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002164void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002165{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002166 char buf[BUF_SIZE];
2167 XMLUtil::ToStr( value, buf, BUF_SIZE );
2168 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002169}
2170
2171
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002172void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002173{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002174 char buf[BUF_SIZE];
2175 XMLUtil::ToStr( value, buf, BUF_SIZE );
2176 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002177}
2178
2179
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002180void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002181{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002182 char buf[BUF_SIZE];
2183 XMLUtil::ToStr( value, buf, BUF_SIZE );
2184 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002185}
2186
2187
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002188void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002189{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002190 char buf[BUF_SIZE];
2191 XMLUtil::ToStr( value, buf, BUF_SIZE );
2192 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002193}
2194
Lee Thomason5cae8972012-01-24 18:03:07 -08002195
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002196void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002197{
Lee Thomason624d43f2012-10-12 10:58:48 -07002198 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002199 SealElement();
2200 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002201 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002202 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002203 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002204 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002205 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002206 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002207}
Lee Thomason751da522012-02-10 08:50:51 -08002208
2209
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002210void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002211{
Lee Thomason624d43f2012-10-12 10:58:48 -07002212 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002213 SealElement();
2214 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002215 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002216 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002217 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002218 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002219 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002220 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002221}
2222
2223
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002224void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002225{
Lee Thomason624d43f2012-10-12 10:58:48 -07002226 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002227 SealElement();
2228 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002229 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002230 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002231 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002232 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002233 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002234 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002235}
2236
2237
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002238bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002239{
Lee Thomason624d43f2012-10-12 10:58:48 -07002240 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002241 if ( doc.HasBOM() ) {
2242 PushHeader( true, false );
2243 }
2244 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002245}
2246
2247
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002248bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002249{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002250 const XMLElement* parentElem = element.Parent()->ToElement();
2251 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2252 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002253 while ( attribute ) {
2254 PushAttribute( attribute->Name(), attribute->Value() );
2255 attribute = attribute->Next();
2256 }
2257 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002258}
2259
2260
Uli Kustererca412e82014-02-01 13:35:05 +01002261bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002262{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002263 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002264 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002265}
2266
2267
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002268bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002269{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002270 PushText( text.Value(), text.CData() );
2271 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002272}
2273
2274
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002275bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002276{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002277 PushComment( comment.Value() );
2278 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002279}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002280
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002281bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002282{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002283 PushDeclaration( declaration.Value() );
2284 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002285}
2286
2287
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002288bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002289{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002290 PushUnknown( unknown.Value() );
2291 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002292}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002293
Lee Thomason685b8952012-11-12 13:00:06 -08002294} // namespace tinyxml2
2295