blob: 7d7026ee264928570144503c27d53c2daa62e2de [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 }
JayXonee525db2014-12-24 04:01:42 -0500143 if ( !XMLUtil::IsNameStartChar( *p ) ) {
144 return 0;
145 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800146
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400147 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500148 ++p;
149 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700150 ++p;
151 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800152
JayXonee525db2014-12-24 04:01:42 -0500153 Set( start, p, 0 );
154 return p;
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
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300165 if ( *_start ) {
Lee Thomason120b3a62012-10-12 10:06:59 -0700166 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{
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300189 TIXMLASSERT( _start );
190 TIXMLASSERT( _end );
Lee Thomason120b3a62012-10-12 10:06:59 -0700191 if ( _flags & NEEDS_FLUSH ) {
192 *_end = 0;
193 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800194
Lee Thomason120b3a62012-10-12 10:06:59 -0700195 if ( _flags ) {
196 char* p = _start; // the read pointer
197 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800198
Lee Thomason120b3a62012-10-12 10:06:59 -0700199 while( p < _end ) {
200 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700201 // CR-LF pair becomes LF
202 // CR alone becomes LF
203 // LF-CR becomes LF
204 if ( *(p+1) == LF ) {
205 p += 2;
206 }
207 else {
208 ++p;
209 }
210 *q++ = LF;
211 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700212 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700213 if ( *(p+1) == CR ) {
214 p += 2;
215 }
216 else {
217 ++p;
218 }
219 *q++ = LF;
220 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700221 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700222 // Entities handled by tinyXML2:
223 // - special entities in the entity table [in/out]
224 // - numeric character reference [in]
225 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800226
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700227 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400228 const int buflen = 10;
229 char buf[buflen] = { 0 };
230 int len = 0;
Dmitry-Me6f51c802015-03-14 13:25:03 +0300231 char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
232 if ( adjusted == 0 ) {
233 *q = *p;
234 ++p;
235 ++q;
236 }
237 else {
238 TIXMLASSERT( 0 <= len && len <= buflen );
239 TIXMLASSERT( q + len <= adjusted );
240 p = adjusted;
241 memcpy( q, buf, len );
242 q += len;
243 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700244 }
245 else {
Dmitry-Me764545e2015-05-20 10:29:24 +0300246 bool entityFound = false;
247 for( int i = 0; i < NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400248 const Entity& entity = entities[i];
249 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
250 && *( p + entity.length + 1 ) == ';' ) {
251 // Found an entity - convert.
252 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700253 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400254 p += entity.length + 2;
Dmitry-Me764545e2015-05-20 10:29:24 +0300255 entityFound = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700256 break;
257 }
258 }
Dmitry-Me764545e2015-05-20 10:29:24 +0300259 if ( !entityFound ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700260 // fixme: treat as error?
261 ++p;
262 ++q;
263 }
264 }
265 }
266 else {
267 *q = *p;
268 ++p;
269 ++q;
270 }
271 }
272 *q = 0;
273 }
274 // The loop below has plenty going on, and this
275 // is a less useful mode. Break it out.
Dmitry-Me5420e542015-05-20 10:51:26 +0300276 if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700277 CollapseWhitespace();
278 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700279 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700280 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300281 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700282 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800283}
284
Lee Thomason2c85a712012-01-31 08:24:24 -0800285
Lee Thomasone4422302012-01-20 17:59:50 -0800286
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800287
Lee Thomason56bdd022012-02-09 18:16:58 -0800288// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800289
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800290const char* XMLUtil::ReadBOM( const char* p, bool* bom )
291{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300292 TIXMLASSERT( p );
293 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700294 *bom = false;
295 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
296 // Check for BOM:
297 if ( *(pu+0) == TIXML_UTF_LEAD_0
298 && *(pu+1) == TIXML_UTF_LEAD_1
299 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
300 *bom = true;
301 p += 3;
302 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300303 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700304 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800305}
306
307
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800308void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
309{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700310 const unsigned long BYTE_MASK = 0xBF;
311 const unsigned long BYTE_MARK = 0x80;
312 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800313
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700314 if (input < 0x80) {
315 *length = 1;
316 }
317 else if ( input < 0x800 ) {
318 *length = 2;
319 }
320 else if ( input < 0x10000 ) {
321 *length = 3;
322 }
323 else if ( input < 0x200000 ) {
324 *length = 4;
325 }
326 else {
Dmitry-Me2f465c42015-03-16 11:08:23 +0300327 *length = 0; // This code won't convert this correctly anyway.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700328 return;
329 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800330
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700331 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800332
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700333 // Scary scary fall throughs.
334 switch (*length) {
335 case 4:
336 --output;
337 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
338 input >>= 6;
339 case 3:
340 --output;
341 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
342 input >>= 6;
343 case 2:
344 --output;
345 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
346 input >>= 6;
347 case 1:
348 --output;
349 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100350 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300351 default:
352 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700353 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800354}
355
356
357const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
358{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700359 // Presume an entity, and pull it out.
360 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800361
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700362 if ( *(p+1) == '#' && *(p+2) ) {
363 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300364 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700365 ptrdiff_t delta = 0;
366 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800367 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800368
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700369 if ( *(p+2) == 'x' ) {
370 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300371 const char* q = p+3;
372 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700373 return 0;
374 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800375
Lee Thomason7e67bc82015-01-12 14:05:12 -0800376 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800377
Dmitry-Me9f56e122015-01-12 10:07:54 +0300378 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700379 return 0;
380 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800381 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800382
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700383 delta = q-p;
384 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800385
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700386 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700387 unsigned int digit = 0;
388
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700389 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300390 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700391 }
392 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300393 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700394 }
395 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300396 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700397 }
398 else {
399 return 0;
400 }
Dmitry-Me3dc797b2015-03-16 11:06:46 +0300401 TIXMLASSERT( digit >= 0 && digit < 16);
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300402 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
403 const unsigned int digitScaled = mult * digit;
404 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
405 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300406 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700407 mult *= 16;
408 --q;
409 }
410 }
411 else {
412 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300413 const char* q = p+2;
414 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700415 return 0;
416 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800417
Lee Thomason7e67bc82015-01-12 14:05:12 -0800418 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800419
Dmitry-Me9f56e122015-01-12 10:07:54 +0300420 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700421 return 0;
422 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800423 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800424
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700425 delta = q-p;
426 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800427
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700428 while ( *q != '#' ) {
429 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300430 const unsigned int digit = *q - '0';
Dmitry-Me3dc797b2015-03-16 11:06:46 +0300431 TIXMLASSERT( digit >= 0 && digit < 10);
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300432 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
433 const unsigned int digitScaled = mult * digit;
434 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
435 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700436 }
437 else {
438 return 0;
439 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300440 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700441 mult *= 10;
442 --q;
443 }
444 }
445 // convert the UCS to UTF-8
446 ConvertUTF32ToUTF8( ucs, value, length );
447 return p + delta + 1;
448 }
449 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800450}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800451
452
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700453void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700454{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700455 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700456}
457
458
459void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
460{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700461 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700462}
463
464
465void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
466{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700467 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700468}
469
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800470/*
471 ToStr() of a number is a very tricky topic.
472 https://github.com/leethomason/tinyxml2/issues/106
473*/
Lee Thomason21be8822012-07-15 17:27:22 -0700474void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
475{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800476 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700477}
478
479
480void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
481{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800482 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700483}
484
485
486bool XMLUtil::ToInt( const char* str, int* value )
487{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700488 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
489 return true;
490 }
491 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700492}
493
494bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
495{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700496 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
497 return true;
498 }
499 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700500}
501
502bool XMLUtil::ToBool( const char* str, bool* value )
503{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700504 int ival = 0;
505 if ( ToInt( str, &ival )) {
506 *value = (ival==0) ? false : true;
507 return true;
508 }
509 if ( StringEqual( str, "true" ) ) {
510 *value = true;
511 return true;
512 }
513 else if ( StringEqual( str, "false" ) ) {
514 *value = false;
515 return true;
516 }
517 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700518}
519
520
521bool XMLUtil::ToFloat( const char* str, float* value )
522{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700523 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
524 return true;
525 }
526 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700527}
528
529bool XMLUtil::ToDouble( const char* str, double* value )
530{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700531 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
532 return true;
533 }
534 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700535}
536
537
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700538char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800539{
Dmitry-Me02384662015-03-03 16:02:13 +0300540 TIXMLASSERT( node );
541 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400542 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700543 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300544 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300545 *node = 0;
546 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700547 return p;
548 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800549
Dmitry-Me962083b2015-05-26 11:38:30 +0300550 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700551 static const char* xmlHeader = { "<?" };
552 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700553 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300554 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700555 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800556
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700557 static const int xmlHeaderLen = 2;
558 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700559 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300560 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700561 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800562
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700563 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
564 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400565 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700566 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300567 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700568 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
569 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700570 p += xmlHeaderLen;
571 }
572 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300573 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700574 returnNode = new (_commentPool.Alloc()) XMLComment( this );
575 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700576 p += commentHeaderLen;
577 }
578 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300579 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700580 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700581 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700582 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700583 p += cdataHeaderLen;
584 text->SetCData( true );
585 }
586 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300587 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700588 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
589 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700590 p += dtdHeaderLen;
591 }
592 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300593 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700594 returnNode = new (_elementPool.Alloc()) XMLElement( this );
595 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700596 p += elementHeaderLen;
597 }
598 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300599 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700600 returnNode = new (_textPool.Alloc()) XMLText( this );
601 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700602 p = start; // Back it up, all the text counts.
603 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800604
Dmitry-Me02384662015-03-03 16:02:13 +0300605 TIXMLASSERT( returnNode );
606 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700607 *node = returnNode;
608 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800609}
610
611
Lee Thomason751da522012-02-10 08:50:51 -0800612bool XMLDocument::Accept( XMLVisitor* visitor ) const
613{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300614 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700615 if ( visitor->VisitEnter( *this ) ) {
616 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
617 if ( !node->Accept( visitor ) ) {
618 break;
619 }
620 }
621 }
622 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800623}
Lee Thomason56bdd022012-02-09 18:16:58 -0800624
625
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800626// --------- XMLNode ----------- //
627
628XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700629 _document( doc ),
630 _parent( 0 ),
631 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200632 _prev( 0 ), _next( 0 ),
633 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800634{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800635}
636
637
638XMLNode::~XMLNode()
639{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700640 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700641 if ( _parent ) {
642 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700643 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800644}
645
Michael Daumling21626882013-10-22 17:03:37 +0200646const char* XMLNode::Value() const
647{
Lee Thomason85492022015-05-22 11:07:45 -0700648 // Catch an edge case: XMLDocuments don't have a a Value. Carefully return nullptr.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530649 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530650 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200651 return _value.GetStr();
652}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800653
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800654void XMLNode::SetValue( const char* str, bool staticMem )
655{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700656 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700657 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700658 }
659 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700660 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700661 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800662}
663
664
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800665void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800666{
Lee Thomason624d43f2012-10-12 10:58:48 -0700667 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300668 TIXMLASSERT( _lastChild );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300669 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700670 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700671 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700672
Dmitry-Mee3225b12014-09-03 11:03:11 +0400673 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700674 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700675 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800676}
677
678
679void XMLNode::Unlink( XMLNode* child )
680{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300681 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300682 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300683 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700684 if ( child == _firstChild ) {
685 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700686 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700687 if ( child == _lastChild ) {
688 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700689 }
Lee Thomasond923c672012-01-23 08:44:25 -0800690
Lee Thomason624d43f2012-10-12 10:58:48 -0700691 if ( child->_prev ) {
692 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700693 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700694 if ( child->_next ) {
695 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700696 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700697 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800698}
699
700
U-Stream\Leeae25a442012-02-17 17:48:16 -0800701void XMLNode::DeleteChild( XMLNode* node )
702{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300703 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300704 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700705 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400706 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800707}
708
709
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800710XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
711{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300712 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300713 if ( addThis->_document != _document ) {
714 TIXMLASSERT( false );
715 return 0;
716 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800717 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700718
Lee Thomason624d43f2012-10-12 10:58:48 -0700719 if ( _lastChild ) {
720 TIXMLASSERT( _firstChild );
721 TIXMLASSERT( _lastChild->_next == 0 );
722 _lastChild->_next = addThis;
723 addThis->_prev = _lastChild;
724 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800725
Lee Thomason624d43f2012-10-12 10:58:48 -0700726 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700727 }
728 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700729 TIXMLASSERT( _firstChild == 0 );
730 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800731
Lee Thomason624d43f2012-10-12 10:58:48 -0700732 addThis->_prev = 0;
733 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700734 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700735 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700736 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800737}
738
739
Lee Thomason1ff38e02012-02-14 18:18:16 -0800740XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
741{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300742 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300743 if ( addThis->_document != _document ) {
744 TIXMLASSERT( false );
745 return 0;
746 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800747 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700748
Lee Thomason624d43f2012-10-12 10:58:48 -0700749 if ( _firstChild ) {
750 TIXMLASSERT( _lastChild );
751 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800752
Lee Thomason624d43f2012-10-12 10:58:48 -0700753 _firstChild->_prev = addThis;
754 addThis->_next = _firstChild;
755 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800756
Lee Thomason624d43f2012-10-12 10:58:48 -0700757 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700758 }
759 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700760 TIXMLASSERT( _lastChild == 0 );
761 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800762
Lee Thomason624d43f2012-10-12 10:58:48 -0700763 addThis->_prev = 0;
764 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700765 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700766 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400767 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800768}
769
770
771XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
772{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300773 TIXMLASSERT( addThis );
774 if ( addThis->_document != _document ) {
775 TIXMLASSERT( false );
776 return 0;
777 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700778
Dmitry-Meabb2d042014-12-09 12:59:31 +0300779 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700780
Lee Thomason624d43f2012-10-12 10:58:48 -0700781 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300782 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700783 return 0;
784 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800785
Lee Thomason624d43f2012-10-12 10:58:48 -0700786 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700787 // The last node or the only node.
788 return InsertEndChild( addThis );
789 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800790 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700791 addThis->_prev = afterThis;
792 addThis->_next = afterThis->_next;
793 afterThis->_next->_prev = addThis;
794 afterThis->_next = addThis;
795 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700796 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800797}
798
799
800
801
Lee Thomason56bdd022012-02-09 18:16:58 -0800802const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800803{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300804 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
805 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700806 if ( element ) {
807 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
808 return element;
809 }
810 }
811 }
812 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800813}
814
815
Lee Thomason56bdd022012-02-09 18:16:58 -0800816const XMLElement* XMLNode::LastChildElement( const char* value ) const
817{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300818 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
819 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700820 if ( element ) {
821 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
822 return element;
823 }
824 }
825 }
826 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800827}
828
829
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800830const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
831{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300832 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400833 const XMLElement* element = node->ToElement();
834 if ( element
835 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
836 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700837 }
838 }
839 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800840}
841
842
843const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
844{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300845 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400846 const XMLElement* element = node->ToElement();
847 if ( element
848 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
849 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700850 }
851 }
852 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800853}
854
855
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800856char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800857{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700858 // This is a recursive method, but thinking about it "at the current level"
859 // it is a pretty simple flat list:
860 // <foo/>
861 // <!-- comment -->
862 //
863 // With a special case:
864 // <foo>
865 // </foo>
866 // <!-- comment -->
867 //
868 // Where the closing element (/foo) *must* be the next thing after the opening
869 // element, and the names must match. BUT the tricky bit is that the closing
870 // element will be read by the child.
871 //
872 // 'endTag' is the end tag for this node, it is returned by a call to a child.
873 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800874
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700875 while( p && *p ) {
876 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800877
Lee Thomason624d43f2012-10-12 10:58:48 -0700878 p = _document->Identify( p, &node );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300879 if ( node == 0 ) {
880 break;
881 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800882
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700883 StrPair endTag;
884 p = node->ParseDeep( p, &endTag );
885 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400886 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700887 if ( !_document->Error() ) {
888 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700889 }
890 break;
891 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800892
Sarat Addepalli3df007e2015-05-20 10:43:51 +0530893 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530894 if ( decl ) {
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530895 // A declaration can only be the first child of a document.
896 // Set error, if document already has children.
897 if ( !_document->NoChildren() ) {
898 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0);
899 DeleteNode( decl );
900 break;
901 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530902 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530903
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400904 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700905 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -0500906 // We read the end tag. Return it to the parent.
907 if ( ele->ClosingType() == XMLElement::CLOSING ) {
908 if ( parentEnd ) {
909 ele->_value.TransferTo( parentEnd );
910 }
911 node->_memPool->SetTracked(); // created and then immediately deleted.
912 DeleteNode( node );
913 return p;
914 }
915
916 // Handle an end tag returned to this level.
917 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400918 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300919 if ( endTag.Empty() ) {
920 if ( ele->ClosingType() == XMLElement::OPEN ) {
921 mismatch = true;
922 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700923 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300924 else {
925 if ( ele->ClosingType() != XMLElement::OPEN ) {
926 mismatch = true;
927 }
928 else if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400929 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700930 }
931 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400932 if ( mismatch ) {
933 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -0500934 DeleteNode( node );
935 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400936 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700937 }
JayXondbfdd8f2014-12-12 20:07:14 -0500938 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700939 }
940 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800941}
942
Dmitry-Mee3225b12014-09-03 11:03:11 +0400943void XMLNode::DeleteNode( XMLNode* node )
944{
945 if ( node == 0 ) {
946 return;
947 }
948 MemPool* pool = node->_memPool;
949 node->~XMLNode();
950 pool->Free( node );
951}
952
Lee Thomason3cebdc42015-01-05 17:16:28 -0800953void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +0300954{
955 TIXMLASSERT( insertThis );
956 TIXMLASSERT( insertThis->_document == _document );
957
958 if ( insertThis->_parent )
959 insertThis->_parent->Unlink( insertThis );
960 else
961 insertThis->_memPool->SetTracked();
962}
963
Lee Thomason5492a1c2012-01-23 15:32:10 -0800964// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800965char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800966{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700967 const char* start = p;
968 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700969 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700970 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700971 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700972 }
973 return p;
974 }
975 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700976 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
977 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +0300978 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700979 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700980
Lee Thomason624d43f2012-10-12 10:58:48 -0700981 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700982 if ( p && *p ) {
983 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +0300984 }
985 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +0300986 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700987 }
988 }
989 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800990}
991
992
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800993XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
994{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700995 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700996 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700997 }
998 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
999 text->SetCData( this->CData() );
1000 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001001}
1002
1003
1004bool XMLText::ShallowEqual( const XMLNode* compare ) const
1005{
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001006 const XMLText* text = compare->ToText();
1007 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001008}
1009
1010
Lee Thomason56bdd022012-02-09 18:16:58 -08001011bool XMLText::Accept( XMLVisitor* visitor ) const
1012{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001013 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001014 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001015}
1016
1017
Lee Thomason3f57d272012-01-11 15:30:03 -08001018// --------- XMLComment ---------- //
1019
Lee Thomasone4422302012-01-20 17:59:50 -08001020XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001021{
1022}
1023
1024
Lee Thomasonce0763e2012-01-11 15:43:54 -08001025XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001026{
Lee Thomason3f57d272012-01-11 15:30:03 -08001027}
1028
1029
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001030char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -08001031{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001032 // Comment parses as text.
1033 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001034 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001035 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001036 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001037 }
1038 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001039}
1040
1041
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001042XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1043{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001044 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001045 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001046 }
1047 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1048 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001049}
1050
1051
1052bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1053{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001054 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001055 const XMLComment* comment = compare->ToComment();
1056 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001057}
1058
1059
Lee Thomason751da522012-02-10 08:50:51 -08001060bool XMLComment::Accept( XMLVisitor* visitor ) const
1061{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001062 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001063 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001064}
Lee Thomason56bdd022012-02-09 18:16:58 -08001065
1066
Lee Thomason50f97b22012-02-11 16:33:40 -08001067// --------- XMLDeclaration ---------- //
1068
1069XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1070{
1071}
1072
1073
1074XMLDeclaration::~XMLDeclaration()
1075{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001076 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001077}
1078
1079
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001080char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001081{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001082 // Declaration parses as text.
1083 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001084 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001085 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001086 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001087 }
1088 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001089}
1090
1091
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001092XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1093{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001094 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001095 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001096 }
1097 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1098 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001099}
1100
1101
1102bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1103{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001104 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001105 const XMLDeclaration* declaration = compare->ToDeclaration();
1106 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001107}
1108
1109
1110
Lee Thomason50f97b22012-02-11 16:33:40 -08001111bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1112{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001113 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001114 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001115}
1116
1117// --------- XMLUnknown ---------- //
1118
1119XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1120{
1121}
1122
1123
1124XMLUnknown::~XMLUnknown()
1125{
1126}
1127
1128
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001129char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001130{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001131 // Unknown parses as text.
1132 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001133
Lee Thomason624d43f2012-10-12 10:58:48 -07001134 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001135 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001136 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001137 }
1138 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001139}
1140
1141
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001142XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1143{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001144 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001145 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001146 }
1147 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1148 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001149}
1150
1151
1152bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1153{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001154 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001155 const XMLUnknown* unknown = compare->ToUnknown();
1156 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001157}
1158
1159
Lee Thomason50f97b22012-02-11 16:33:40 -08001160bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1161{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001162 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001163 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001164}
1165
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001166// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001167
1168const char* XMLAttribute::Name() const
1169{
1170 return _name.GetStr();
1171}
1172
1173const char* XMLAttribute::Value() const
1174{
1175 return _value.GetStr();
1176}
1177
Lee Thomason6f381b72012-03-02 12:59:39 -08001178char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001179{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001180 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001181 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001182 if ( !p || !*p ) {
1183 return 0;
1184 }
Lee Thomason22aead12012-01-23 13:29:35 -08001185
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001186 // Skip white space before =
1187 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001188 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001189 return 0;
1190 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001191
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001192 ++p; // move up to opening quote
1193 p = XMLUtil::SkipWhiteSpace( p );
1194 if ( *p != '\"' && *p != '\'' ) {
1195 return 0;
1196 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001197
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001198 char endTag[2] = { *p, 0 };
1199 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001200
Lee Thomason624d43f2012-10-12 10:58:48 -07001201 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001202 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001203}
1204
1205
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001206void XMLAttribute::SetName( const char* n )
1207{
Lee Thomason624d43f2012-10-12 10:58:48 -07001208 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001209}
1210
1211
Lee Thomason2fa81722012-11-09 12:37:46 -08001212XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001213{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001214 if ( XMLUtil::ToInt( Value(), value )) {
1215 return XML_NO_ERROR;
1216 }
1217 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001218}
1219
1220
Lee Thomason2fa81722012-11-09 12:37:46 -08001221XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001222{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001223 if ( XMLUtil::ToUnsigned( Value(), value )) {
1224 return XML_NO_ERROR;
1225 }
1226 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001227}
1228
1229
Lee Thomason2fa81722012-11-09 12:37:46 -08001230XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001231{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001232 if ( XMLUtil::ToBool( Value(), value )) {
1233 return XML_NO_ERROR;
1234 }
1235 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001236}
1237
1238
Lee Thomason2fa81722012-11-09 12:37:46 -08001239XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001240{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001241 if ( XMLUtil::ToFloat( Value(), value )) {
1242 return XML_NO_ERROR;
1243 }
1244 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001245}
1246
1247
Lee Thomason2fa81722012-11-09 12:37:46 -08001248XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001249{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001250 if ( XMLUtil::ToDouble( Value(), value )) {
1251 return XML_NO_ERROR;
1252 }
1253 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001254}
1255
1256
1257void XMLAttribute::SetAttribute( const char* v )
1258{
Lee Thomason624d43f2012-10-12 10:58:48 -07001259 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001260}
1261
1262
Lee Thomason1ff38e02012-02-14 18:18:16 -08001263void XMLAttribute::SetAttribute( int v )
1264{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001265 char buf[BUF_SIZE];
1266 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001267 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001268}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001269
1270
1271void XMLAttribute::SetAttribute( unsigned v )
1272{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001273 char buf[BUF_SIZE];
1274 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001275 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001276}
1277
1278
1279void XMLAttribute::SetAttribute( bool v )
1280{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001281 char buf[BUF_SIZE];
1282 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001283 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001284}
1285
1286void XMLAttribute::SetAttribute( double v )
1287{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001288 char buf[BUF_SIZE];
1289 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001290 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001291}
1292
1293void XMLAttribute::SetAttribute( float v )
1294{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001295 char buf[BUF_SIZE];
1296 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001297 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001298}
1299
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001300
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001301// --------- XMLElement ---------- //
1302XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001303 _closingType( 0 ),
1304 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001305{
1306}
1307
1308
1309XMLElement::~XMLElement()
1310{
Lee Thomason624d43f2012-10-12 10:58:48 -07001311 while( _rootAttribute ) {
1312 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001313 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001314 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001315 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001316}
1317
1318
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001319const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1320{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001321 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001322 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1323 return a;
1324 }
1325 }
1326 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001327}
1328
1329
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001330const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001331{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001332 const XMLAttribute* a = FindAttribute( name );
1333 if ( !a ) {
1334 return 0;
1335 }
1336 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1337 return a->Value();
1338 }
1339 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001340}
1341
1342
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001343const char* XMLElement::GetText() const
1344{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001345 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001346 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001347 }
1348 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001349}
1350
1351
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001352void XMLElement::SetText( const char* inText )
1353{
Uli Kusterer869bb592014-01-21 01:36:16 +01001354 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001355 FirstChild()->SetValue( inText );
1356 else {
1357 XMLText* theText = GetDocument()->NewText( inText );
1358 InsertFirstChild( theText );
1359 }
1360}
1361
Lee Thomason5bb2d802014-01-24 10:42:57 -08001362
1363void XMLElement::SetText( int v )
1364{
1365 char buf[BUF_SIZE];
1366 XMLUtil::ToStr( v, buf, BUF_SIZE );
1367 SetText( buf );
1368}
1369
1370
1371void XMLElement::SetText( unsigned v )
1372{
1373 char buf[BUF_SIZE];
1374 XMLUtil::ToStr( v, buf, BUF_SIZE );
1375 SetText( buf );
1376}
1377
1378
1379void XMLElement::SetText( bool v )
1380{
1381 char buf[BUF_SIZE];
1382 XMLUtil::ToStr( v, buf, BUF_SIZE );
1383 SetText( buf );
1384}
1385
1386
1387void XMLElement::SetText( float v )
1388{
1389 char buf[BUF_SIZE];
1390 XMLUtil::ToStr( v, buf, BUF_SIZE );
1391 SetText( buf );
1392}
1393
1394
1395void XMLElement::SetText( double v )
1396{
1397 char buf[BUF_SIZE];
1398 XMLUtil::ToStr( v, buf, BUF_SIZE );
1399 SetText( buf );
1400}
1401
1402
MortenMacFly4ee49f12013-01-14 20:03:14 +01001403XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001404{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001405 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001406 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001407 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001408 return XML_SUCCESS;
1409 }
1410 return XML_CAN_NOT_CONVERT_TEXT;
1411 }
1412 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001413}
1414
1415
MortenMacFly4ee49f12013-01-14 20:03:14 +01001416XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001417{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001418 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001419 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001420 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001421 return XML_SUCCESS;
1422 }
1423 return XML_CAN_NOT_CONVERT_TEXT;
1424 }
1425 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001426}
1427
1428
MortenMacFly4ee49f12013-01-14 20:03:14 +01001429XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001430{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001431 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001432 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001433 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001434 return XML_SUCCESS;
1435 }
1436 return XML_CAN_NOT_CONVERT_TEXT;
1437 }
1438 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001439}
1440
1441
MortenMacFly4ee49f12013-01-14 20:03:14 +01001442XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001443{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001444 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001445 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001446 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001447 return XML_SUCCESS;
1448 }
1449 return XML_CAN_NOT_CONVERT_TEXT;
1450 }
1451 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001452}
1453
1454
MortenMacFly4ee49f12013-01-14 20:03:14 +01001455XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001456{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001457 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001458 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001459 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001460 return XML_SUCCESS;
1461 }
1462 return XML_CAN_NOT_CONVERT_TEXT;
1463 }
1464 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001465}
1466
1467
1468
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001469XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1470{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001471 XMLAttribute* last = 0;
1472 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001473 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001474 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001475 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001476 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1477 break;
1478 }
1479 }
1480 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001481 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001482 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1483 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001484 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001485 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001486 }
1487 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001488 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001489 }
1490 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001491 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001492 }
1493 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001494}
1495
1496
U-Stream\Leeae25a442012-02-17 17:48:16 -08001497void XMLElement::DeleteAttribute( const char* name )
1498{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001499 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001500 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001501 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1502 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001503 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001504 }
1505 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001506 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001507 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001508 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001509 break;
1510 }
1511 prev = a;
1512 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001513}
1514
1515
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001516char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001517{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001518 const char* start = p;
1519 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001520
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001521 // Read the attributes.
1522 while( p ) {
1523 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001524 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001525 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001526 return 0;
1527 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001528
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001529 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001530 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001531 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001532 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1533 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001534 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001535
Lee Thomason624d43f2012-10-12 10:58:48 -07001536 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001537 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001538 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001539 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001540 return 0;
1541 }
1542 // There is a minor bug here: if the attribute in the source xml
1543 // document is duplicated, it will not be detected and the
1544 // attribute will be doubly added. However, tracking the 'prevAttribute'
1545 // avoids re-scanning the attribute list. Preferring performance for
1546 // now, may reconsider in the future.
1547 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001548 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001549 }
1550 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001551 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001552 }
1553 prevAttribute = attrib;
1554 }
1555 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001556 else if ( *p == '>' ) {
1557 ++p;
1558 break;
1559 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001560 // end of the tag
1561 else if ( *p == '/' && *(p+1) == '>' ) {
1562 _closingType = CLOSED;
1563 return p+2; // done; sealed element.
1564 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001565 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001566 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001567 return 0;
1568 }
1569 }
1570 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001571}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001572
Dmitry-Mee3225b12014-09-03 11:03:11 +04001573void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1574{
1575 if ( attribute == 0 ) {
1576 return;
1577 }
1578 MemPool* pool = attribute->_memPool;
1579 attribute->~XMLAttribute();
1580 pool->Free( attribute );
1581}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001582
Lee Thomason67d61312012-01-24 16:01:51 -08001583//
1584// <ele></ele>
1585// <ele>foo<b>bar</b></ele>
1586//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001587char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001588{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001589 // Read the element name.
1590 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001591
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001592 // The closing element is the </element> form. It is
1593 // parsed just like a regular element then deleted from
1594 // the DOM.
1595 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001596 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001597 ++p;
1598 }
Lee Thomason67d61312012-01-24 16:01:51 -08001599
Lee Thomason624d43f2012-10-12 10:58:48 -07001600 p = _value.ParseName( p );
1601 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001602 return 0;
1603 }
Lee Thomason67d61312012-01-24 16:01:51 -08001604
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001605 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001606 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001607 return p;
1608 }
Lee Thomason67d61312012-01-24 16:01:51 -08001609
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001610 p = XMLNode::ParseDeep( p, strPair );
1611 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001612}
1613
1614
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001615
1616XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1617{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001618 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001619 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001620 }
1621 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1622 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1623 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1624 }
1625 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001626}
1627
1628
1629bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1630{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001631 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001632 const XMLElement* other = compare->ToElement();
1633 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001634
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001635 const XMLAttribute* a=FirstAttribute();
1636 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001637
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001638 while ( a && b ) {
1639 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1640 return false;
1641 }
1642 a = a->Next();
1643 b = b->Next();
1644 }
1645 if ( a || b ) {
1646 // different count
1647 return false;
1648 }
1649 return true;
1650 }
1651 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001652}
1653
1654
Lee Thomason751da522012-02-10 08:50:51 -08001655bool XMLElement::Accept( XMLVisitor* visitor ) const
1656{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001657 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001658 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001659 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1660 if ( !node->Accept( visitor ) ) {
1661 break;
1662 }
1663 }
1664 }
1665 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001666}
Lee Thomason56bdd022012-02-09 18:16:58 -08001667
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001668
Lee Thomason3f57d272012-01-11 15:30:03 -08001669// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001670
1671// Warning: List must match 'enum XMLError'
1672const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1673 "XML_SUCCESS",
1674 "XML_NO_ATTRIBUTE",
1675 "XML_WRONG_ATTRIBUTE_TYPE",
1676 "XML_ERROR_FILE_NOT_FOUND",
1677 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1678 "XML_ERROR_FILE_READ_ERROR",
1679 "XML_ERROR_ELEMENT_MISMATCH",
1680 "XML_ERROR_PARSING_ELEMENT",
1681 "XML_ERROR_PARSING_ATTRIBUTE",
1682 "XML_ERROR_IDENTIFYING_TAG",
1683 "XML_ERROR_PARSING_TEXT",
1684 "XML_ERROR_PARSING_CDATA",
1685 "XML_ERROR_PARSING_COMMENT",
1686 "XML_ERROR_PARSING_DECLARATION",
1687 "XML_ERROR_PARSING_UNKNOWN",
1688 "XML_ERROR_EMPTY_DOCUMENT",
1689 "XML_ERROR_MISMATCHED_ELEMENT",
1690 "XML_ERROR_PARSING",
1691 "XML_CAN_NOT_CONVERT_TEXT",
1692 "XML_NO_TEXT_NODE"
1693};
1694
1695
Lee Thomason624d43f2012-10-12 10:58:48 -07001696XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001697 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001698 _writeBOM( false ),
1699 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001700 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001701 _whitespace( whitespace ),
1702 _errorStr1( 0 ),
1703 _errorStr2( 0 ),
1704 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001705{
Lee Thomason624d43f2012-10-12 10:58:48 -07001706 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001707}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001708
1709
Lee Thomason3f57d272012-01-11 15:30:03 -08001710XMLDocument::~XMLDocument()
1711{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001712 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001713}
1714
1715
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001716void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001717{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001718 DeleteChildren();
1719
Dmitry-Meab37df82014-11-28 12:08:36 +03001720#ifdef DEBUG
1721 const bool hadError = Error();
1722#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001723 _errorID = XML_NO_ERROR;
1724 _errorStr1 = 0;
1725 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001726
Lee Thomason624d43f2012-10-12 10:58:48 -07001727 delete [] _charBuffer;
1728 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001729
1730#if 0
1731 _textPool.Trace( "text" );
1732 _elementPool.Trace( "element" );
1733 _commentPool.Trace( "comment" );
1734 _attributePool.Trace( "attribute" );
1735#endif
1736
1737#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001738 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001739 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1740 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1741 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1742 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1743 }
1744#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001745}
1746
Lee Thomason3f57d272012-01-11 15:30:03 -08001747
Lee Thomason2c85a712012-01-31 08:24:24 -08001748XMLElement* XMLDocument::NewElement( const char* name )
1749{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001750 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001751 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1752 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001753 ele->SetName( name );
1754 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001755}
1756
1757
Lee Thomason1ff38e02012-02-14 18:18:16 -08001758XMLComment* XMLDocument::NewComment( const char* str )
1759{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001760 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001761 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1762 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001763 comment->SetValue( str );
1764 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001765}
1766
1767
1768XMLText* XMLDocument::NewText( const char* str )
1769{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001770 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001771 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1772 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001773 text->SetValue( str );
1774 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001775}
1776
1777
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001778XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1779{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001780 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001781 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1782 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001783 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1784 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001785}
1786
1787
1788XMLUnknown* XMLDocument::NewUnknown( const char* str )
1789{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001790 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001791 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1792 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001793 unk->SetValue( str );
1794 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001795}
1796
Dmitry-Me01578db2014-08-19 10:18:48 +04001797static FILE* callfopen( const char* filepath, const char* mode )
1798{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001799 TIXMLASSERT( filepath );
1800 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001801#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1802 FILE* fp = 0;
1803 errno_t err = fopen_s( &fp, filepath, mode );
1804 if ( err ) {
1805 return 0;
1806 }
1807#else
1808 FILE* fp = fopen( filepath, mode );
1809#endif
1810 return fp;
1811}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001812
1813void XMLDocument::DeleteNode( XMLNode* node ) {
1814 TIXMLASSERT( node );
1815 TIXMLASSERT(node->_document == this );
1816 if (node->_parent) {
1817 node->_parent->DeleteChild( node );
1818 }
1819 else {
1820 // Isn't in the tree.
1821 // Use the parent delete.
1822 // Also, we need to mark it tracked: we 'know'
1823 // it was never used.
1824 node->_memPool->SetTracked();
1825 // Call the static XMLNode version:
1826 XMLNode::DeleteNode(node);
1827 }
1828}
1829
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001830
Lee Thomason2fa81722012-11-09 12:37:46 -08001831XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001832{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001833 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001834 FILE* fp = callfopen( filename, "rb" );
1835 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001836 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001837 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001838 }
1839 LoadFile( fp );
1840 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001841 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001842}
1843
1844
Lee Thomason2fa81722012-11-09 12:37:46 -08001845XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001846{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001847 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001848
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001849 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001850 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001851 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1852 return _errorID;
1853 }
1854
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001855 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001856 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001857 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001858 if ( filelength == -1L ) {
1859 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1860 return _errorID;
1861 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001862
Dmitry-Meca86a0f2015-05-25 11:29:14 +03001863 if ( (unsigned long)filelength >= (size_t)-1 ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03001864 // Cannot handle files which won't fit in buffer together with null terminator
1865 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1866 return _errorID;
1867 }
1868
Dmitry-Me72801b82015-05-07 09:41:39 +03001869 if ( filelength == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001870 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001871 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001872 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001873
Dmitry-Me72801b82015-05-07 09:41:39 +03001874 const size_t size = filelength;
Lee Thomason624d43f2012-10-12 10:58:48 -07001875 _charBuffer = new char[size+1];
1876 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001877 if ( read != size ) {
1878 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001879 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001880 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001881
Lee Thomason624d43f2012-10-12 10:58:48 -07001882 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001883
Dmitry-Me97476b72015-01-01 16:15:57 +03001884 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07001885 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001886}
1887
1888
Lee Thomason2fa81722012-11-09 12:37:46 -08001889XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001890{
Dmitry-Me01578db2014-08-19 10:18:48 +04001891 FILE* fp = callfopen( filename, "w" );
1892 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001893 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001894 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001895 }
1896 SaveFile(fp, compact);
1897 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001898 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001899}
1900
1901
Lee Thomason2fa81722012-11-09 12:37:46 -08001902XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001903{
Ant Mitchell189198f2015-03-24 16:20:36 +00001904 // Clear any error from the last save, otherwise it will get reported
1905 // for *this* call.
1906 SetError( XML_NO_ERROR, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001907 XMLPrinter stream( fp, compact );
1908 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001909 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001910}
1911
Lee Thomason1ff38e02012-02-14 18:18:16 -08001912
Lee Thomason2fa81722012-11-09 12:37:46 -08001913XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001914{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001915 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001916
Lee Thomason82d32002014-02-21 22:47:18 -08001917 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001918 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001919 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001920 }
1921 if ( len == (size_t)(-1) ) {
1922 len = strlen( p );
1923 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001924 _charBuffer = new char[ len+1 ];
1925 memcpy( _charBuffer, p, len );
1926 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001927
Dmitry-Me97476b72015-01-01 16:15:57 +03001928 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001929 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001930 // clean up now essentially dangling memory.
1931 // and the parse fail can put objects in the
1932 // pools that are dead and inaccessible.
1933 DeleteChildren();
1934 _elementPool.Clear();
1935 _attributePool.Clear();
1936 _textPool.Clear();
1937 _commentPool.Clear();
1938 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001939 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001940}
1941
1942
PKEuS1c5f99e2013-07-06 11:28:39 +02001943void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001944{
Dmitry-Me67c429e2015-05-08 18:08:18 +03001945 if ( streamer ) {
1946 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001947 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03001948 else {
1949 XMLPrinter stdoutStreamer( stdout );
1950 Accept( &stdoutStreamer );
1951 }
Lee Thomason3f57d272012-01-11 15:30:03 -08001952}
1953
1954
Lee Thomason2fa81722012-11-09 12:37:46 -08001955void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001956{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001957 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07001958 _errorID = error;
1959 _errorStr1 = str1;
1960 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001961}
1962
Lee Thomason331596e2014-09-11 14:56:43 -07001963const char* XMLDocument::ErrorName() const
1964{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001965 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001966 const char* errorName = _errorNames[_errorID];
1967 TIXMLASSERT( errorName && errorName[0] );
1968 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07001969}
Lee Thomason5cae8972012-01-24 18:03:07 -08001970
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001971void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001972{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001973 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001974 static const int LEN = 20;
1975 char buf1[LEN] = { 0 };
1976 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001977
Lee Thomason624d43f2012-10-12 10:58:48 -07001978 if ( _errorStr1 ) {
1979 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001980 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001981 if ( _errorStr2 ) {
1982 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001983 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001984
Dmitry-Me2ad43202015-04-16 12:18:58 +03001985 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
1986 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
1987 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
Lee Thomason331596e2014-09-11 14:56:43 -07001988 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
Dmitry-Me400f1192015-04-07 11:51:21 +03001989 static_cast<int>( _errorID ), ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001990 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001991}
1992
Dmitry-Me97476b72015-01-01 16:15:57 +03001993void XMLDocument::Parse()
1994{
1995 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
1996 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08001997 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03001998 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03001999 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002000 if ( !*p ) {
2001 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2002 return;
2003 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08002004 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002005}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002006
PKEuS1bfb9542013-08-04 13:51:17 +02002007XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002008 _elementJustOpened( false ),
2009 _firstElement( true ),
2010 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002011 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002012 _textDepth( -1 ),
2013 _processEntities( true ),
2014 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002015{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002016 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002017 _entityFlag[i] = false;
2018 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002019 }
2020 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002021 const char entityValue = entities[i].value;
2022 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
2023 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002024 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002025 _restrictedEntityFlag[(unsigned char)'&'] = true;
2026 _restrictedEntityFlag[(unsigned char)'<'] = true;
2027 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002028 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002029}
2030
2031
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002032void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002033{
2034 va_list va;
2035 va_start( va, format );
2036
Lee Thomason624d43f2012-10-12 10:58:48 -07002037 if ( _fp ) {
2038 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002039 }
2040 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07002041#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08002042 #if defined(WINCE)
2043 int len = 512;
2044 do {
2045 len = len*2;
2046 char* str = new char[len]();
2047 len = _vsnprintf(str, len, format, va);
2048 delete[] str;
2049 }while (len < 0);
2050 #else
Thomas Roß268c6832014-03-13 23:35:16 +01002051 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08002052 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002053#else
2054 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01002055#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002056 // Close out and re-start the va-args
2057 va_end( va );
2058 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002059 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002060 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
2061#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08002062 #if defined(WINCE)
2063 _vsnprintf( p, len+1, format, va );
2064 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07002065 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08002066 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07002067#else
2068 vsnprintf( p, len+1, format, va );
2069#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002070 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002071 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002072}
2073
2074
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002075void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002076{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002077 for( int i=0; i<depth; ++i ) {
2078 Print( " " );
2079 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002080}
2081
2082
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002083void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002084{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002085 // Look for runs of bytes between entities to print.
2086 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002087
Lee Thomason624d43f2012-10-12 10:58:48 -07002088 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002089 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002090 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002091 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002092 // Remember, char is sometimes signed. (How many times has that bitten me?)
2093 if ( *q > 0 && *q < ENTITY_RANGE ) {
2094 // Check for entities. If one is found, flush
2095 // the stream up until the entity, write the
2096 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002097 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002098 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002099 const size_t delta = q - p;
2100 // %.*s accepts type int as "precision"
2101 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : delta;
2102 Print( "%.*s", toPrint, p );
2103 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002104 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002105 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002106 for( int i=0; i<NUM_ENTITIES; ++i ) {
2107 if ( entities[i].value == *q ) {
2108 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002109 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002110 break;
2111 }
2112 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002113 if ( !entityPatternPrinted ) {
2114 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2115 TIXMLASSERT( false );
2116 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002117 ++p;
2118 }
2119 }
2120 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002121 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002122 }
2123 }
2124 // Flush the remaining string. This will be the entire
2125 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002126 TIXMLASSERT( p <= q );
2127 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002128 Print( "%s", p );
2129 }
Lee Thomason857b8682012-01-25 17:50:25 -08002130}
2131
U-Stream\Leeae25a442012-02-17 17:48:16 -08002132
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002133void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002134{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002135 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002136 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 -07002137 Print( "%s", bom );
2138 }
2139 if ( writeDec ) {
2140 PushDeclaration( "xml version=\"1.0\"" );
2141 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002142}
2143
2144
Uli Kusterer593a33d2014-02-01 12:48:51 +01002145void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002146{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002147 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002148 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002149
Uli Kusterer593a33d2014-02-01 12:48:51 +01002150 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002151 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002152 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002153 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002154 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002155 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002156
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002157 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002158 _elementJustOpened = true;
2159 _firstElement = false;
2160 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002161}
2162
2163
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002164void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002165{
Lee Thomason624d43f2012-10-12 10:58:48 -07002166 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002167 Print( " %s=\"", name );
2168 PrintString( value, false );
2169 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002170}
2171
2172
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002173void XMLPrinter::PushAttribute( const char* name, int v )
2174{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002175 char buf[BUF_SIZE];
2176 XMLUtil::ToStr( v, buf, BUF_SIZE );
2177 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002178}
2179
2180
2181void XMLPrinter::PushAttribute( const char* name, unsigned v )
2182{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002183 char buf[BUF_SIZE];
2184 XMLUtil::ToStr( v, buf, BUF_SIZE );
2185 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002186}
2187
2188
2189void XMLPrinter::PushAttribute( const char* name, bool v )
2190{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002191 char buf[BUF_SIZE];
2192 XMLUtil::ToStr( v, buf, BUF_SIZE );
2193 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002194}
2195
2196
2197void XMLPrinter::PushAttribute( const char* name, double v )
2198{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002199 char buf[BUF_SIZE];
2200 XMLUtil::ToStr( v, buf, BUF_SIZE );
2201 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002202}
2203
2204
Uli Kustererca412e82014-02-01 13:35:05 +01002205void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002206{
Lee Thomason624d43f2012-10-12 10:58:48 -07002207 --_depth;
2208 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002209
Lee Thomason624d43f2012-10-12 10:58:48 -07002210 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002211 Print( "/>" );
2212 }
2213 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002214 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002215 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002216 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002217 }
2218 Print( "</%s>", name );
2219 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002220
Lee Thomason624d43f2012-10-12 10:58:48 -07002221 if ( _textDepth == _depth ) {
2222 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002223 }
Uli Kustererca412e82014-02-01 13:35:05 +01002224 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002225 Print( "\n" );
2226 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002227 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002228}
2229
2230
Dmitry-Mea092bc12014-12-23 17:57:05 +03002231void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002232{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002233 if ( !_elementJustOpened ) {
2234 return;
2235 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002236 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002237 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002238}
2239
2240
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002241void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002242{
Lee Thomason624d43f2012-10-12 10:58:48 -07002243 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002244
Dmitry-Mea092bc12014-12-23 17:57:05 +03002245 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002246 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002247 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002248 }
2249 else {
2250 PrintString( text, true );
2251 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002252}
2253
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002254void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002255{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002256 char buf[BUF_SIZE];
2257 XMLUtil::ToStr( value, buf, BUF_SIZE );
2258 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002259}
2260
2261
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002262void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002263{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002264 char buf[BUF_SIZE];
2265 XMLUtil::ToStr( value, buf, BUF_SIZE );
2266 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002267}
2268
2269
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002270void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002271{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002272 char buf[BUF_SIZE];
2273 XMLUtil::ToStr( value, buf, BUF_SIZE );
2274 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002275}
2276
2277
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002278void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002279{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002280 char buf[BUF_SIZE];
2281 XMLUtil::ToStr( value, buf, BUF_SIZE );
2282 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002283}
2284
2285
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002286void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002287{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002288 char buf[BUF_SIZE];
2289 XMLUtil::ToStr( value, buf, BUF_SIZE );
2290 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002291}
2292
Lee Thomason5cae8972012-01-24 18:03:07 -08002293
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002294void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002295{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002296 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002297 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002298 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002299 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002300 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002301 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002302 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002303}
Lee Thomason751da522012-02-10 08:50:51 -08002304
2305
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002306void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002307{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002308 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002309 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002310 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002311 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002312 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002313 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002314 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002315}
2316
2317
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002318void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002319{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002320 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002321 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002322 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002323 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002324 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002325 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002326 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002327}
2328
2329
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002330bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002331{
Lee Thomason624d43f2012-10-12 10:58:48 -07002332 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002333 if ( doc.HasBOM() ) {
2334 PushHeader( true, false );
2335 }
2336 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002337}
2338
2339
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002340bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002341{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002342 const XMLElement* parentElem = 0;
2343 if ( element.Parent() ) {
2344 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002345 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002346 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002347 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002348 while ( attribute ) {
2349 PushAttribute( attribute->Name(), attribute->Value() );
2350 attribute = attribute->Next();
2351 }
2352 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002353}
2354
2355
Uli Kustererca412e82014-02-01 13:35:05 +01002356bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002357{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002358 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002359 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002360}
2361
2362
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002363bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002364{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002365 PushText( text.Value(), text.CData() );
2366 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002367}
2368
2369
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002370bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002371{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002372 PushComment( comment.Value() );
2373 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002374}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002375
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002376bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002377{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002378 PushDeclaration( declaration.Value() );
2379 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002380}
2381
2382
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002383bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002384{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002385 PushUnknown( unknown.Value() );
2386 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002387}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002388
Lee Thomason685b8952012-11-12 13:00:06 -08002389} // namespace tinyxml2
2390