blob: 2c07897942d916ef97e192d90aaf24488b4fe6bc [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
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700550 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800551 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700552 static const char* xmlHeader = { "<?" };
553 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700554 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300555 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700556 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800557
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700558 static const int xmlHeaderLen = 2;
559 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700560 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300561 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700562 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800563
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700564 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
565 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400566 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700567 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300568 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700569 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
570 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700571 p += xmlHeaderLen;
572 }
573 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300574 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700575 returnNode = new (_commentPool.Alloc()) XMLComment( this );
576 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700577 p += commentHeaderLen;
578 }
579 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300580 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700581 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700582 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700583 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700584 p += cdataHeaderLen;
585 text->SetCData( true );
586 }
587 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300588 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700589 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
590 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700591 p += dtdHeaderLen;
592 }
593 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300594 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700595 returnNode = new (_elementPool.Alloc()) XMLElement( this );
596 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700597 p += elementHeaderLen;
598 }
599 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300600 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700601 returnNode = new (_textPool.Alloc()) XMLText( this );
602 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700603 p = start; // Back it up, all the text counts.
604 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800605
Dmitry-Me02384662015-03-03 16:02:13 +0300606 TIXMLASSERT( returnNode );
607 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700608 *node = returnNode;
609 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800610}
611
612
Lee Thomason751da522012-02-10 08:50:51 -0800613bool XMLDocument::Accept( XMLVisitor* visitor ) const
614{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300615 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700616 if ( visitor->VisitEnter( *this ) ) {
617 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
618 if ( !node->Accept( visitor ) ) {
619 break;
620 }
621 }
622 }
623 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800624}
Lee Thomason56bdd022012-02-09 18:16:58 -0800625
626
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800627// --------- XMLNode ----------- //
628
629XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700630 _document( doc ),
631 _parent( 0 ),
632 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200633 _prev( 0 ), _next( 0 ),
634 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800635{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800636}
637
638
639XMLNode::~XMLNode()
640{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700641 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700642 if ( _parent ) {
643 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700644 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800645}
646
Michael Daumling21626882013-10-22 17:03:37 +0200647const char* XMLNode::Value() const
648{
Lee Thomason85492022015-05-22 11:07:45 -0700649 // Catch an edge case: XMLDocuments don't have a a Value. Carefully return nullptr.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530650 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530651 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200652 return _value.GetStr();
653}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800654
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800655void XMLNode::SetValue( const char* str, bool staticMem )
656{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700657 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700658 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700659 }
660 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700661 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700662 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800663}
664
665
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800666void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800667{
Lee Thomason624d43f2012-10-12 10:58:48 -0700668 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300669 TIXMLASSERT( _lastChild );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300670 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700671 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700672 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700673
Dmitry-Mee3225b12014-09-03 11:03:11 +0400674 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700675 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700676 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800677}
678
679
680void XMLNode::Unlink( XMLNode* child )
681{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300682 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300683 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300684 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700685 if ( child == _firstChild ) {
686 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700687 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700688 if ( child == _lastChild ) {
689 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700690 }
Lee Thomasond923c672012-01-23 08:44:25 -0800691
Lee Thomason624d43f2012-10-12 10:58:48 -0700692 if ( child->_prev ) {
693 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700694 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700695 if ( child->_next ) {
696 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700697 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700698 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800699}
700
701
U-Stream\Leeae25a442012-02-17 17:48:16 -0800702void XMLNode::DeleteChild( XMLNode* node )
703{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300704 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300705 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700706 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400707 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800708}
709
710
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800711XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
712{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300713 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300714 if ( addThis->_document != _document ) {
715 TIXMLASSERT( false );
716 return 0;
717 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800718 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700719
Lee Thomason624d43f2012-10-12 10:58:48 -0700720 if ( _lastChild ) {
721 TIXMLASSERT( _firstChild );
722 TIXMLASSERT( _lastChild->_next == 0 );
723 _lastChild->_next = addThis;
724 addThis->_prev = _lastChild;
725 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800726
Lee Thomason624d43f2012-10-12 10:58:48 -0700727 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700728 }
729 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700730 TIXMLASSERT( _firstChild == 0 );
731 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800732
Lee Thomason624d43f2012-10-12 10:58:48 -0700733 addThis->_prev = 0;
734 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700735 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700736 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700737 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800738}
739
740
Lee Thomason1ff38e02012-02-14 18:18:16 -0800741XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
742{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300743 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300744 if ( addThis->_document != _document ) {
745 TIXMLASSERT( false );
746 return 0;
747 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800748 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700749
Lee Thomason624d43f2012-10-12 10:58:48 -0700750 if ( _firstChild ) {
751 TIXMLASSERT( _lastChild );
752 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800753
Lee Thomason624d43f2012-10-12 10:58:48 -0700754 _firstChild->_prev = addThis;
755 addThis->_next = _firstChild;
756 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800757
Lee Thomason624d43f2012-10-12 10:58:48 -0700758 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700759 }
760 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700761 TIXMLASSERT( _lastChild == 0 );
762 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800763
Lee Thomason624d43f2012-10-12 10:58:48 -0700764 addThis->_prev = 0;
765 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700766 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700767 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400768 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800769}
770
771
772XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
773{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300774 TIXMLASSERT( addThis );
775 if ( addThis->_document != _document ) {
776 TIXMLASSERT( false );
777 return 0;
778 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700779
Dmitry-Meabb2d042014-12-09 12:59:31 +0300780 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700781
Lee Thomason624d43f2012-10-12 10:58:48 -0700782 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300783 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700784 return 0;
785 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800786
Lee Thomason624d43f2012-10-12 10:58:48 -0700787 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700788 // The last node or the only node.
789 return InsertEndChild( addThis );
790 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800791 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700792 addThis->_prev = afterThis;
793 addThis->_next = afterThis->_next;
794 afterThis->_next->_prev = addThis;
795 afterThis->_next = addThis;
796 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700797 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800798}
799
800
801
802
Lee Thomason56bdd022012-02-09 18:16:58 -0800803const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800804{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300805 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
806 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700807 if ( element ) {
808 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
809 return element;
810 }
811 }
812 }
813 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800814}
815
816
Lee Thomason56bdd022012-02-09 18:16:58 -0800817const XMLElement* XMLNode::LastChildElement( const char* value ) const
818{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300819 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
820 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700821 if ( element ) {
822 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
823 return element;
824 }
825 }
826 }
827 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800828}
829
830
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800831const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
832{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300833 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400834 const XMLElement* element = node->ToElement();
835 if ( element
836 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
837 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700838 }
839 }
840 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800841}
842
843
844const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
845{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300846 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400847 const XMLElement* element = node->ToElement();
848 if ( element
849 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
850 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700851 }
852 }
853 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800854}
855
856
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800857char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800858{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700859 // This is a recursive method, but thinking about it "at the current level"
860 // it is a pretty simple flat list:
861 // <foo/>
862 // <!-- comment -->
863 //
864 // With a special case:
865 // <foo>
866 // </foo>
867 // <!-- comment -->
868 //
869 // Where the closing element (/foo) *must* be the next thing after the opening
870 // element, and the names must match. BUT the tricky bit is that the closing
871 // element will be read by the child.
872 //
873 // 'endTag' is the end tag for this node, it is returned by a call to a child.
874 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800875
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700876 while( p && *p ) {
877 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800878
Lee Thomason624d43f2012-10-12 10:58:48 -0700879 p = _document->Identify( p, &node );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300880 if ( node == 0 ) {
881 break;
882 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800883
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700884 StrPair endTag;
885 p = node->ParseDeep( p, &endTag );
886 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400887 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700888 if ( !_document->Error() ) {
889 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700890 }
891 break;
892 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800893
Sarat Addepalli3df007e2015-05-20 10:43:51 +0530894 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530895 if ( decl ) {
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530896 // A declaration can only be the first child of a document.
897 // Set error, if document already has children.
898 if ( !_document->NoChildren() ) {
899 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0);
900 DeleteNode( decl );
901 break;
902 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530903 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530904
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400905 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700906 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -0500907 // We read the end tag. Return it to the parent.
908 if ( ele->ClosingType() == XMLElement::CLOSING ) {
909 if ( parentEnd ) {
910 ele->_value.TransferTo( parentEnd );
911 }
912 node->_memPool->SetTracked(); // created and then immediately deleted.
913 DeleteNode( node );
914 return p;
915 }
916
917 // Handle an end tag returned to this level.
918 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400919 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300920 if ( endTag.Empty() ) {
921 if ( ele->ClosingType() == XMLElement::OPEN ) {
922 mismatch = true;
923 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700924 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +0300925 else {
926 if ( ele->ClosingType() != XMLElement::OPEN ) {
927 mismatch = true;
928 }
929 else if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400930 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700931 }
932 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400933 if ( mismatch ) {
934 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -0500935 DeleteNode( node );
936 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400937 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700938 }
JayXondbfdd8f2014-12-12 20:07:14 -0500939 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700940 }
941 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800942}
943
Dmitry-Mee3225b12014-09-03 11:03:11 +0400944void XMLNode::DeleteNode( XMLNode* node )
945{
946 if ( node == 0 ) {
947 return;
948 }
949 MemPool* pool = node->_memPool;
950 node->~XMLNode();
951 pool->Free( node );
952}
953
Lee Thomason3cebdc42015-01-05 17:16:28 -0800954void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +0300955{
956 TIXMLASSERT( insertThis );
957 TIXMLASSERT( insertThis->_document == _document );
958
959 if ( insertThis->_parent )
960 insertThis->_parent->Unlink( insertThis );
961 else
962 insertThis->_memPool->SetTracked();
963}
964
Lee Thomason5492a1c2012-01-23 15:32:10 -0800965// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800966char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800967{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700968 const char* start = p;
969 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700970 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700971 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700972 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700973 }
974 return p;
975 }
976 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700977 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
978 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +0300979 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700980 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700981
Lee Thomason624d43f2012-10-12 10:58:48 -0700982 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700983 if ( p && *p ) {
984 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +0300985 }
986 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +0300987 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700988 }
989 }
990 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800991}
992
993
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800994XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
995{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700996 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700997 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700998 }
999 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1000 text->SetCData( this->CData() );
1001 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001002}
1003
1004
1005bool XMLText::ShallowEqual( const XMLNode* compare ) const
1006{
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001007 const XMLText* text = compare->ToText();
1008 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001009}
1010
1011
Lee Thomason56bdd022012-02-09 18:16:58 -08001012bool XMLText::Accept( XMLVisitor* visitor ) const
1013{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001014 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001015 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001016}
1017
1018
Lee Thomason3f57d272012-01-11 15:30:03 -08001019// --------- XMLComment ---------- //
1020
Lee Thomasone4422302012-01-20 17:59:50 -08001021XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001022{
1023}
1024
1025
Lee Thomasonce0763e2012-01-11 15:43:54 -08001026XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001027{
Lee Thomason3f57d272012-01-11 15:30:03 -08001028}
1029
1030
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001031char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -08001032{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001033 // Comment parses as text.
1034 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001035 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001036 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001037 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001038 }
1039 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001040}
1041
1042
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001043XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1044{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001045 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001046 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001047 }
1048 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1049 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001050}
1051
1052
1053bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1054{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001055 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001056 const XMLComment* comment = compare->ToComment();
1057 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001058}
1059
1060
Lee Thomason751da522012-02-10 08:50:51 -08001061bool XMLComment::Accept( XMLVisitor* visitor ) const
1062{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001063 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001064 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001065}
Lee Thomason56bdd022012-02-09 18:16:58 -08001066
1067
Lee Thomason50f97b22012-02-11 16:33:40 -08001068// --------- XMLDeclaration ---------- //
1069
1070XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1071{
1072}
1073
1074
1075XMLDeclaration::~XMLDeclaration()
1076{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001077 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001078}
1079
1080
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001081char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001082{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001083 // Declaration parses as text.
1084 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001085 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001086 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001087 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001088 }
1089 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001090}
1091
1092
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001093XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1094{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001095 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001096 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001097 }
1098 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1099 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001100}
1101
1102
1103bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1104{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001105 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001106 const XMLDeclaration* declaration = compare->ToDeclaration();
1107 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001108}
1109
1110
1111
Lee Thomason50f97b22012-02-11 16:33:40 -08001112bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1113{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001114 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001115 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001116}
1117
1118// --------- XMLUnknown ---------- //
1119
1120XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1121{
1122}
1123
1124
1125XMLUnknown::~XMLUnknown()
1126{
1127}
1128
1129
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001130char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001131{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001132 // Unknown parses as text.
1133 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001134
Lee Thomason624d43f2012-10-12 10:58:48 -07001135 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001136 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001137 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001138 }
1139 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001140}
1141
1142
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001143XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1144{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001145 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001146 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001147 }
1148 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1149 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001150}
1151
1152
1153bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1154{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001155 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001156 const XMLUnknown* unknown = compare->ToUnknown();
1157 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001158}
1159
1160
Lee Thomason50f97b22012-02-11 16:33:40 -08001161bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1162{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001163 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001164 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001165}
1166
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001167// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001168
1169const char* XMLAttribute::Name() const
1170{
1171 return _name.GetStr();
1172}
1173
1174const char* XMLAttribute::Value() const
1175{
1176 return _value.GetStr();
1177}
1178
Lee Thomason6f381b72012-03-02 12:59:39 -08001179char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001180{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001181 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001182 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001183 if ( !p || !*p ) {
1184 return 0;
1185 }
Lee Thomason22aead12012-01-23 13:29:35 -08001186
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001187 // Skip white space before =
1188 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001189 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001190 return 0;
1191 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001192
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001193 ++p; // move up to opening quote
1194 p = XMLUtil::SkipWhiteSpace( p );
1195 if ( *p != '\"' && *p != '\'' ) {
1196 return 0;
1197 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001198
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001199 char endTag[2] = { *p, 0 };
1200 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001201
Lee Thomason624d43f2012-10-12 10:58:48 -07001202 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001203 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001204}
1205
1206
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001207void XMLAttribute::SetName( const char* n )
1208{
Lee Thomason624d43f2012-10-12 10:58:48 -07001209 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001210}
1211
1212
Lee Thomason2fa81722012-11-09 12:37:46 -08001213XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001214{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001215 if ( XMLUtil::ToInt( Value(), value )) {
1216 return XML_NO_ERROR;
1217 }
1218 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001219}
1220
1221
Lee Thomason2fa81722012-11-09 12:37:46 -08001222XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001223{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001224 if ( XMLUtil::ToUnsigned( Value(), value )) {
1225 return XML_NO_ERROR;
1226 }
1227 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001228}
1229
1230
Lee Thomason2fa81722012-11-09 12:37:46 -08001231XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001232{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001233 if ( XMLUtil::ToBool( Value(), value )) {
1234 return XML_NO_ERROR;
1235 }
1236 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001237}
1238
1239
Lee Thomason2fa81722012-11-09 12:37:46 -08001240XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001241{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001242 if ( XMLUtil::ToFloat( Value(), value )) {
1243 return XML_NO_ERROR;
1244 }
1245 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001246}
1247
1248
Lee Thomason2fa81722012-11-09 12:37:46 -08001249XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001250{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001251 if ( XMLUtil::ToDouble( Value(), value )) {
1252 return XML_NO_ERROR;
1253 }
1254 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001255}
1256
1257
1258void XMLAttribute::SetAttribute( const char* v )
1259{
Lee Thomason624d43f2012-10-12 10:58:48 -07001260 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001261}
1262
1263
Lee Thomason1ff38e02012-02-14 18:18:16 -08001264void XMLAttribute::SetAttribute( int v )
1265{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001266 char buf[BUF_SIZE];
1267 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001268 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001269}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001270
1271
1272void XMLAttribute::SetAttribute( unsigned v )
1273{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001274 char buf[BUF_SIZE];
1275 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001276 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001277}
1278
1279
1280void XMLAttribute::SetAttribute( bool v )
1281{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001282 char buf[BUF_SIZE];
1283 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001284 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001285}
1286
1287void XMLAttribute::SetAttribute( double v )
1288{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001289 char buf[BUF_SIZE];
1290 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001291 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001292}
1293
1294void XMLAttribute::SetAttribute( float v )
1295{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001296 char buf[BUF_SIZE];
1297 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001298 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001299}
1300
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001301
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001302// --------- XMLElement ---------- //
1303XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001304 _closingType( 0 ),
1305 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001306{
1307}
1308
1309
1310XMLElement::~XMLElement()
1311{
Lee Thomason624d43f2012-10-12 10:58:48 -07001312 while( _rootAttribute ) {
1313 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001314 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001315 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001316 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001317}
1318
1319
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001320const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1321{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001322 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001323 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1324 return a;
1325 }
1326 }
1327 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001328}
1329
1330
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001331const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001332{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001333 const XMLAttribute* a = FindAttribute( name );
1334 if ( !a ) {
1335 return 0;
1336 }
1337 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1338 return a->Value();
1339 }
1340 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001341}
1342
1343
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001344const char* XMLElement::GetText() const
1345{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001346 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001347 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001348 }
1349 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001350}
1351
1352
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001353void XMLElement::SetText( const char* inText )
1354{
Uli Kusterer869bb592014-01-21 01:36:16 +01001355 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001356 FirstChild()->SetValue( inText );
1357 else {
1358 XMLText* theText = GetDocument()->NewText( inText );
1359 InsertFirstChild( theText );
1360 }
1361}
1362
Lee Thomason5bb2d802014-01-24 10:42:57 -08001363
1364void XMLElement::SetText( int v )
1365{
1366 char buf[BUF_SIZE];
1367 XMLUtil::ToStr( v, buf, BUF_SIZE );
1368 SetText( buf );
1369}
1370
1371
1372void XMLElement::SetText( unsigned v )
1373{
1374 char buf[BUF_SIZE];
1375 XMLUtil::ToStr( v, buf, BUF_SIZE );
1376 SetText( buf );
1377}
1378
1379
1380void XMLElement::SetText( bool v )
1381{
1382 char buf[BUF_SIZE];
1383 XMLUtil::ToStr( v, buf, BUF_SIZE );
1384 SetText( buf );
1385}
1386
1387
1388void XMLElement::SetText( float v )
1389{
1390 char buf[BUF_SIZE];
1391 XMLUtil::ToStr( v, buf, BUF_SIZE );
1392 SetText( buf );
1393}
1394
1395
1396void XMLElement::SetText( double v )
1397{
1398 char buf[BUF_SIZE];
1399 XMLUtil::ToStr( v, buf, BUF_SIZE );
1400 SetText( buf );
1401}
1402
1403
MortenMacFly4ee49f12013-01-14 20:03:14 +01001404XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001405{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001406 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001407 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001408 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001409 return XML_SUCCESS;
1410 }
1411 return XML_CAN_NOT_CONVERT_TEXT;
1412 }
1413 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001414}
1415
1416
MortenMacFly4ee49f12013-01-14 20:03:14 +01001417XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001418{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001419 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001420 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001421 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001422 return XML_SUCCESS;
1423 }
1424 return XML_CAN_NOT_CONVERT_TEXT;
1425 }
1426 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001427}
1428
1429
MortenMacFly4ee49f12013-01-14 20:03:14 +01001430XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001431{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001432 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001433 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001434 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001435 return XML_SUCCESS;
1436 }
1437 return XML_CAN_NOT_CONVERT_TEXT;
1438 }
1439 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001440}
1441
1442
MortenMacFly4ee49f12013-01-14 20:03:14 +01001443XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001444{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001445 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001446 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001447 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001448 return XML_SUCCESS;
1449 }
1450 return XML_CAN_NOT_CONVERT_TEXT;
1451 }
1452 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001453}
1454
1455
MortenMacFly4ee49f12013-01-14 20:03:14 +01001456XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001457{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001458 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001459 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001460 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001461 return XML_SUCCESS;
1462 }
1463 return XML_CAN_NOT_CONVERT_TEXT;
1464 }
1465 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001466}
1467
1468
1469
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001470XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1471{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001472 XMLAttribute* last = 0;
1473 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001474 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001475 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001476 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001477 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1478 break;
1479 }
1480 }
1481 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001482 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001483 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1484 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001485 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001486 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001487 }
1488 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001489 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001490 }
1491 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001492 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001493 }
1494 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001495}
1496
1497
U-Stream\Leeae25a442012-02-17 17:48:16 -08001498void XMLElement::DeleteAttribute( const char* name )
1499{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001500 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001501 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001502 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1503 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001504 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001505 }
1506 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001507 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001508 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001509 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001510 break;
1511 }
1512 prev = a;
1513 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001514}
1515
1516
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001517char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001518{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001519 const char* start = p;
1520 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001521
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001522 // Read the attributes.
1523 while( p ) {
1524 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001525 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001526 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001527 return 0;
1528 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001529
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001530 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001531 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001532 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001533 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1534 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001535 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001536
Lee Thomason624d43f2012-10-12 10:58:48 -07001537 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001538 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001539 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001540 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001541 return 0;
1542 }
1543 // There is a minor bug here: if the attribute in the source xml
1544 // document is duplicated, it will not be detected and the
1545 // attribute will be doubly added. However, tracking the 'prevAttribute'
1546 // avoids re-scanning the attribute list. Preferring performance for
1547 // now, may reconsider in the future.
1548 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001549 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001550 }
1551 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001552 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001553 }
1554 prevAttribute = attrib;
1555 }
1556 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001557 else if ( *p == '>' ) {
1558 ++p;
1559 break;
1560 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001561 // end of the tag
1562 else if ( *p == '/' && *(p+1) == '>' ) {
1563 _closingType = CLOSED;
1564 return p+2; // done; sealed element.
1565 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001566 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001567 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001568 return 0;
1569 }
1570 }
1571 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001572}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001573
Dmitry-Mee3225b12014-09-03 11:03:11 +04001574void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1575{
1576 if ( attribute == 0 ) {
1577 return;
1578 }
1579 MemPool* pool = attribute->_memPool;
1580 attribute->~XMLAttribute();
1581 pool->Free( attribute );
1582}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001583
Lee Thomason67d61312012-01-24 16:01:51 -08001584//
1585// <ele></ele>
1586// <ele>foo<b>bar</b></ele>
1587//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001588char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001589{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001590 // Read the element name.
1591 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001592
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001593 // The closing element is the </element> form. It is
1594 // parsed just like a regular element then deleted from
1595 // the DOM.
1596 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001597 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001598 ++p;
1599 }
Lee Thomason67d61312012-01-24 16:01:51 -08001600
Lee Thomason624d43f2012-10-12 10:58:48 -07001601 p = _value.ParseName( p );
1602 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001603 return 0;
1604 }
Lee Thomason67d61312012-01-24 16:01:51 -08001605
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001606 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001607 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001608 return p;
1609 }
Lee Thomason67d61312012-01-24 16:01:51 -08001610
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001611 p = XMLNode::ParseDeep( p, strPair );
1612 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001613}
1614
1615
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001616
1617XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1618{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001619 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001620 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001621 }
1622 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1623 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1624 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1625 }
1626 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001627}
1628
1629
1630bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1631{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001632 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001633 const XMLElement* other = compare->ToElement();
1634 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001635
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001636 const XMLAttribute* a=FirstAttribute();
1637 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001638
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001639 while ( a && b ) {
1640 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1641 return false;
1642 }
1643 a = a->Next();
1644 b = b->Next();
1645 }
1646 if ( a || b ) {
1647 // different count
1648 return false;
1649 }
1650 return true;
1651 }
1652 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001653}
1654
1655
Lee Thomason751da522012-02-10 08:50:51 -08001656bool XMLElement::Accept( XMLVisitor* visitor ) const
1657{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001658 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001659 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001660 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1661 if ( !node->Accept( visitor ) ) {
1662 break;
1663 }
1664 }
1665 }
1666 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001667}
Lee Thomason56bdd022012-02-09 18:16:58 -08001668
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001669
Lee Thomason3f57d272012-01-11 15:30:03 -08001670// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001671
1672// Warning: List must match 'enum XMLError'
1673const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1674 "XML_SUCCESS",
1675 "XML_NO_ATTRIBUTE",
1676 "XML_WRONG_ATTRIBUTE_TYPE",
1677 "XML_ERROR_FILE_NOT_FOUND",
1678 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1679 "XML_ERROR_FILE_READ_ERROR",
1680 "XML_ERROR_ELEMENT_MISMATCH",
1681 "XML_ERROR_PARSING_ELEMENT",
1682 "XML_ERROR_PARSING_ATTRIBUTE",
1683 "XML_ERROR_IDENTIFYING_TAG",
1684 "XML_ERROR_PARSING_TEXT",
1685 "XML_ERROR_PARSING_CDATA",
1686 "XML_ERROR_PARSING_COMMENT",
1687 "XML_ERROR_PARSING_DECLARATION",
1688 "XML_ERROR_PARSING_UNKNOWN",
1689 "XML_ERROR_EMPTY_DOCUMENT",
1690 "XML_ERROR_MISMATCHED_ELEMENT",
1691 "XML_ERROR_PARSING",
1692 "XML_CAN_NOT_CONVERT_TEXT",
1693 "XML_NO_TEXT_NODE"
1694};
1695
1696
Lee Thomason624d43f2012-10-12 10:58:48 -07001697XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001698 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001699 _writeBOM( false ),
1700 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001701 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001702 _whitespace( whitespace ),
1703 _errorStr1( 0 ),
1704 _errorStr2( 0 ),
1705 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001706{
Lee Thomason624d43f2012-10-12 10:58:48 -07001707 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001708}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001709
1710
Lee Thomason3f57d272012-01-11 15:30:03 -08001711XMLDocument::~XMLDocument()
1712{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001713 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001714}
1715
1716
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001717void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001718{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001719 DeleteChildren();
1720
Dmitry-Meab37df82014-11-28 12:08:36 +03001721#ifdef DEBUG
1722 const bool hadError = Error();
1723#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001724 _errorID = XML_NO_ERROR;
1725 _errorStr1 = 0;
1726 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001727
Lee Thomason624d43f2012-10-12 10:58:48 -07001728 delete [] _charBuffer;
1729 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001730
1731#if 0
1732 _textPool.Trace( "text" );
1733 _elementPool.Trace( "element" );
1734 _commentPool.Trace( "comment" );
1735 _attributePool.Trace( "attribute" );
1736#endif
1737
1738#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001739 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001740 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1741 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1742 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1743 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1744 }
1745#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001746}
1747
Lee Thomason3f57d272012-01-11 15:30:03 -08001748
Lee Thomason2c85a712012-01-31 08:24:24 -08001749XMLElement* XMLDocument::NewElement( const char* name )
1750{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001751 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001752 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1753 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001754 ele->SetName( name );
1755 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001756}
1757
1758
Lee Thomason1ff38e02012-02-14 18:18:16 -08001759XMLComment* XMLDocument::NewComment( const char* str )
1760{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001761 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001762 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1763 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001764 comment->SetValue( str );
1765 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001766}
1767
1768
1769XMLText* XMLDocument::NewText( const char* str )
1770{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001771 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001772 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1773 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001774 text->SetValue( str );
1775 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001776}
1777
1778
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001779XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1780{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001781 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001782 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1783 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001784 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1785 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001786}
1787
1788
1789XMLUnknown* XMLDocument::NewUnknown( const char* str )
1790{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001791 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001792 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1793 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001794 unk->SetValue( str );
1795 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001796}
1797
Dmitry-Me01578db2014-08-19 10:18:48 +04001798static FILE* callfopen( const char* filepath, const char* mode )
1799{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001800 TIXMLASSERT( filepath );
1801 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001802#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1803 FILE* fp = 0;
1804 errno_t err = fopen_s( &fp, filepath, mode );
1805 if ( err ) {
1806 return 0;
1807 }
1808#else
1809 FILE* fp = fopen( filepath, mode );
1810#endif
1811 return fp;
1812}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001813
1814void XMLDocument::DeleteNode( XMLNode* node ) {
1815 TIXMLASSERT( node );
1816 TIXMLASSERT(node->_document == this );
1817 if (node->_parent) {
1818 node->_parent->DeleteChild( node );
1819 }
1820 else {
1821 // Isn't in the tree.
1822 // Use the parent delete.
1823 // Also, we need to mark it tracked: we 'know'
1824 // it was never used.
1825 node->_memPool->SetTracked();
1826 // Call the static XMLNode version:
1827 XMLNode::DeleteNode(node);
1828 }
1829}
1830
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001831
Lee Thomason2fa81722012-11-09 12:37:46 -08001832XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001833{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001834 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001835 FILE* fp = callfopen( filename, "rb" );
1836 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001837 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001838 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001839 }
1840 LoadFile( fp );
1841 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001842 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001843}
1844
1845
Lee Thomason2fa81722012-11-09 12:37:46 -08001846XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001847{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001848 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001849
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001850 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001851 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001852 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1853 return _errorID;
1854 }
1855
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001856 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001857 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001858 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001859 if ( filelength == -1L ) {
1860 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1861 return _errorID;
1862 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001863
Lee Thomason7a93b332015-05-22 11:00:32 -07001864 if ( (size_t)filelength >= (size_t)-1 ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03001865 // Cannot handle files which won't fit in buffer together with null terminator
1866 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1867 return _errorID;
1868 }
1869
Dmitry-Me72801b82015-05-07 09:41:39 +03001870 if ( filelength == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001871 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001872 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001873 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001874
Dmitry-Me72801b82015-05-07 09:41:39 +03001875 const size_t size = filelength;
Lee Thomason624d43f2012-10-12 10:58:48 -07001876 _charBuffer = new char[size+1];
1877 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001878 if ( read != size ) {
1879 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001880 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001881 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001882
Lee Thomason624d43f2012-10-12 10:58:48 -07001883 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001884
Dmitry-Me97476b72015-01-01 16:15:57 +03001885 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07001886 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001887}
1888
1889
Lee Thomason2fa81722012-11-09 12:37:46 -08001890XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001891{
Dmitry-Me01578db2014-08-19 10:18:48 +04001892 FILE* fp = callfopen( filename, "w" );
1893 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001894 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001895 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001896 }
1897 SaveFile(fp, compact);
1898 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001899 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001900}
1901
1902
Lee Thomason2fa81722012-11-09 12:37:46 -08001903XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001904{
Ant Mitchell189198f2015-03-24 16:20:36 +00001905 // Clear any error from the last save, otherwise it will get reported
1906 // for *this* call.
1907 SetError( XML_NO_ERROR, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001908 XMLPrinter stream( fp, compact );
1909 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001910 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001911}
1912
Lee Thomason1ff38e02012-02-14 18:18:16 -08001913
Lee Thomason2fa81722012-11-09 12:37:46 -08001914XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001915{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001916 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001917
Lee Thomason82d32002014-02-21 22:47:18 -08001918 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001919 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001920 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001921 }
1922 if ( len == (size_t)(-1) ) {
1923 len = strlen( p );
1924 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001925 _charBuffer = new char[ len+1 ];
1926 memcpy( _charBuffer, p, len );
1927 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001928
Dmitry-Me97476b72015-01-01 16:15:57 +03001929 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001930 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001931 // clean up now essentially dangling memory.
1932 // and the parse fail can put objects in the
1933 // pools that are dead and inaccessible.
1934 DeleteChildren();
1935 _elementPool.Clear();
1936 _attributePool.Clear();
1937 _textPool.Clear();
1938 _commentPool.Clear();
1939 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001940 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001941}
1942
1943
PKEuS1c5f99e2013-07-06 11:28:39 +02001944void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001945{
Dmitry-Me67c429e2015-05-08 18:08:18 +03001946 if ( streamer ) {
1947 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001948 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03001949 else {
1950 XMLPrinter stdoutStreamer( stdout );
1951 Accept( &stdoutStreamer );
1952 }
Lee Thomason3f57d272012-01-11 15:30:03 -08001953}
1954
1955
Lee Thomason2fa81722012-11-09 12:37:46 -08001956void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001957{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001958 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07001959 _errorID = error;
1960 _errorStr1 = str1;
1961 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001962}
1963
Lee Thomason331596e2014-09-11 14:56:43 -07001964const char* XMLDocument::ErrorName() const
1965{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001966 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Lee Thomason331596e2014-09-11 14:56:43 -07001967 return _errorNames[_errorID];
1968}
Lee Thomason5cae8972012-01-24 18:03:07 -08001969
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001970void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001971{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001972 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001973 static const int LEN = 20;
1974 char buf1[LEN] = { 0 };
1975 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001976
Lee Thomason624d43f2012-10-12 10:58:48 -07001977 if ( _errorStr1 ) {
1978 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001979 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001980 if ( _errorStr2 ) {
1981 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001982 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001983
Dmitry-Me2ad43202015-04-16 12:18:58 +03001984 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
1985 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
1986 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
Lee Thomason331596e2014-09-11 14:56:43 -07001987 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
Dmitry-Me400f1192015-04-07 11:51:21 +03001988 static_cast<int>( _errorID ), ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001989 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001990}
1991
Dmitry-Me97476b72015-01-01 16:15:57 +03001992void XMLDocument::Parse()
1993{
1994 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
1995 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08001996 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03001997 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03001998 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03001999 if ( !*p ) {
2000 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2001 return;
2002 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08002003 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002004}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002005
PKEuS1bfb9542013-08-04 13:51:17 +02002006XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002007 _elementJustOpened( false ),
2008 _firstElement( true ),
2009 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002010 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002011 _textDepth( -1 ),
2012 _processEntities( true ),
2013 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002014{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002015 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002016 _entityFlag[i] = false;
2017 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002018 }
2019 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002020 const char entityValue = entities[i].value;
2021 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
2022 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002023 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002024 _restrictedEntityFlag[(unsigned char)'&'] = true;
2025 _restrictedEntityFlag[(unsigned char)'<'] = true;
2026 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002027 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002028}
2029
2030
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002031void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002032{
2033 va_list va;
2034 va_start( va, format );
2035
Lee Thomason624d43f2012-10-12 10:58:48 -07002036 if ( _fp ) {
2037 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002038 }
2039 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07002040#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08002041 #if defined(WINCE)
2042 int len = 512;
2043 do {
2044 len = len*2;
2045 char* str = new char[len]();
2046 len = _vsnprintf(str, len, format, va);
2047 delete[] str;
2048 }while (len < 0);
2049 #else
Thomas Roß268c6832014-03-13 23:35:16 +01002050 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08002051 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002052#else
2053 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01002054#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002055 // Close out and re-start the va-args
2056 va_end( va );
2057 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002058 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002059 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
2060#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08002061 #if defined(WINCE)
2062 _vsnprintf( p, len+1, format, va );
2063 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07002064 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08002065 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07002066#else
2067 vsnprintf( p, len+1, format, va );
2068#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002069 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002070 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002071}
2072
2073
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002074void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002075{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002076 for( int i=0; i<depth; ++i ) {
2077 Print( " " );
2078 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002079}
2080
2081
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002082void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002083{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002084 // Look for runs of bytes between entities to print.
2085 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002086
Lee Thomason624d43f2012-10-12 10:58:48 -07002087 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002088 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002089 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002090 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002091 // Remember, char is sometimes signed. (How many times has that bitten me?)
2092 if ( *q > 0 && *q < ENTITY_RANGE ) {
2093 // Check for entities. If one is found, flush
2094 // the stream up until the entity, write the
2095 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002096 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002097 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002098 const size_t delta = q - p;
2099 // %.*s accepts type int as "precision"
2100 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : delta;
2101 Print( "%.*s", toPrint, p );
2102 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002103 }
2104 for( int i=0; i<NUM_ENTITIES; ++i ) {
2105 if ( entities[i].value == *q ) {
2106 Print( "&%s;", entities[i].pattern );
2107 break;
2108 }
2109 }
2110 ++p;
2111 }
2112 }
2113 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002114 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002115 }
2116 }
2117 // Flush the remaining string. This will be the entire
2118 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002119 TIXMLASSERT( p <= q );
2120 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002121 Print( "%s", p );
2122 }
Lee Thomason857b8682012-01-25 17:50:25 -08002123}
2124
U-Stream\Leeae25a442012-02-17 17:48:16 -08002125
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002126void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002127{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002128 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002129 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 -07002130 Print( "%s", bom );
2131 }
2132 if ( writeDec ) {
2133 PushDeclaration( "xml version=\"1.0\"" );
2134 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002135}
2136
2137
Uli Kusterer593a33d2014-02-01 12:48:51 +01002138void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002139{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002140 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002141 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002142
Uli Kusterer593a33d2014-02-01 12:48:51 +01002143 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002144 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002145 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002146 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002147 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002148 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002149
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002150 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002151 _elementJustOpened = true;
2152 _firstElement = false;
2153 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002154}
2155
2156
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002157void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002158{
Lee Thomason624d43f2012-10-12 10:58:48 -07002159 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002160 Print( " %s=\"", name );
2161 PrintString( value, false );
2162 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002163}
2164
2165
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002166void XMLPrinter::PushAttribute( const char* name, int v )
2167{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002168 char buf[BUF_SIZE];
2169 XMLUtil::ToStr( v, buf, BUF_SIZE );
2170 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002171}
2172
2173
2174void XMLPrinter::PushAttribute( const char* name, unsigned v )
2175{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002176 char buf[BUF_SIZE];
2177 XMLUtil::ToStr( v, buf, BUF_SIZE );
2178 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002179}
2180
2181
2182void XMLPrinter::PushAttribute( const char* name, bool v )
2183{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002184 char buf[BUF_SIZE];
2185 XMLUtil::ToStr( v, buf, BUF_SIZE );
2186 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002187}
2188
2189
2190void XMLPrinter::PushAttribute( const char* name, double v )
2191{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002192 char buf[BUF_SIZE];
2193 XMLUtil::ToStr( v, buf, BUF_SIZE );
2194 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002195}
2196
2197
Uli Kustererca412e82014-02-01 13:35:05 +01002198void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002199{
Lee Thomason624d43f2012-10-12 10:58:48 -07002200 --_depth;
2201 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002202
Lee Thomason624d43f2012-10-12 10:58:48 -07002203 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002204 Print( "/>" );
2205 }
2206 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002207 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002208 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002209 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002210 }
2211 Print( "</%s>", name );
2212 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002213
Lee Thomason624d43f2012-10-12 10:58:48 -07002214 if ( _textDepth == _depth ) {
2215 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002216 }
Uli Kustererca412e82014-02-01 13:35:05 +01002217 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002218 Print( "\n" );
2219 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002220 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002221}
2222
2223
Dmitry-Mea092bc12014-12-23 17:57:05 +03002224void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002225{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002226 if ( !_elementJustOpened ) {
2227 return;
2228 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002229 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002230 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002231}
2232
2233
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002234void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002235{
Lee Thomason624d43f2012-10-12 10:58:48 -07002236 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002237
Dmitry-Mea092bc12014-12-23 17:57:05 +03002238 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002239 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002240 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002241 }
2242 else {
2243 PrintString( text, true );
2244 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002245}
2246
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002247void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002248{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002249 char buf[BUF_SIZE];
2250 XMLUtil::ToStr( value, buf, BUF_SIZE );
2251 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002252}
2253
2254
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002255void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002256{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002257 char buf[BUF_SIZE];
2258 XMLUtil::ToStr( value, buf, BUF_SIZE );
2259 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002260}
2261
2262
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002263void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002264{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002265 char buf[BUF_SIZE];
2266 XMLUtil::ToStr( value, buf, BUF_SIZE );
2267 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002268}
2269
2270
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002271void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002272{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002273 char buf[BUF_SIZE];
2274 XMLUtil::ToStr( value, buf, BUF_SIZE );
2275 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002276}
2277
2278
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002279void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002280{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002281 char buf[BUF_SIZE];
2282 XMLUtil::ToStr( value, buf, BUF_SIZE );
2283 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002284}
2285
Lee Thomason5cae8972012-01-24 18:03:07 -08002286
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002287void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002288{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002289 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002290 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002291 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002292 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002293 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002294 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002295 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002296}
Lee Thomason751da522012-02-10 08:50:51 -08002297
2298
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002299void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002300{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002301 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002302 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002303 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002304 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002305 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002306 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002307 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002308}
2309
2310
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002311void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002312{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002313 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002314 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002315 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002316 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002317 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002318 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002319 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002320}
2321
2322
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002323bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002324{
Lee Thomason624d43f2012-10-12 10:58:48 -07002325 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002326 if ( doc.HasBOM() ) {
2327 PushHeader( true, false );
2328 }
2329 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002330}
2331
2332
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002333bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002334{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002335 const XMLElement* parentElem = 0;
2336 if ( element.Parent() ) {
2337 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002338 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002339 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002340 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002341 while ( attribute ) {
2342 PushAttribute( attribute->Name(), attribute->Value() );
2343 attribute = attribute->Next();
2344 }
2345 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002346}
2347
2348
Uli Kustererca412e82014-02-01 13:35:05 +01002349bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002350{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002351 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002352 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002353}
2354
2355
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002356bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002357{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002358 PushText( text.Value(), text.CData() );
2359 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 XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002364{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002365 PushComment( comment.Value() );
2366 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002367}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002368
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002369bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002370{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002371 PushDeclaration( declaration.Value() );
2372 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002373}
2374
2375
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002376bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002377{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002378 PushUnknown( unknown.Value() );
2379 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002380}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002381
Lee Thomason685b8952012-11-12 13:00:06 -08002382} // namespace tinyxml2
2383