blob: 1b540174da8bf7dfa8ca9a798698beeb0670daab [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.
Wilfred van Velzen67abee52016-03-25 14:01:15 +010027#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)
Lee Thomasona9cf3f92012-10-11 16:56:51 -070028# include <stddef.h>
Philipp Kloke358202c2015-07-30 16:02:26 +020029# include <stdarg.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070030#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070031# include <cstddef>
Philipp Kloke358202c2015-07-30 16:02:26 +020032# include <cstdarg>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070033#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080034
Lee Thomason53db4a62015-06-11 22:52:08 -070035#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
Dmitry-Me1ca593c2015-06-22 12:49:32 +030036 // Microsoft Visual Studio, version 2005 and higher. Not WinCE.
Lee Thomason53db4a62015-06-11 22:52:08 -070037 /*int _snprintf_s(
38 char *buffer,
39 size_t sizeOfBuffer,
40 size_t count,
41 const char *format [,
42 argument] ...
43 );*/
PKEuScac75782015-08-15 18:17:27 +020044 static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
Lee Thomason53db4a62015-06-11 22:52:08 -070045 {
46 va_list va;
47 va_start( va, format );
48 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
49 va_end( va );
50 return result;
51 }
52
PKEuScac75782015-08-15 18:17:27 +020053 static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070054 {
55 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
56 return result;
57 }
58
59 #define TIXML_VSCPRINTF _vscprintf
60 #define TIXML_SSCANF sscanf_s
61#elif defined _MSC_VER
62 // Microsoft Visual Studio 2003 and earlier or WinCE
63 #define TIXML_SNPRINTF _snprintf
64 #define TIXML_VSNPRINTF _vsnprintf
65 #define TIXML_SSCANF sscanf
Lee Thomasonaa8566b2015-06-19 16:52:40 -070066 #if (_MSC_VER < 1400 ) && (!defined WINCE)
Lee Thomason53db4a62015-06-11 22:52:08 -070067 // Microsoft Visual Studio 2003 and not WinCE.
68 #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have.
69 #else
70 // Microsoft Visual Studio 2003 and earlier or WinCE.
PKEuScac75782015-08-15 18:17:27 +020071 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070072 {
73 int len = 512;
74 for (;;) {
75 len = len*2;
76 char* str = new char[len]();
77 const int required = _vsnprintf(str, len, format, va);
78 delete[] str;
79 if ( required != -1 ) {
Dmitry-Me1d32e582015-07-27 17:11:51 +030080 TIXMLASSERT( required >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070081 len = required;
82 break;
83 }
84 }
Dmitry-Me1d32e582015-07-27 17:11:51 +030085 TIXMLASSERT( len >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070086 return len;
87 }
88 #endif
89#else
90 // GCC version 3 and higher
91 //#warning( "Using sn* functions." )
92 #define TIXML_SNPRINTF snprintf
93 #define TIXML_VSNPRINTF vsnprintf
PKEuScac75782015-08-15 18:17:27 +020094 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070095 {
96 int len = vsnprintf( 0, 0, format, va );
Dmitry-Me1d32e582015-07-27 17:11:51 +030097 TIXMLASSERT( len >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070098 return len;
99 }
100 #define TIXML_SSCANF sscanf
101#endif
102
103
Lee Thomasone4422302012-01-20 17:59:50 -0800104static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -0800105static const char LF = LINE_FEED;
106static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
107static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -0800108static const char SINGLE_QUOTE = '\'';
109static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -0800110
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800111// Bunch of unicode info at:
112// http://www.unicode.org/faq/utf_bom.html
113// ef bb bf (Microsoft "lead bytes") - designates UTF-8
114
115static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
116static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
117static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800118
Kevin Wojniak04c22d22012-11-08 11:02:22 -0800119namespace tinyxml2
120{
121
Lee Thomason8ee79892012-01-25 17:44:30 -0800122struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700123 const char* pattern;
124 int length;
125 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -0800126};
127
128static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700129static const Entity entities[NUM_ENTITIES] = {
130 { "quot", 4, DOUBLE_QUOTE },
131 { "amp", 3, '&' },
132 { "apos", 4, SINGLE_QUOTE },
133 { "lt", 2, '<' },
134 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -0800135};
136
Lee Thomasonfde6a752012-01-14 18:08:12 -0800137
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800138StrPair::~StrPair()
139{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700140 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800141}
142
143
Lee Thomason29658802014-11-27 22:31:11 -0800144void StrPair::TransferTo( StrPair* other )
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300145{
Lee Thomason29658802014-11-27 22:31:11 -0800146 if ( this == other ) {
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300147 return;
148 }
149 // This in effect implements the assignment operator by "moving"
150 // ownership (as in auto_ptr).
151
Dmitry-Medb02b212016-08-04 17:16:05 +0300152 TIXMLASSERT( other != 0 );
Lee Thomason29658802014-11-27 22:31:11 -0800153 TIXMLASSERT( other->_flags == 0 );
154 TIXMLASSERT( other->_start == 0 );
155 TIXMLASSERT( other->_end == 0 );
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300156
Lee Thomason29658802014-11-27 22:31:11 -0800157 other->Reset();
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300158
Lee Thomason29658802014-11-27 22:31:11 -0800159 other->_flags = _flags;
160 other->_start = _start;
161 other->_end = _end;
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300162
163 _flags = 0;
164 _start = 0;
165 _end = 0;
166}
167
Lee Thomasonaa188392017-09-19 17:54:31 -0700168
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800169void StrPair::Reset()
170{
Lee Thomason120b3a62012-10-12 10:06:59 -0700171 if ( _flags & NEEDS_DELETE ) {
172 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700173 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700174 _flags = 0;
175 _start = 0;
176 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800177}
178
179
180void StrPair::SetStr( const char* str, int flags )
181{
Dmitry-Me0515fa92015-12-09 11:54:06 +0300182 TIXMLASSERT( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700183 Reset();
184 size_t len = strlen( str );
Dmitry-Me96f38cc2015-08-10 16:45:12 +0300185 TIXMLASSERT( _start == 0 );
Lee Thomason120b3a62012-10-12 10:06:59 -0700186 _start = new char[ len+1 ];
187 memcpy( _start, str, len+1 );
188 _end = _start + len;
189 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800190}
191
192
kezenator4f756162016-11-29 19:46:27 +1000193char* StrPair::ParseText( char* p, const char* endTag, int strFlags, int* curLineNumPtr )
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800194{
Dmitry-Mef9f3c3e2016-08-30 15:51:55 +0300195 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700196 TIXMLASSERT( endTag && *endTag );
Lee Thomasone90e9012016-12-24 07:34:39 -0800197 TIXMLASSERT(curLineNumPtr);
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800198
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400199 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700200 char endChar = *endTag;
201 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800202
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700203 // Inner loop of text parsing.
204 while ( *p ) {
205 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
206 Set( start, p, strFlags );
207 return p + length;
kezenatorec694152016-11-26 17:21:43 +1000208 } else if (*p == '\n') {
kezenator4f756162016-11-29 19:46:27 +1000209 ++(*curLineNumPtr);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700210 }
211 ++p;
Dmitry-Mef9f3c3e2016-08-30 15:51:55 +0300212 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700213 }
214 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800215}
216
217
218char* StrPair::ParseName( char* p )
219{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400220 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700221 return 0;
222 }
JayXonee525db2014-12-24 04:01:42 -0500223 if ( !XMLUtil::IsNameStartChar( *p ) ) {
224 return 0;
225 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800226
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400227 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500228 ++p;
229 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700230 ++p;
231 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800232
JayXonee525db2014-12-24 04:01:42 -0500233 Set( start, p, 0 );
234 return p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800235}
236
237
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700238void StrPair::CollapseWhitespace()
239{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400240 // Adjusting _start would cause undefined behavior on delete[]
241 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700242 // Trim leading space.
Lee Thomasone90e9012016-12-24 07:34:39 -0800243 _start = XMLUtil::SkipWhiteSpace( _start, 0 );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700244
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300245 if ( *_start ) {
Dmitry-Me24495822016-09-02 16:53:32 +0300246 const char* p = _start; // the read pointer
Lee Thomason120b3a62012-10-12 10:06:59 -0700247 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700248
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700249 while( *p ) {
250 if ( XMLUtil::IsWhiteSpace( *p )) {
Lee Thomasone90e9012016-12-24 07:34:39 -0800251 p = XMLUtil::SkipWhiteSpace( p, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700252 if ( *p == 0 ) {
253 break; // don't write to q; this trims the trailing space.
254 }
255 *q = ' ';
256 ++q;
257 }
258 *q = *p;
259 ++q;
260 ++p;
261 }
262 *q = 0;
263 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700264}
265
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800266
Lee Thomasone4422302012-01-20 17:59:50 -0800267const char* StrPair::GetStr()
268{
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300269 TIXMLASSERT( _start );
270 TIXMLASSERT( _end );
Lee Thomason120b3a62012-10-12 10:06:59 -0700271 if ( _flags & NEEDS_FLUSH ) {
272 *_end = 0;
273 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800274
Lee Thomason120b3a62012-10-12 10:06:59 -0700275 if ( _flags ) {
Dmitry-Me24495822016-09-02 16:53:32 +0300276 const char* p = _start; // the read pointer
Lee Thomason120b3a62012-10-12 10:06:59 -0700277 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800278
Lee Thomason120b3a62012-10-12 10:06:59 -0700279 while( p < _end ) {
280 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700281 // CR-LF pair becomes LF
282 // CR alone becomes LF
283 // LF-CR becomes LF
284 if ( *(p+1) == LF ) {
285 p += 2;
286 }
287 else {
288 ++p;
289 }
Dmitry-Mefed51122016-09-06 18:08:55 +0300290 *q = LF;
291 ++q;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700292 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700293 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700294 if ( *(p+1) == CR ) {
295 p += 2;
296 }
297 else {
298 ++p;
299 }
Dmitry-Mefed51122016-09-06 18:08:55 +0300300 *q = LF;
301 ++q;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700302 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700303 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700304 // Entities handled by tinyXML2:
305 // - special entities in the entity table [in/out]
306 // - numeric character reference [in]
307 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800308
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700309 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400310 const int buflen = 10;
311 char buf[buflen] = { 0 };
312 int len = 0;
Dmitry-Me6f51c802015-03-14 13:25:03 +0300313 char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
314 if ( adjusted == 0 ) {
315 *q = *p;
316 ++p;
317 ++q;
318 }
319 else {
320 TIXMLASSERT( 0 <= len && len <= buflen );
321 TIXMLASSERT( q + len <= adjusted );
322 p = adjusted;
323 memcpy( q, buf, len );
324 q += len;
325 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700326 }
327 else {
Dmitry-Me764545e2015-05-20 10:29:24 +0300328 bool entityFound = false;
329 for( int i = 0; i < NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400330 const Entity& entity = entities[i];
331 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
332 && *( p + entity.length + 1 ) == ';' ) {
333 // Found an entity - convert.
334 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700335 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400336 p += entity.length + 2;
Dmitry-Me764545e2015-05-20 10:29:24 +0300337 entityFound = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700338 break;
339 }
340 }
Dmitry-Me764545e2015-05-20 10:29:24 +0300341 if ( !entityFound ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700342 // fixme: treat as error?
343 ++p;
344 ++q;
345 }
346 }
347 }
348 else {
349 *q = *p;
350 ++p;
351 ++q;
352 }
353 }
354 *q = 0;
355 }
356 // The loop below has plenty going on, and this
357 // is a less useful mode. Break it out.
Dmitry-Me5420e542015-05-20 10:51:26 +0300358 if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700359 CollapseWhitespace();
360 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700361 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700362 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300363 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700364 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800365}
366
Lee Thomason2c85a712012-01-31 08:24:24 -0800367
Lee Thomasone4422302012-01-20 17:59:50 -0800368
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800369
Lee Thomason56bdd022012-02-09 18:16:58 -0800370// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800371
Lee Thomasonf458d262016-12-26 22:47:25 -0800372const char* XMLUtil::writeBoolTrue = "true";
373const char* XMLUtil::writeBoolFalse = "false";
Lee Thomasonce667c92016-12-26 16:45:30 -0800374
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800375void XMLUtil::SetBoolSerialization(const char* writeTrue, const char* writeFalse)
Lee Thomasonce667c92016-12-26 16:45:30 -0800376{
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800377 static const char* defTrue = "true";
Lee Thomasonce667c92016-12-26 16:45:30 -0800378 static const char* defFalse = "false";
Lee Thomasonce667c92016-12-26 16:45:30 -0800379
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800380 writeBoolTrue = (writeTrue) ? writeTrue : defTrue;
381 writeBoolFalse = (writeFalse) ? writeFalse : defFalse;
Lee Thomasonce667c92016-12-26 16:45:30 -0800382}
383
384
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800385const char* XMLUtil::ReadBOM( const char* p, bool* bom )
386{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300387 TIXMLASSERT( p );
388 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700389 *bom = false;
390 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
391 // Check for BOM:
392 if ( *(pu+0) == TIXML_UTF_LEAD_0
393 && *(pu+1) == TIXML_UTF_LEAD_1
394 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
395 *bom = true;
396 p += 3;
397 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300398 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700399 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800400}
401
402
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800403void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
404{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700405 const unsigned long BYTE_MASK = 0xBF;
406 const unsigned long BYTE_MARK = 0x80;
407 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800408
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700409 if (input < 0x80) {
410 *length = 1;
411 }
412 else if ( input < 0x800 ) {
413 *length = 2;
414 }
415 else if ( input < 0x10000 ) {
416 *length = 3;
417 }
418 else if ( input < 0x200000 ) {
419 *length = 4;
420 }
421 else {
Dmitry-Me2f465c42015-03-16 11:08:23 +0300422 *length = 0; // This code won't convert this correctly anyway.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700423 return;
424 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800425
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700426 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800427
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300428 // Scary scary fall throughs are annotated with carefully designed comments
429 // to suppress compiler warnings such as -Wimplicit-fallthrough in gcc
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700430 switch (*length) {
431 case 4:
432 --output;
433 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
434 input >>= 6;
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300435 //fall through
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700436 case 3:
437 --output;
438 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
439 input >>= 6;
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300440 //fall through
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700441 case 2:
442 --output;
443 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
444 input >>= 6;
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300445 //fall through
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700446 case 1:
447 --output;
448 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100449 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300450 default:
451 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700452 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800453}
454
455
456const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
457{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700458 // Presume an entity, and pull it out.
459 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800460
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700461 if ( *(p+1) == '#' && *(p+2) ) {
462 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300463 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700464 ptrdiff_t delta = 0;
465 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800466 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800467
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700468 if ( *(p+2) == 'x' ) {
469 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300470 const char* q = p+3;
471 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700472 return 0;
473 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800474
Lee Thomason7e67bc82015-01-12 14:05:12 -0800475 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800476
Dmitry-Me9f56e122015-01-12 10:07:54 +0300477 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700478 return 0;
479 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800480 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800481
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700482 delta = q-p;
483 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800484
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700485 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700486 unsigned int digit = 0;
487
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700488 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300489 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700490 }
491 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300492 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700493 }
494 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300495 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700496 }
497 else {
498 return 0;
499 }
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100500 TIXMLASSERT( digit < 16 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300501 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
502 const unsigned int digitScaled = mult * digit;
503 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
504 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300505 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700506 mult *= 16;
507 --q;
508 }
509 }
510 else {
511 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300512 const char* q = p+2;
513 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700514 return 0;
515 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800516
Lee Thomason7e67bc82015-01-12 14:05:12 -0800517 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800518
Dmitry-Me9f56e122015-01-12 10:07:54 +0300519 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700520 return 0;
521 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800522 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800523
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700524 delta = q-p;
525 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800526
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700527 while ( *q != '#' ) {
528 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300529 const unsigned int digit = *q - '0';
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100530 TIXMLASSERT( digit < 10 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300531 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
532 const unsigned int digitScaled = mult * digit;
533 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
534 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700535 }
536 else {
537 return 0;
538 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300539 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700540 mult *= 10;
541 --q;
542 }
543 }
544 // convert the UCS to UTF-8
545 ConvertUTF32ToUTF8( ucs, value, length );
546 return p + delta + 1;
547 }
548 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800549}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800550
551
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700552void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700553{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700554 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700555}
556
557
558void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
559{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700560 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700561}
562
563
564void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
565{
Lee Thomasonce667c92016-12-26 16:45:30 -0800566 TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? writeBoolTrue : writeBoolFalse);
Lee Thomason21be8822012-07-15 17:27:22 -0700567}
568
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800569/*
570 ToStr() of a number is a very tricky topic.
571 https://github.com/leethomason/tinyxml2/issues/106
572*/
Lee Thomason21be8822012-07-15 17:27:22 -0700573void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
574{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800575 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700576}
577
578
579void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
580{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800581 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700582}
583
584
Lee Thomason51c12712016-06-04 20:18:49 -0700585void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize)
586{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700587 // horrible syntax trick to make the compiler happy about %lld
588 TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v);
Lee Thomason51c12712016-06-04 20:18:49 -0700589}
590
591
Lee Thomason21be8822012-07-15 17:27:22 -0700592bool XMLUtil::ToInt( const char* str, int* value )
593{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700594 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
595 return true;
596 }
597 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700598}
599
600bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
601{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700602 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
603 return true;
604 }
605 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700606}
607
608bool XMLUtil::ToBool( const char* str, bool* value )
609{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700610 int ival = 0;
611 if ( ToInt( str, &ival )) {
612 *value = (ival==0) ? false : true;
613 return true;
614 }
615 if ( StringEqual( str, "true" ) ) {
616 *value = true;
617 return true;
618 }
619 else if ( StringEqual( str, "false" ) ) {
620 *value = false;
621 return true;
622 }
623 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700624}
625
626
627bool XMLUtil::ToFloat( const char* str, float* value )
628{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700629 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
630 return true;
631 }
632 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700633}
634
Lee Thomason51c12712016-06-04 20:18:49 -0700635
Lee Thomason21be8822012-07-15 17:27:22 -0700636bool XMLUtil::ToDouble( const char* str, double* value )
637{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700638 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
639 return true;
640 }
641 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700642}
643
644
Lee Thomason51c12712016-06-04 20:18:49 -0700645bool XMLUtil::ToInt64(const char* str, int64_t* value)
646{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700647 long long v = 0; // horrible syntax trick to make the compiler happy about %lld
648 if (TIXML_SSCANF(str, "%lld", &v) == 1) {
649 *value = (int64_t)v;
Lee Thomason51c12712016-06-04 20:18:49 -0700650 return true;
651 }
652 return false;
653}
654
655
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700656char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800657{
Dmitry-Me02384662015-03-03 16:02:13 +0300658 TIXMLASSERT( node );
659 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400660 char* const start = p;
kezenatorec694152016-11-26 17:21:43 +1000661 int const startLine = _parseCurLineNum;
kezenator4f756162016-11-29 19:46:27 +1000662 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300663 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300664 *node = 0;
665 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700666 return p;
667 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800668
Dmitry-Me962083b2015-05-26 11:38:30 +0300669 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700670 static const char* xmlHeader = { "<?" };
671 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700672 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300673 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700674 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800675
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700676 static const int xmlHeaderLen = 2;
677 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700678 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300679 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700680 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800681
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700682 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
683 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400684 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700685 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300686 returnNode = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000687 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700688 p += xmlHeaderLen;
689 }
690 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300691 returnNode = CreateUnlinkedNode<XMLComment>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000692 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700693 p += commentHeaderLen;
694 }
695 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300696 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700697 returnNode = text;
kezenatorec694152016-11-26 17:21:43 +1000698 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700699 p += cdataHeaderLen;
700 text->SetCData( true );
701 }
702 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300703 returnNode = CreateUnlinkedNode<XMLUnknown>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000704 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700705 p += dtdHeaderLen;
706 }
707 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300708 returnNode = CreateUnlinkedNode<XMLElement>( _elementPool );
kezenatorec694152016-11-26 17:21:43 +1000709 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700710 p += elementHeaderLen;
711 }
712 else {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300713 returnNode = CreateUnlinkedNode<XMLText>( _textPool );
kezenatorec694152016-11-26 17:21:43 +1000714 returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700715 p = start; // Back it up, all the text counts.
kezenatorec694152016-11-26 17:21:43 +1000716 _parseCurLineNum = startLine;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700717 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800718
Dmitry-Me02384662015-03-03 16:02:13 +0300719 TIXMLASSERT( returnNode );
720 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700721 *node = returnNode;
722 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800723}
724
725
Lee Thomason751da522012-02-10 08:50:51 -0800726bool XMLDocument::Accept( XMLVisitor* visitor ) const
727{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300728 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700729 if ( visitor->VisitEnter( *this ) ) {
730 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
731 if ( !node->Accept( visitor ) ) {
732 break;
733 }
734 }
735 }
736 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800737}
Lee Thomason56bdd022012-02-09 18:16:58 -0800738
739
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800740// --------- XMLNode ----------- //
741
742XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700743 _document( doc ),
744 _parent( 0 ),
kezenatorec694152016-11-26 17:21:43 +1000745 _parseLineNum( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -0700746 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200747 _prev( 0 ), _next( 0 ),
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700748 _userData( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200749 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800750{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800751}
752
753
754XMLNode::~XMLNode()
755{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700756 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700757 if ( _parent ) {
758 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700759 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800760}
761
Michael Daumling21626882013-10-22 17:03:37 +0200762const char* XMLNode::Value() const
763{
Dmitry-Mecaa72a62016-08-10 17:34:34 +0300764 // Edge case: XMLDocuments don't have a Value. Return null.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530765 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530766 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200767 return _value.GetStr();
768}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800769
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800770void XMLNode::SetValue( const char* str, bool staticMem )
771{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700772 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700773 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700774 }
775 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700776 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700777 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800778}
779
Dmitry-Me3f63f212017-06-19 18:25:19 +0300780XMLNode* XMLNode::DeepClone(XMLDocument* target) const
Lee Thomason7085f002017-06-01 18:09:43 -0700781{
Dmitry-Me3f63f212017-06-19 18:25:19 +0300782 XMLNode* clone = this->ShallowClone(target);
Lee Thomason7085f002017-06-01 18:09:43 -0700783 if (!clone) return 0;
784
785 for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) {
Dmitry-Me3f63f212017-06-19 18:25:19 +0300786 XMLNode* childClone = child->DeepClone(target);
Lee Thomason7085f002017-06-01 18:09:43 -0700787 TIXMLASSERT(childClone);
788 clone->InsertEndChild(childClone);
789 }
790 return clone;
791}
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800792
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800793void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800794{
Lee Thomason624d43f2012-10-12 10:58:48 -0700795 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300796 TIXMLASSERT( _lastChild );
Dmitry-Me9cb4eca2016-08-18 18:10:59 +0300797 DeleteChild( _firstChild );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700798 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700799 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800800}
801
802
803void XMLNode::Unlink( XMLNode* child )
804{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300805 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300806 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300807 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700808 if ( child == _firstChild ) {
809 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700810 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700811 if ( child == _lastChild ) {
812 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700813 }
Lee Thomasond923c672012-01-23 08:44:25 -0800814
Lee Thomason624d43f2012-10-12 10:58:48 -0700815 if ( child->_prev ) {
816 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700817 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700818 if ( child->_next ) {
819 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700820 }
Lee Thomason8a763612017-06-16 09:30:16 -0700821 child->_next = 0;
822 child->_prev = 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700823 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800824}
825
826
U-Stream\Leeae25a442012-02-17 17:48:16 -0800827void XMLNode::DeleteChild( XMLNode* node )
828{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300829 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300830 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700831 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100832 Unlink( node );
Lee Thomason816d3fa2017-06-05 14:35:55 -0700833 TIXMLASSERT(node->_prev == 0);
834 TIXMLASSERT(node->_next == 0);
835 TIXMLASSERT(node->_parent == 0);
Dmitry-Mee3225b12014-09-03 11:03:11 +0400836 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800837}
838
839
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800840XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
841{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300842 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300843 if ( addThis->_document != _document ) {
844 TIXMLASSERT( false );
845 return 0;
846 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800847 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700848
Lee Thomason624d43f2012-10-12 10:58:48 -0700849 if ( _lastChild ) {
850 TIXMLASSERT( _firstChild );
851 TIXMLASSERT( _lastChild->_next == 0 );
852 _lastChild->_next = addThis;
853 addThis->_prev = _lastChild;
854 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800855
Lee Thomason624d43f2012-10-12 10:58:48 -0700856 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700857 }
858 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700859 TIXMLASSERT( _firstChild == 0 );
860 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800861
Lee Thomason624d43f2012-10-12 10:58:48 -0700862 addThis->_prev = 0;
863 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700864 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700865 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700866 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800867}
868
869
Lee Thomason1ff38e02012-02-14 18:18:16 -0800870XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
871{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300872 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300873 if ( addThis->_document != _document ) {
874 TIXMLASSERT( false );
875 return 0;
876 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800877 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700878
Lee Thomason624d43f2012-10-12 10:58:48 -0700879 if ( _firstChild ) {
880 TIXMLASSERT( _lastChild );
881 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800882
Lee Thomason624d43f2012-10-12 10:58:48 -0700883 _firstChild->_prev = addThis;
884 addThis->_next = _firstChild;
885 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800886
Lee Thomason624d43f2012-10-12 10:58:48 -0700887 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700888 }
889 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700890 TIXMLASSERT( _lastChild == 0 );
891 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800892
Lee Thomason624d43f2012-10-12 10:58:48 -0700893 addThis->_prev = 0;
894 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700895 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700896 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400897 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800898}
899
900
901XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
902{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300903 TIXMLASSERT( addThis );
904 if ( addThis->_document != _document ) {
905 TIXMLASSERT( false );
906 return 0;
907 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700908
Dmitry-Meabb2d042014-12-09 12:59:31 +0300909 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700910
Lee Thomason624d43f2012-10-12 10:58:48 -0700911 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300912 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700913 return 0;
914 }
Dmitry-Mee8f4a8b2017-09-15 19:34:36 +0300915 if ( afterThis == addThis ) {
916 // Current state: BeforeThis -> AddThis -> OneAfterAddThis
917 // Now AddThis must disappear from it's location and then
918 // reappear between BeforeThis and OneAfterAddThis.
919 // So just leave it where it is.
920 return addThis;
921 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800922
Lee Thomason624d43f2012-10-12 10:58:48 -0700923 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700924 // The last node or the only node.
925 return InsertEndChild( addThis );
926 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800927 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700928 addThis->_prev = afterThis;
929 addThis->_next = afterThis->_next;
930 afterThis->_next->_prev = addThis;
931 afterThis->_next = addThis;
932 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700933 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800934}
935
936
937
938
Dmitry-Me886ad972015-07-22 11:00:51 +0300939const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800940{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300941 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300942 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700943 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300944 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700945 }
946 }
947 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800948}
949
950
Dmitry-Me886ad972015-07-22 11:00:51 +0300951const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800952{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300953 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300954 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700955 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300956 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700957 }
958 }
959 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800960}
961
962
Dmitry-Me886ad972015-07-22 11:00:51 +0300963const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800964{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300965 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300966 const XMLElement* element = node->ToElementWithName( name );
967 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400968 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700969 }
970 }
971 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800972}
973
974
Dmitry-Me886ad972015-07-22 11:00:51 +0300975const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800976{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300977 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300978 const XMLElement* element = node->ToElementWithName( name );
979 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400980 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700981 }
982 }
983 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800984}
985
986
Dmitry-Me10b8ecc2017-04-12 17:57:44 +0300987char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -0800988{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700989 // This is a recursive method, but thinking about it "at the current level"
990 // it is a pretty simple flat list:
991 // <foo/>
992 // <!-- comment -->
993 //
994 // With a special case:
995 // <foo>
996 // </foo>
997 // <!-- comment -->
998 //
999 // Where the closing element (/foo) *must* be the next thing after the opening
1000 // element, and the names must match. BUT the tricky bit is that the closing
1001 // element will be read by the child.
1002 //
1003 // 'endTag' is the end tag for this node, it is returned by a call to a child.
1004 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001005
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001006 while( p && *p ) {
1007 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -08001008
Lee Thomason624d43f2012-10-12 10:58:48 -07001009 p = _document->Identify( p, &node );
Dmitry-Me43364312016-11-07 18:48:50 +03001010 TIXMLASSERT( p );
Dmitry-Me9fcb8762015-03-05 17:53:34 +03001011 if ( node == 0 ) {
1012 break;
1013 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001014
kezenatore3531812016-11-29 19:49:07 +10001015 int initialLineNum = node->_parseLineNum;
kezenatorec694152016-11-26 17:21:43 +10001016
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001017 StrPair endTag;
kezenator4f756162016-11-29 19:46:27 +10001018 p = node->ParseDeep( p, &endTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001019 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001020 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -07001021 if ( !_document->Error() ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001022 _document->SetError( XML_ERROR_PARSING, initialLineNum, 0);
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001023 }
1024 break;
1025 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001026
Sarat Addepalli3df007e2015-05-20 10:43:51 +05301027 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301028 if ( decl ) {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001029 // Declarations are only allowed at document level
1030 bool wellLocated = ( ToDocument() != 0 );
1031 if ( wellLocated ) {
1032 // Multiple declarations are allowed but all declarations
1033 // must occur before anything else
1034 for ( const XMLNode* existingNode = _document->FirstChild(); existingNode; existingNode = existingNode->NextSibling() ) {
1035 if ( !existingNode->ToDeclaration() ) {
1036 wellLocated = false;
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301037 break;
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001038 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301039 }
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001040 }
1041 if ( !wellLocated ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001042 _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, "value: %s", decl->Value());
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001043 DeleteNode( node );
1044 break;
1045 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301046 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301047
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001048 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001049 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -05001050 // We read the end tag. Return it to the parent.
1051 if ( ele->ClosingType() == XMLElement::CLOSING ) {
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001052 if ( parentEndTag ) {
1053 ele->_value.TransferTo( parentEndTag );
JayXone4bf6e32014-12-26 01:00:24 -05001054 }
1055 node->_memPool->SetTracked(); // created and then immediately deleted.
1056 DeleteNode( node );
1057 return p;
1058 }
1059
1060 // Handle an end tag returned to this level.
1061 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001062 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001063 if ( endTag.Empty() ) {
1064 if ( ele->ClosingType() == XMLElement::OPEN ) {
1065 mismatch = true;
1066 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001067 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001068 else {
1069 if ( ele->ClosingType() != XMLElement::OPEN ) {
1070 mismatch = true;
1071 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001072 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001073 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001074 }
1075 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001076 if ( mismatch ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001077 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, "name=%s", ele->Name());
JayXondbfdd8f2014-12-12 20:07:14 -05001078 DeleteNode( node );
1079 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001080 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001081 }
JayXondbfdd8f2014-12-12 20:07:14 -05001082 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001083 }
1084 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001085}
1086
Lee Thomason816d3fa2017-06-05 14:35:55 -07001087/*static*/ void XMLNode::DeleteNode( XMLNode* node )
Dmitry-Mee3225b12014-09-03 11:03:11 +04001088{
1089 if ( node == 0 ) {
1090 return;
1091 }
Lee Thomason816d3fa2017-06-05 14:35:55 -07001092 TIXMLASSERT(node->_document);
1093 if (!node->ToDocument()) {
1094 node->_document->MarkInUse(node);
1095 }
1096
Dmitry-Mee3225b12014-09-03 11:03:11 +04001097 MemPool* pool = node->_memPool;
1098 node->~XMLNode();
1099 pool->Free( node );
1100}
1101
Lee Thomason3cebdc42015-01-05 17:16:28 -08001102void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001103{
1104 TIXMLASSERT( insertThis );
1105 TIXMLASSERT( insertThis->_document == _document );
1106
Lee Thomason816d3fa2017-06-05 14:35:55 -07001107 if (insertThis->_parent) {
Dmitry-Me74e39402015-01-01 16:26:17 +03001108 insertThis->_parent->Unlink( insertThis );
Lee Thomason816d3fa2017-06-05 14:35:55 -07001109 }
1110 else {
1111 insertThis->_document->MarkInUse(insertThis);
Dmitry-Me74e39402015-01-01 16:26:17 +03001112 insertThis->_memPool->SetTracked();
Lee Thomason816d3fa2017-06-05 14:35:55 -07001113 }
Dmitry-Me74e39402015-01-01 16:26:17 +03001114}
1115
Dmitry-Meecb9b072016-10-12 16:44:59 +03001116const XMLElement* XMLNode::ToElementWithName( const char* name ) const
1117{
1118 const XMLElement* element = this->ToElement();
1119 if ( element == 0 ) {
1120 return 0;
1121 }
1122 if ( name == 0 ) {
1123 return element;
1124 }
1125 if ( XMLUtil::StringEqual( element->Name(), name ) ) {
1126 return element;
1127 }
1128 return 0;
1129}
1130
Lee Thomason5492a1c2012-01-23 15:32:10 -08001131// --------- XMLText ---------- //
kezenator4f756162016-11-29 19:46:27 +10001132char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001133{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001134 const char* start = p;
1135 if ( this->CData() ) {
kezenator4f756162016-11-29 19:46:27 +10001136 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001137 if ( !p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001138 _document->SetError( XML_ERROR_PARSING_CDATA, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001139 }
1140 return p;
1141 }
1142 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001143 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1144 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001145 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001146 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001147
kezenator4f756162016-11-29 19:46:27 +10001148 p = _value.ParseText( p, "<", flags, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001149 if ( p && *p ) {
1150 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001151 }
1152 if ( !p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001153 _document->SetError( XML_ERROR_PARSING_TEXT, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001154 }
1155 }
1156 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001157}
1158
1159
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001160XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1161{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001162 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001163 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001164 }
1165 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1166 text->SetCData( this->CData() );
1167 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001168}
1169
1170
1171bool XMLText::ShallowEqual( const XMLNode* compare ) const
1172{
Dmitry-Meba68a3a2017-03-21 11:39:48 +03001173 TIXMLASSERT( compare );
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001174 const XMLText* text = compare->ToText();
1175 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001176}
1177
1178
Lee Thomason56bdd022012-02-09 18:16:58 -08001179bool XMLText::Accept( XMLVisitor* visitor ) const
1180{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001181 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001182 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001183}
1184
1185
Lee Thomason3f57d272012-01-11 15:30:03 -08001186// --------- XMLComment ---------- //
1187
Lee Thomasone4422302012-01-20 17:59:50 -08001188XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001189{
1190}
1191
1192
Lee Thomasonce0763e2012-01-11 15:43:54 -08001193XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001194{
Lee Thomason3f57d272012-01-11 15:30:03 -08001195}
1196
1197
kezenator4f756162016-11-29 19:46:27 +10001198char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason3f57d272012-01-11 15:30:03 -08001199{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001200 // Comment parses as text.
1201 const char* start = p;
kezenator4f756162016-11-29 19:46:27 +10001202 p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001203 if ( p == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001204 _document->SetError( XML_ERROR_PARSING_COMMENT, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001205 }
1206 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001207}
1208
1209
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001210XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1211{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001212 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001213 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001214 }
1215 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1216 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001217}
1218
1219
1220bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1221{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001222 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001223 const XMLComment* comment = compare->ToComment();
1224 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001225}
1226
1227
Lee Thomason751da522012-02-10 08:50:51 -08001228bool XMLComment::Accept( XMLVisitor* visitor ) const
1229{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001230 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001231 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001232}
Lee Thomason56bdd022012-02-09 18:16:58 -08001233
1234
Lee Thomason50f97b22012-02-11 16:33:40 -08001235// --------- XMLDeclaration ---------- //
1236
1237XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1238{
1239}
1240
1241
1242XMLDeclaration::~XMLDeclaration()
1243{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001244 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001245}
1246
1247
kezenator4f756162016-11-29 19:46:27 +10001248char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001249{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001250 // Declaration parses as text.
1251 const char* start = p;
kezenator4f756162016-11-29 19:46:27 +10001252 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001253 if ( p == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001254 _document->SetError( XML_ERROR_PARSING_DECLARATION, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001255 }
1256 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001257}
1258
1259
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001260XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1261{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001262 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001263 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001264 }
1265 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1266 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001267}
1268
1269
1270bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1271{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001272 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001273 const XMLDeclaration* declaration = compare->ToDeclaration();
1274 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001275}
1276
1277
1278
Lee Thomason50f97b22012-02-11 16:33:40 -08001279bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1280{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001281 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001282 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001283}
1284
1285// --------- XMLUnknown ---------- //
1286
1287XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1288{
1289}
1290
1291
1292XMLUnknown::~XMLUnknown()
1293{
1294}
1295
1296
kezenator4f756162016-11-29 19:46:27 +10001297char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001298{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001299 // Unknown parses as text.
1300 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001301
kezenator4f756162016-11-29 19:46:27 +10001302 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001303 if ( !p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001304 _document->SetError( XML_ERROR_PARSING_UNKNOWN, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001305 }
1306 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001307}
1308
1309
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001310XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1311{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001312 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001313 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001314 }
1315 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1316 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001317}
1318
1319
1320bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1321{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001322 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001323 const XMLUnknown* unknown = compare->ToUnknown();
1324 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001325}
1326
1327
Lee Thomason50f97b22012-02-11 16:33:40 -08001328bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1329{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001330 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001331 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001332}
1333
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001334// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001335
1336const char* XMLAttribute::Name() const
1337{
1338 return _name.GetStr();
1339}
1340
1341const char* XMLAttribute::Value() const
1342{
1343 return _value.GetStr();
1344}
1345
kezenator4f756162016-11-29 19:46:27 +10001346char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001347{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001348 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001349 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001350 if ( !p || !*p ) {
1351 return 0;
1352 }
Lee Thomason22aead12012-01-23 13:29:35 -08001353
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001354 // Skip white space before =
kezenator4f756162016-11-29 19:46:27 +10001355 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001356 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001357 return 0;
1358 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001359
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001360 ++p; // move up to opening quote
kezenator4f756162016-11-29 19:46:27 +10001361 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001362 if ( *p != '\"' && *p != '\'' ) {
1363 return 0;
1364 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001365
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001366 char endTag[2] = { *p, 0 };
1367 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001368
kezenator4f756162016-11-29 19:46:27 +10001369 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001370 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001371}
1372
1373
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001374void XMLAttribute::SetName( const char* n )
1375{
Lee Thomason624d43f2012-10-12 10:58:48 -07001376 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001377}
1378
1379
Lee Thomason2fa81722012-11-09 12:37:46 -08001380XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001381{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001382 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001383 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001384 }
1385 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001386}
1387
1388
Lee Thomason2fa81722012-11-09 12:37:46 -08001389XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001390{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001391 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001392 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001393 }
1394 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001395}
1396
1397
Lee Thomason51c12712016-06-04 20:18:49 -07001398XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1399{
1400 if (XMLUtil::ToInt64(Value(), value)) {
1401 return XML_SUCCESS;
1402 }
1403 return XML_WRONG_ATTRIBUTE_TYPE;
1404}
1405
1406
Lee Thomason2fa81722012-11-09 12:37:46 -08001407XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001408{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001409 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001410 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001411 }
1412 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001413}
1414
1415
Lee Thomason2fa81722012-11-09 12:37:46 -08001416XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001417{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001418 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001419 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001420 }
1421 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001422}
1423
1424
Lee Thomason2fa81722012-11-09 12:37:46 -08001425XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001426{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001427 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001428 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001429 }
1430 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001431}
1432
1433
1434void XMLAttribute::SetAttribute( const char* v )
1435{
Lee Thomason624d43f2012-10-12 10:58:48 -07001436 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001437}
1438
1439
Lee Thomason1ff38e02012-02-14 18:18:16 -08001440void XMLAttribute::SetAttribute( int v )
1441{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001442 char buf[BUF_SIZE];
1443 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001444 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001445}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001446
1447
1448void XMLAttribute::SetAttribute( unsigned v )
1449{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001450 char buf[BUF_SIZE];
1451 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001452 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001453}
1454
1455
Lee Thomason51c12712016-06-04 20:18:49 -07001456void XMLAttribute::SetAttribute(int64_t v)
1457{
1458 char buf[BUF_SIZE];
1459 XMLUtil::ToStr(v, buf, BUF_SIZE);
1460 _value.SetStr(buf);
1461}
1462
1463
1464
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001465void XMLAttribute::SetAttribute( bool v )
1466{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001467 char buf[BUF_SIZE];
1468 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001469 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001470}
1471
1472void XMLAttribute::SetAttribute( double v )
1473{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001474 char buf[BUF_SIZE];
1475 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001476 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001477}
1478
1479void XMLAttribute::SetAttribute( float v )
1480{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001481 char buf[BUF_SIZE];
1482 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001483 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001484}
1485
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001486
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001487// --------- XMLElement ---------- //
1488XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Dmitry-Mee5035632017-04-05 18:02:40 +03001489 _closingType( OPEN ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001490 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001491{
1492}
1493
1494
1495XMLElement::~XMLElement()
1496{
Lee Thomason624d43f2012-10-12 10:58:48 -07001497 while( _rootAttribute ) {
1498 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001499 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001500 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001501 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001502}
1503
1504
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001505const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1506{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001507 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001508 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1509 return a;
1510 }
1511 }
1512 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001513}
1514
1515
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001516const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001517{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001518 const XMLAttribute* a = FindAttribute( name );
1519 if ( !a ) {
1520 return 0;
1521 }
1522 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1523 return a->Value();
1524 }
1525 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001526}
1527
Josh Wittnercf3dd092016-10-11 18:57:17 -07001528int XMLElement::IntAttribute(const char* name, int defaultValue) const
1529{
1530 int i = defaultValue;
1531 QueryIntAttribute(name, &i);
1532 return i;
1533}
1534
1535unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
1536{
1537 unsigned i = defaultValue;
1538 QueryUnsignedAttribute(name, &i);
1539 return i;
1540}
1541
1542int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
1543{
1544 int64_t i = defaultValue;
1545 QueryInt64Attribute(name, &i);
1546 return i;
1547}
1548
1549bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
1550{
1551 bool b = defaultValue;
1552 QueryBoolAttribute(name, &b);
1553 return b;
1554}
1555
1556double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
1557{
1558 double d = defaultValue;
1559 QueryDoubleAttribute(name, &d);
1560 return d;
1561}
1562
1563float XMLElement::FloatAttribute(const char* name, float defaultValue) const
1564{
1565 float f = defaultValue;
1566 QueryFloatAttribute(name, &f);
1567 return f;
1568}
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001569
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001570const char* XMLElement::GetText() const
1571{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001572 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001573 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001574 }
1575 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001576}
1577
1578
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001579void XMLElement::SetText( const char* inText )
1580{
Uli Kusterer869bb592014-01-21 01:36:16 +01001581 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001582 FirstChild()->SetValue( inText );
1583 else {
1584 XMLText* theText = GetDocument()->NewText( inText );
1585 InsertFirstChild( theText );
1586 }
1587}
1588
Lee Thomason5bb2d802014-01-24 10:42:57 -08001589
1590void XMLElement::SetText( int v )
1591{
1592 char buf[BUF_SIZE];
1593 XMLUtil::ToStr( v, buf, BUF_SIZE );
1594 SetText( buf );
1595}
1596
1597
1598void XMLElement::SetText( unsigned v )
1599{
1600 char buf[BUF_SIZE];
1601 XMLUtil::ToStr( v, buf, BUF_SIZE );
1602 SetText( buf );
1603}
1604
1605
Lee Thomason51c12712016-06-04 20:18:49 -07001606void XMLElement::SetText(int64_t v)
1607{
1608 char buf[BUF_SIZE];
1609 XMLUtil::ToStr(v, buf, BUF_SIZE);
1610 SetText(buf);
1611}
1612
1613
1614void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001615{
1616 char buf[BUF_SIZE];
1617 XMLUtil::ToStr( v, buf, BUF_SIZE );
1618 SetText( buf );
1619}
1620
1621
1622void XMLElement::SetText( float v )
1623{
1624 char buf[BUF_SIZE];
1625 XMLUtil::ToStr( v, buf, BUF_SIZE );
1626 SetText( buf );
1627}
1628
1629
1630void XMLElement::SetText( double v )
1631{
1632 char buf[BUF_SIZE];
1633 XMLUtil::ToStr( v, buf, BUF_SIZE );
1634 SetText( buf );
1635}
1636
1637
MortenMacFly4ee49f12013-01-14 20:03:14 +01001638XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001639{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001640 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001641 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001642 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001643 return XML_SUCCESS;
1644 }
1645 return XML_CAN_NOT_CONVERT_TEXT;
1646 }
1647 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001648}
1649
1650
MortenMacFly4ee49f12013-01-14 20:03:14 +01001651XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001652{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001653 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001654 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001655 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001656 return XML_SUCCESS;
1657 }
1658 return XML_CAN_NOT_CONVERT_TEXT;
1659 }
1660 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001661}
1662
1663
Lee Thomason51c12712016-06-04 20:18:49 -07001664XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1665{
1666 if (FirstChild() && FirstChild()->ToText()) {
1667 const char* t = FirstChild()->Value();
1668 if (XMLUtil::ToInt64(t, ival)) {
1669 return XML_SUCCESS;
1670 }
1671 return XML_CAN_NOT_CONVERT_TEXT;
1672 }
1673 return XML_NO_TEXT_NODE;
1674}
1675
1676
MortenMacFly4ee49f12013-01-14 20:03:14 +01001677XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001678{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001679 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001680 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001681 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001682 return XML_SUCCESS;
1683 }
1684 return XML_CAN_NOT_CONVERT_TEXT;
1685 }
1686 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001687}
1688
1689
MortenMacFly4ee49f12013-01-14 20:03:14 +01001690XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001691{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001692 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001693 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001694 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001695 return XML_SUCCESS;
1696 }
1697 return XML_CAN_NOT_CONVERT_TEXT;
1698 }
1699 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001700}
1701
1702
MortenMacFly4ee49f12013-01-14 20:03:14 +01001703XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001704{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001705 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001706 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001707 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001708 return XML_SUCCESS;
1709 }
1710 return XML_CAN_NOT_CONVERT_TEXT;
1711 }
1712 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001713}
1714
Josh Wittnercf3dd092016-10-11 18:57:17 -07001715int XMLElement::IntText(int defaultValue) const
1716{
1717 int i = defaultValue;
1718 QueryIntText(&i);
1719 return i;
1720}
1721
1722unsigned XMLElement::UnsignedText(unsigned defaultValue) const
1723{
1724 unsigned i = defaultValue;
1725 QueryUnsignedText(&i);
1726 return i;
1727}
1728
1729int64_t XMLElement::Int64Text(int64_t defaultValue) const
1730{
1731 int64_t i = defaultValue;
1732 QueryInt64Text(&i);
1733 return i;
1734}
1735
1736bool XMLElement::BoolText(bool defaultValue) const
1737{
1738 bool b = defaultValue;
1739 QueryBoolText(&b);
1740 return b;
1741}
1742
1743double XMLElement::DoubleText(double defaultValue) const
1744{
1745 double d = defaultValue;
1746 QueryDoubleText(&d);
1747 return d;
1748}
1749
1750float XMLElement::FloatText(float defaultValue) const
1751{
1752 float f = defaultValue;
1753 QueryFloatText(&f);
1754 return f;
1755}
Lee Thomason21be8822012-07-15 17:27:22 -07001756
1757
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001758XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1759{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001760 XMLAttribute* last = 0;
1761 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001762 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001763 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001764 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001765 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1766 break;
1767 }
1768 }
1769 if ( !attrib ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001770 attrib = CreateAttribute();
1771 TIXMLASSERT( attrib );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001772 if ( last ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001773 TIXMLASSERT( last->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001774 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001775 }
1776 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001777 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001778 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001779 }
1780 attrib->SetName( name );
1781 }
1782 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001783}
1784
1785
U-Stream\Leeae25a442012-02-17 17:48:16 -08001786void XMLElement::DeleteAttribute( const char* name )
1787{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001788 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001789 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001790 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1791 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001792 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001793 }
1794 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001795 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001796 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001797 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001798 break;
1799 }
1800 prev = a;
1801 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001802}
1803
1804
kezenator4f756162016-11-29 19:46:27 +10001805char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001806{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001807 const char* start = p;
1808 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001809
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001810 // Read the attributes.
1811 while( p ) {
kezenator4f756162016-11-29 19:46:27 +10001812 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001813 if ( !(*p) ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001814 _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, "element name=%s", Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001815 return 0;
1816 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001817
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001818 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001819 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001820 XMLAttribute* attrib = CreateAttribute();
1821 TIXMLASSERT( attrib );
kezenatorec694152016-11-26 17:21:43 +10001822 attrib->_parseLineNum = _document->_parseCurLineNum;
Lee Thomasond1983222012-02-06 08:41:24 -08001823
kezenatorec694152016-11-26 17:21:43 +10001824 int attrLineNum = attrib->_parseLineNum;
1825
kezenator4f756162016-11-29 19:46:27 +10001826 p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001827 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001828 DeleteAttribute( attrib );
Lee Thomasonaa188392017-09-19 17:54:31 -07001829 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, attrLineNum, "element name=%s", Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001830 return 0;
1831 }
1832 // There is a minor bug here: if the attribute in the source xml
1833 // document is duplicated, it will not be detected and the
1834 // attribute will be doubly added. However, tracking the 'prevAttribute'
1835 // avoids re-scanning the attribute list. Preferring performance for
1836 // now, may reconsider in the future.
1837 if ( prevAttribute ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001838 TIXMLASSERT( prevAttribute->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001839 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001840 }
1841 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001842 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001843 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001844 }
1845 prevAttribute = attrib;
1846 }
1847 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001848 else if ( *p == '>' ) {
1849 ++p;
1850 break;
1851 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001852 // end of the tag
1853 else if ( *p == '/' && *(p+1) == '>' ) {
1854 _closingType = CLOSED;
1855 return p+2; // done; sealed element.
1856 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001857 else {
Lee Thomasonaa188392017-09-19 17:54:31 -07001858 _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001859 return 0;
1860 }
1861 }
1862 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001863}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001864
Dmitry-Mee3225b12014-09-03 11:03:11 +04001865void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1866{
1867 if ( attribute == 0 ) {
1868 return;
1869 }
1870 MemPool* pool = attribute->_memPool;
1871 attribute->~XMLAttribute();
1872 pool->Free( attribute );
1873}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001874
Dmitry-Mea60caa22016-11-22 18:28:08 +03001875XMLAttribute* XMLElement::CreateAttribute()
1876{
1877 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
1878 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
Dmitry-Me7221b492017-03-03 15:45:51 +03001879 TIXMLASSERT( attrib );
Dmitry-Mea60caa22016-11-22 18:28:08 +03001880 attrib->_memPool = &_document->_attributePool;
1881 attrib->_memPool->SetTracked();
1882 return attrib;
1883}
1884
Lee Thomason67d61312012-01-24 16:01:51 -08001885//
1886// <ele></ele>
1887// <ele>foo<b>bar</b></ele>
1888//
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001889char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -08001890{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001891 // Read the element name.
kezenator4f756162016-11-29 19:46:27 +10001892 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomason67d61312012-01-24 16:01:51 -08001893
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001894 // The closing element is the </element> form. It is
1895 // parsed just like a regular element then deleted from
1896 // the DOM.
1897 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001898 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001899 ++p;
1900 }
Lee Thomason67d61312012-01-24 16:01:51 -08001901
Lee Thomason624d43f2012-10-12 10:58:48 -07001902 p = _value.ParseName( p );
1903 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001904 return 0;
1905 }
Lee Thomason67d61312012-01-24 16:01:51 -08001906
kezenator4f756162016-11-29 19:46:27 +10001907 p = ParseAttributes( p, curLineNumPtr );
Dmitry-Mee5035632017-04-05 18:02:40 +03001908 if ( !p || !*p || _closingType != OPEN ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001909 return p;
1910 }
Lee Thomason67d61312012-01-24 16:01:51 -08001911
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001912 p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001913 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001914}
1915
1916
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001917
1918XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1919{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001920 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001921 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001922 }
1923 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1924 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1925 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1926 }
1927 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001928}
1929
1930
1931bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1932{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001933 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001934 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001935 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001936
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001937 const XMLAttribute* a=FirstAttribute();
1938 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001939
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001940 while ( a && b ) {
1941 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1942 return false;
1943 }
1944 a = a->Next();
1945 b = b->Next();
1946 }
1947 if ( a || b ) {
1948 // different count
1949 return false;
1950 }
1951 return true;
1952 }
1953 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001954}
1955
1956
Lee Thomason751da522012-02-10 08:50:51 -08001957bool XMLElement::Accept( XMLVisitor* visitor ) const
1958{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001959 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001960 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001961 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1962 if ( !node->Accept( visitor ) ) {
1963 break;
1964 }
1965 }
1966 }
1967 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001968}
Lee Thomason56bdd022012-02-09 18:16:58 -08001969
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001970
Lee Thomason3f57d272012-01-11 15:30:03 -08001971// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001972
1973// Warning: List must match 'enum XMLError'
1974const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1975 "XML_SUCCESS",
1976 "XML_NO_ATTRIBUTE",
1977 "XML_WRONG_ATTRIBUTE_TYPE",
1978 "XML_ERROR_FILE_NOT_FOUND",
1979 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1980 "XML_ERROR_FILE_READ_ERROR",
Lee Thomason8bba8b42017-06-20 09:18:41 -07001981 "UNUSED_XML_ERROR_ELEMENT_MISMATCH",
Lee Thomason331596e2014-09-11 14:56:43 -07001982 "XML_ERROR_PARSING_ELEMENT",
1983 "XML_ERROR_PARSING_ATTRIBUTE",
Lee Thomason8bba8b42017-06-20 09:18:41 -07001984 "UNUSED_XML_ERROR_IDENTIFYING_TAG",
Lee Thomason331596e2014-09-11 14:56:43 -07001985 "XML_ERROR_PARSING_TEXT",
1986 "XML_ERROR_PARSING_CDATA",
1987 "XML_ERROR_PARSING_COMMENT",
1988 "XML_ERROR_PARSING_DECLARATION",
1989 "XML_ERROR_PARSING_UNKNOWN",
1990 "XML_ERROR_EMPTY_DOCUMENT",
1991 "XML_ERROR_MISMATCHED_ELEMENT",
1992 "XML_ERROR_PARSING",
1993 "XML_CAN_NOT_CONVERT_TEXT",
1994 "XML_NO_TEXT_NODE"
1995};
1996
1997
Dmitry-Meae8a82a2017-03-03 15:40:32 +03001998XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001999 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002000 _writeBOM( false ),
2001 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07002002 _errorID(XML_SUCCESS),
Dmitry-Meae8a82a2017-03-03 15:40:32 +03002003 _whitespaceMode( whitespaceMode ),
Dmitry-Mef89bd3e2017-01-18 18:33:55 +03002004 _errorLineNum( 0 ),
2005 _charBuffer( 0 ),
2006 _parseCurLineNum( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08002007{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03002008 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
2009 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08002010}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002011
2012
Lee Thomason3f57d272012-01-11 15:30:03 -08002013XMLDocument::~XMLDocument()
2014{
Lee Thomasonf07b9522014-10-30 13:25:12 -07002015 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08002016}
2017
2018
Lee Thomason816d3fa2017-06-05 14:35:55 -07002019void XMLDocument::MarkInUse(XMLNode* node)
2020{
Dmitry-Mec2f677b2017-06-15 12:44:27 +03002021 TIXMLASSERT(node);
Lee Thomason816d3fa2017-06-05 14:35:55 -07002022 TIXMLASSERT(node->_parent == 0);
2023
2024 for (int i = 0; i < _unlinked.Size(); ++i) {
2025 if (node == _unlinked[i]) {
2026 _unlinked.SwapRemove(i);
2027 break;
2028 }
2029 }
2030}
2031
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002032void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08002033{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002034 DeleteChildren();
Lee Thomason816d3fa2017-06-05 14:35:55 -07002035 while( _unlinked.Size()) {
2036 DeleteNode(_unlinked[0]); // Will remove from _unlinked as part of delete.
2037 }
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002038
Dmitry-Meab37df82014-11-28 12:08:36 +03002039#ifdef DEBUG
2040 const bool hadError = Error();
2041#endif
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002042 ClearError();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002043
Lee Thomason624d43f2012-10-12 10:58:48 -07002044 delete [] _charBuffer;
2045 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07002046
2047#if 0
2048 _textPool.Trace( "text" );
2049 _elementPool.Trace( "element" );
2050 _commentPool.Trace( "comment" );
2051 _attributePool.Trace( "attribute" );
2052#endif
2053
2054#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002055 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002056 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
2057 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
2058 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
2059 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
2060 }
2061#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08002062}
2063
Lee Thomason3f57d272012-01-11 15:30:03 -08002064
Shuichiro Suzuki87cd4e02017-08-24 11:20:26 +09002065void XMLDocument::DeepCopy(XMLDocument* target) const
Lee Thomason7085f002017-06-01 18:09:43 -07002066{
2067 TIXMLASSERT(target);
Lee Thomason1346a172017-06-14 15:14:19 -07002068 if (target == this) {
2069 return; // technically success - a no-op.
2070 }
Lee Thomason7085f002017-06-01 18:09:43 -07002071
2072 target->Clear();
2073 for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {
2074 target->InsertEndChild(node->DeepClone(target));
2075 }
2076}
2077
Lee Thomason2c85a712012-01-31 08:24:24 -08002078XMLElement* XMLDocument::NewElement( const char* name )
2079{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002080 XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002081 ele->SetName( name );
2082 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08002083}
2084
2085
Lee Thomason1ff38e02012-02-14 18:18:16 -08002086XMLComment* XMLDocument::NewComment( const char* str )
2087{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002088 XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002089 comment->SetValue( str );
2090 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002091}
2092
2093
2094XMLText* XMLDocument::NewText( const char* str )
2095{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002096 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002097 text->SetValue( str );
2098 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002099}
2100
2101
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002102XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2103{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002104 XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002105 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2106 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002107}
2108
2109
2110XMLUnknown* XMLDocument::NewUnknown( const char* str )
2111{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002112 XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002113 unk->SetValue( str );
2114 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002115}
2116
Dmitry-Me01578db2014-08-19 10:18:48 +04002117static FILE* callfopen( const char* filepath, const char* mode )
2118{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002119 TIXMLASSERT( filepath );
2120 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002121#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2122 FILE* fp = 0;
2123 errno_t err = fopen_s( &fp, filepath, mode );
2124 if ( err ) {
2125 return 0;
2126 }
2127#else
2128 FILE* fp = fopen( filepath, mode );
2129#endif
2130 return fp;
2131}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08002132
2133void XMLDocument::DeleteNode( XMLNode* node ) {
2134 TIXMLASSERT( node );
2135 TIXMLASSERT(node->_document == this );
2136 if (node->_parent) {
2137 node->_parent->DeleteChild( node );
2138 }
2139 else {
2140 // Isn't in the tree.
2141 // Use the parent delete.
2142 // Also, we need to mark it tracked: we 'know'
2143 // it was never used.
2144 node->_memPool->SetTracked();
2145 // Call the static XMLNode version:
2146 XMLNode::DeleteNode(node);
2147 }
2148}
2149
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002150
Lee Thomason2fa81722012-11-09 12:37:46 -08002151XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002152{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002153 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04002154 FILE* fp = callfopen( filename, "rb" );
2155 if ( !fp ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002156 SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename );
Lee Thomason624d43f2012-10-12 10:58:48 -07002157 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002158 }
2159 LoadFile( fp );
2160 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002161 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002162}
2163
Dmitry-Me901fed52015-09-25 10:29:51 +03002164// This is likely overengineered template art to have a check that unsigned long value incremented
2165// by one still fits into size_t. If size_t type is larger than unsigned long type
2166// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
2167// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
2168// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
2169// types sizes relate to each other.
2170template
2171<bool = (sizeof(unsigned long) >= sizeof(size_t))>
2172struct LongFitsIntoSizeTMinusOne {
2173 static bool Fits( unsigned long value )
2174 {
2175 return value < (size_t)-1;
2176 }
2177};
2178
2179template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02002180struct LongFitsIntoSizeTMinusOne<false> {
2181 static bool Fits( unsigned long )
2182 {
2183 return true;
2184 }
2185};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002186
Lee Thomason2fa81722012-11-09 12:37:46 -08002187XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002188{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002189 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002190
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002191 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002192 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002193 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002194 return _errorID;
2195 }
2196
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002197 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002198 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002199 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002200 if ( filelength == -1L ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002201 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002202 return _errorID;
2203 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002204 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002205
Dmitry-Me901fed52015-09-25 10:29:51 +03002206 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002207 // Cannot handle files which won't fit in buffer together with null terminator
Lee Thomasonaa188392017-09-19 17:54:31 -07002208 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002209 return _errorID;
2210 }
2211
Dmitry-Me72801b82015-05-07 09:41:39 +03002212 if ( filelength == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002213 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002214 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002215 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002216
Dmitry-Me72801b82015-05-07 09:41:39 +03002217 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002218 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002219 _charBuffer = new char[size+1];
2220 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002221 if ( read != size ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002222 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002223 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002224 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002225
Lee Thomason624d43f2012-10-12 10:58:48 -07002226 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002227
Dmitry-Me97476b72015-01-01 16:15:57 +03002228 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002229 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002230}
2231
2232
Lee Thomason2fa81722012-11-09 12:37:46 -08002233XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002234{
Dmitry-Me01578db2014-08-19 10:18:48 +04002235 FILE* fp = callfopen( filename, "w" );
2236 if ( !fp ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002237 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename );
Lee Thomason624d43f2012-10-12 10:58:48 -07002238 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002239 }
2240 SaveFile(fp, compact);
2241 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002242 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002243}
2244
2245
Lee Thomason2fa81722012-11-09 12:37:46 -08002246XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002247{
Ant Mitchell189198f2015-03-24 16:20:36 +00002248 // Clear any error from the last save, otherwise it will get reported
2249 // for *this* call.
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002250 ClearError();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002251 XMLPrinter stream( fp, compact );
2252 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002253 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002254}
2255
Lee Thomason1ff38e02012-02-14 18:18:16 -08002256
Lee Thomason2fa81722012-11-09 12:37:46 -08002257XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002258{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002259 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002260
Lee Thomason82d32002014-02-21 22:47:18 -08002261 if ( len == 0 || !p || !*p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002262 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002263 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002264 }
2265 if ( len == (size_t)(-1) ) {
2266 len = strlen( p );
2267 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002268 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002269 _charBuffer = new char[ len+1 ];
2270 memcpy( _charBuffer, p, len );
2271 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002272
Dmitry-Me97476b72015-01-01 16:15:57 +03002273 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002274 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002275 // clean up now essentially dangling memory.
2276 // and the parse fail can put objects in the
2277 // pools that are dead and inaccessible.
2278 DeleteChildren();
2279 _elementPool.Clear();
2280 _attributePool.Clear();
2281 _textPool.Clear();
2282 _commentPool.Clear();
2283 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002284 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002285}
2286
2287
PKEuS1c5f99e2013-07-06 11:28:39 +02002288void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002289{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002290 if ( streamer ) {
2291 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002292 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002293 else {
2294 XMLPrinter stdoutStreamer( stdout );
2295 Accept( &stdoutStreamer );
2296 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002297}
2298
2299
Lee Thomasonaa188392017-09-19 17:54:31 -07002300void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... )
Lee Thomason67d61312012-01-24 16:01:51 -08002301{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002302 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002303 _errorID = error;
Lee Thomasonaa188392017-09-19 17:54:31 -07002304 _errorStr.Reset();
Lee Thomason584af572016-09-05 14:14:16 -07002305
Lee Thomasonaa188392017-09-19 17:54:31 -07002306 if (format) {
2307 size_t BUFFER_SIZE = 1000;
2308 char* buffer = new char[BUFFER_SIZE];
2309 TIXML_SNPRINTF(buffer, BUFFER_SIZE, "Error=%s ErrorID=%d line=%d ", ErrorIDToName(error), int(error), lineNum);
2310 size_t len = strlen(buffer);
2311
2312 va_list va;
2313 va_start( va, format );
2314 int result = TIXML_VSNPRINTF( buffer + len, BUFFER_SIZE - len, format, va );
2315 va_end( va );
2316
2317 _errorStr.SetStr(buffer);
2318 delete [] buffer;
2319 }
Lee Thomason67d61312012-01-24 16:01:51 -08002320}
2321
Lee Thomasonaa188392017-09-19 17:54:31 -07002322
Lee Thomasone90e9012016-12-24 07:34:39 -08002323/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
Lee Thomason331596e2014-09-11 14:56:43 -07002324{
kezenator5a700712016-11-26 13:54:42 +10002325 TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2326 const char* errorName = _errorNames[errorID];
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002327 TIXMLASSERT( errorName && errorName[0] );
2328 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002329}
Lee Thomason5cae8972012-01-24 18:03:07 -08002330
Lee Thomasonaa188392017-09-19 17:54:31 -07002331const char* XMLDocument::GetErrorStr() const
Lee Thomason8c9e3132017-06-26 16:55:01 -07002332{
Lee Thomasonaa188392017-09-19 17:54:31 -07002333 return _errorStr.Empty() ? "" : _errorStr.GetStr();
Lee Thomason8c9e3132017-06-26 16:55:01 -07002334}
2335
kezenator5a700712016-11-26 13:54:42 +10002336const char* XMLDocument::ErrorName() const
2337{
Lee Thomasone90e9012016-12-24 07:34:39 -08002338 return ErrorIDToName(_errorID);
kezenator5a700712016-11-26 13:54:42 +10002339}
2340
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002341void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002342{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002343 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002344 static const int LEN = 20;
2345 char buf1[LEN] = { 0 };
2346 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002347
Lee Thomasonaa188392017-09-19 17:54:31 -07002348 if ( !_errorStr.Empty() ) {
2349 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002350 }
Dmitry-Me2ad43202015-04-16 12:18:58 +03002351 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2352 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2353 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
kezenatorec694152016-11-26 17:21:43 +10002354 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s line=%d\n",
2355 static_cast<int>( _errorID ), ErrorName(), buf1, buf2, _errorLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002356 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002357}
2358
Dmitry-Me97476b72015-01-01 16:15:57 +03002359void XMLDocument::Parse()
2360{
2361 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2362 TIXMLASSERT( _charBuffer );
kezenatorec694152016-11-26 17:21:43 +10002363 _parseCurLineNum = 1;
2364 _parseLineNum = 1;
Lee Thomason3cebdc42015-01-05 17:16:28 -08002365 char* p = _charBuffer;
kezenator4f756162016-11-29 19:46:27 +10002366 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mee28be752015-01-09 14:59:30 +03002367 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002368 if ( !*p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002369 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002370 return;
2371 }
kezenator4f756162016-11-29 19:46:27 +10002372 ParseDeep(p, 0, &_parseCurLineNum );
Dmitry-Me97476b72015-01-01 16:15:57 +03002373}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002374
PKEuS1bfb9542013-08-04 13:51:17 +02002375XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002376 _elementJustOpened( false ),
2377 _firstElement( true ),
2378 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002379 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002380 _textDepth( -1 ),
2381 _processEntities( true ),
2382 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002383{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002384 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002385 _entityFlag[i] = false;
2386 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002387 }
2388 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002389 const char entityValue = entities[i].value;
Dmitry-Mea28eb072017-08-25 18:34:18 +03002390 const unsigned char flagIndex = (unsigned char)entityValue;
2391 TIXMLASSERT( flagIndex < ENTITY_RANGE );
2392 _entityFlag[flagIndex] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002393 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002394 _restrictedEntityFlag[(unsigned char)'&'] = true;
2395 _restrictedEntityFlag[(unsigned char)'<'] = true;
2396 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002397 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002398}
2399
2400
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002401void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002402{
2403 va_list va;
2404 va_start( va, format );
2405
Lee Thomason624d43f2012-10-12 10:58:48 -07002406 if ( _fp ) {
2407 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002408 }
2409 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002410 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002411 // Close out and re-start the va-args
2412 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002413 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002414 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002415 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002416 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002417 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002418 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002419 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002420}
2421
2422
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002423void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002424{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002425 for( int i=0; i<depth; ++i ) {
2426 Print( " " );
2427 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002428}
2429
2430
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002431void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002432{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002433 // Look for runs of bytes between entities to print.
2434 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002435
Lee Thomason624d43f2012-10-12 10:58:48 -07002436 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002437 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002438 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002439 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002440 // Remember, char is sometimes signed. (How many times has that bitten me?)
2441 if ( *q > 0 && *q < ENTITY_RANGE ) {
2442 // Check for entities. If one is found, flush
2443 // the stream up until the entity, write the
2444 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002445 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002446 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002447 const size_t delta = q - p;
2448 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002449 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002450 Print( "%.*s", toPrint, p );
2451 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002452 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002453 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002454 for( int i=0; i<NUM_ENTITIES; ++i ) {
2455 if ( entities[i].value == *q ) {
2456 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002457 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002458 break;
2459 }
2460 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002461 if ( !entityPatternPrinted ) {
2462 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2463 TIXMLASSERT( false );
2464 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002465 ++p;
2466 }
2467 }
2468 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002469 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002470 }
2471 }
2472 // Flush the remaining string. This will be the entire
2473 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002474 TIXMLASSERT( p <= q );
2475 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002476 Print( "%s", p );
2477 }
Lee Thomason857b8682012-01-25 17:50:25 -08002478}
2479
U-Stream\Leeae25a442012-02-17 17:48:16 -08002480
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002481void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002482{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002483 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002484 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 -07002485 Print( "%s", bom );
2486 }
2487 if ( writeDec ) {
2488 PushDeclaration( "xml version=\"1.0\"" );
2489 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002490}
2491
2492
Uli Kusterer593a33d2014-02-01 12:48:51 +01002493void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002494{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002495 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002496 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002497
Uli Kusterer593a33d2014-02-01 12:48:51 +01002498 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002499 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002500 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002501 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002502 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002503 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002504
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002505 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002506 _elementJustOpened = true;
2507 _firstElement = false;
2508 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002509}
2510
2511
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002512void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002513{
Lee Thomason624d43f2012-10-12 10:58:48 -07002514 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002515 Print( " %s=\"", name );
2516 PrintString( value, false );
2517 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002518}
2519
2520
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002521void XMLPrinter::PushAttribute( const char* name, int v )
2522{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002523 char buf[BUF_SIZE];
2524 XMLUtil::ToStr( v, buf, BUF_SIZE );
2525 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002526}
2527
2528
2529void XMLPrinter::PushAttribute( const char* name, unsigned v )
2530{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002531 char buf[BUF_SIZE];
2532 XMLUtil::ToStr( v, buf, BUF_SIZE );
2533 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002534}
2535
2536
Lee Thomason51c12712016-06-04 20:18:49 -07002537void XMLPrinter::PushAttribute(const char* name, int64_t v)
2538{
2539 char buf[BUF_SIZE];
2540 XMLUtil::ToStr(v, buf, BUF_SIZE);
2541 PushAttribute(name, buf);
2542}
2543
2544
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002545void XMLPrinter::PushAttribute( const char* name, bool v )
2546{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002547 char buf[BUF_SIZE];
2548 XMLUtil::ToStr( v, buf, BUF_SIZE );
2549 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002550}
2551
2552
2553void XMLPrinter::PushAttribute( const char* name, double v )
2554{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002555 char buf[BUF_SIZE];
2556 XMLUtil::ToStr( v, buf, BUF_SIZE );
2557 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002558}
2559
2560
Uli Kustererca412e82014-02-01 13:35:05 +01002561void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002562{
Lee Thomason624d43f2012-10-12 10:58:48 -07002563 --_depth;
2564 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002565
Lee Thomason624d43f2012-10-12 10:58:48 -07002566 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002567 Print( "/>" );
2568 }
2569 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002570 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002571 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002572 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002573 }
2574 Print( "</%s>", name );
2575 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002576
Lee Thomason624d43f2012-10-12 10:58:48 -07002577 if ( _textDepth == _depth ) {
2578 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002579 }
Uli Kustererca412e82014-02-01 13:35:05 +01002580 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002581 Print( "\n" );
2582 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002583 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002584}
2585
2586
Dmitry-Mea092bc12014-12-23 17:57:05 +03002587void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002588{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002589 if ( !_elementJustOpened ) {
2590 return;
2591 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002592 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002593 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002594}
2595
2596
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002597void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002598{
Lee Thomason624d43f2012-10-12 10:58:48 -07002599 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002600
Dmitry-Mea092bc12014-12-23 17:57:05 +03002601 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002602 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002603 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002604 }
2605 else {
2606 PrintString( text, true );
2607 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002608}
2609
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002610void XMLPrinter::PushText( int64_t value )
2611{
2612 char buf[BUF_SIZE];
2613 XMLUtil::ToStr( value, buf, BUF_SIZE );
2614 PushText( buf, false );
2615}
2616
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002617void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002618{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002619 char buf[BUF_SIZE];
2620 XMLUtil::ToStr( value, buf, BUF_SIZE );
2621 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002622}
2623
2624
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002625void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002626{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002627 char buf[BUF_SIZE];
2628 XMLUtil::ToStr( value, buf, BUF_SIZE );
2629 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002630}
2631
2632
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002633void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002634{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002635 char buf[BUF_SIZE];
2636 XMLUtil::ToStr( value, buf, BUF_SIZE );
2637 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002638}
2639
2640
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002641void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002642{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002643 char buf[BUF_SIZE];
2644 XMLUtil::ToStr( value, buf, BUF_SIZE );
2645 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002646}
2647
2648
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002649void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002650{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002651 char buf[BUF_SIZE];
2652 XMLUtil::ToStr( value, buf, BUF_SIZE );
2653 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002654}
2655
Lee Thomason5cae8972012-01-24 18:03:07 -08002656
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002657void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002658{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002659 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002660 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002661 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002662 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002663 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002664 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002665 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002666}
Lee Thomason751da522012-02-10 08:50:51 -08002667
2668
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002669void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002670{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002671 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002672 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002673 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002674 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002675 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002676 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002677 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002678}
2679
2680
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002681void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002682{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002683 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002684 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002685 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002686 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002687 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002688 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002689 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002690}
2691
2692
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002693bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002694{
Lee Thomason624d43f2012-10-12 10:58:48 -07002695 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002696 if ( doc.HasBOM() ) {
2697 PushHeader( true, false );
2698 }
2699 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002700}
2701
2702
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002703bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002704{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002705 const XMLElement* parentElem = 0;
2706 if ( element.Parent() ) {
2707 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002708 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002709 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002710 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002711 while ( attribute ) {
2712 PushAttribute( attribute->Name(), attribute->Value() );
2713 attribute = attribute->Next();
2714 }
2715 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002716}
2717
2718
Uli Kustererca412e82014-02-01 13:35:05 +01002719bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002720{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002721 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002722 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002723}
2724
2725
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002726bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002727{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002728 PushText( text.Value(), text.CData() );
2729 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002730}
2731
2732
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002733bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002734{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002735 PushComment( comment.Value() );
2736 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002737}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002738
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002739bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002740{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002741 PushDeclaration( declaration.Value() );
2742 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002743}
2744
2745
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002746bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002747{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002748 PushUnknown( unknown.Value() );
2749 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002750}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002751
Lee Thomason685b8952012-11-12 13:00:06 -08002752} // namespace tinyxml2
2753