blob: 5de92b5cdf28a25b757dc42a90177bd43c7b2e3a [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 ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +0200745 _value(),
kezenatorec694152016-11-26 17:21:43 +1000746 _parseLineNum( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -0700747 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200748 _prev( 0 ), _next( 0 ),
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700749 _userData( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200750 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800751{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800752}
753
754
755XMLNode::~XMLNode()
756{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700757 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700758 if ( _parent ) {
759 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700760 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800761}
762
Michael Daumling21626882013-10-22 17:03:37 +0200763const char* XMLNode::Value() const
764{
Dmitry-Mecaa72a62016-08-10 17:34:34 +0300765 // Edge case: XMLDocuments don't have a Value. Return null.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530766 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530767 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200768 return _value.GetStr();
769}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800770
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800771void XMLNode::SetValue( const char* str, bool staticMem )
772{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700773 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700774 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700775 }
776 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700777 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700778 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800779}
780
Dmitry-Me3f63f212017-06-19 18:25:19 +0300781XMLNode* XMLNode::DeepClone(XMLDocument* target) const
Lee Thomason7085f002017-06-01 18:09:43 -0700782{
Dmitry-Me3f63f212017-06-19 18:25:19 +0300783 XMLNode* clone = this->ShallowClone(target);
Lee Thomason7085f002017-06-01 18:09:43 -0700784 if (!clone) return 0;
785
786 for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) {
Dmitry-Me3f63f212017-06-19 18:25:19 +0300787 XMLNode* childClone = child->DeepClone(target);
Lee Thomason7085f002017-06-01 18:09:43 -0700788 TIXMLASSERT(childClone);
789 clone->InsertEndChild(childClone);
790 }
791 return clone;
792}
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800793
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800794void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800795{
Lee Thomason624d43f2012-10-12 10:58:48 -0700796 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300797 TIXMLASSERT( _lastChild );
Dmitry-Me9cb4eca2016-08-18 18:10:59 +0300798 DeleteChild( _firstChild );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700799 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700800 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800801}
802
803
804void XMLNode::Unlink( XMLNode* child )
805{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300806 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300807 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300808 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700809 if ( child == _firstChild ) {
810 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700811 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700812 if ( child == _lastChild ) {
813 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700814 }
Lee Thomasond923c672012-01-23 08:44:25 -0800815
Lee Thomason624d43f2012-10-12 10:58:48 -0700816 if ( child->_prev ) {
817 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700818 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700819 if ( child->_next ) {
820 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700821 }
Lee Thomason8a763612017-06-16 09:30:16 -0700822 child->_next = 0;
823 child->_prev = 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700824 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800825}
826
827
U-Stream\Leeae25a442012-02-17 17:48:16 -0800828void XMLNode::DeleteChild( XMLNode* node )
829{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300830 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300831 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700832 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100833 Unlink( node );
Lee Thomason816d3fa2017-06-05 14:35:55 -0700834 TIXMLASSERT(node->_prev == 0);
835 TIXMLASSERT(node->_next == 0);
836 TIXMLASSERT(node->_parent == 0);
Dmitry-Mee3225b12014-09-03 11:03:11 +0400837 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800838}
839
840
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800841XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
842{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300843 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300844 if ( addThis->_document != _document ) {
845 TIXMLASSERT( false );
846 return 0;
847 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800848 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700849
Lee Thomason624d43f2012-10-12 10:58:48 -0700850 if ( _lastChild ) {
851 TIXMLASSERT( _firstChild );
852 TIXMLASSERT( _lastChild->_next == 0 );
853 _lastChild->_next = addThis;
854 addThis->_prev = _lastChild;
855 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800856
Lee Thomason624d43f2012-10-12 10:58:48 -0700857 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700858 }
859 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700860 TIXMLASSERT( _firstChild == 0 );
861 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800862
Lee Thomason624d43f2012-10-12 10:58:48 -0700863 addThis->_prev = 0;
864 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700865 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700866 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700867 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800868}
869
870
Lee Thomason1ff38e02012-02-14 18:18:16 -0800871XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
872{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300873 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300874 if ( addThis->_document != _document ) {
875 TIXMLASSERT( false );
876 return 0;
877 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800878 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700879
Lee Thomason624d43f2012-10-12 10:58:48 -0700880 if ( _firstChild ) {
881 TIXMLASSERT( _lastChild );
882 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800883
Lee Thomason624d43f2012-10-12 10:58:48 -0700884 _firstChild->_prev = addThis;
885 addThis->_next = _firstChild;
886 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800887
Lee Thomason624d43f2012-10-12 10:58:48 -0700888 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700889 }
890 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700891 TIXMLASSERT( _lastChild == 0 );
892 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800893
Lee Thomason624d43f2012-10-12 10:58:48 -0700894 addThis->_prev = 0;
895 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700896 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700897 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400898 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800899}
900
901
902XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
903{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300904 TIXMLASSERT( addThis );
905 if ( addThis->_document != _document ) {
906 TIXMLASSERT( false );
907 return 0;
908 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700909
Dmitry-Meabb2d042014-12-09 12:59:31 +0300910 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700911
Lee Thomason624d43f2012-10-12 10:58:48 -0700912 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300913 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700914 return 0;
915 }
Dmitry-Mee8f4a8b2017-09-15 19:34:36 +0300916 if ( afterThis == addThis ) {
917 // Current state: BeforeThis -> AddThis -> OneAfterAddThis
918 // Now AddThis must disappear from it's location and then
919 // reappear between BeforeThis and OneAfterAddThis.
920 // So just leave it where it is.
921 return addThis;
922 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800923
Lee Thomason624d43f2012-10-12 10:58:48 -0700924 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700925 // The last node or the only node.
926 return InsertEndChild( addThis );
927 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800928 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700929 addThis->_prev = afterThis;
930 addThis->_next = afterThis->_next;
931 afterThis->_next->_prev = addThis;
932 afterThis->_next = addThis;
933 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700934 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800935}
936
937
938
939
Dmitry-Me886ad972015-07-22 11:00:51 +0300940const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800941{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300942 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300943 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700944 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300945 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700946 }
947 }
948 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800949}
950
951
Dmitry-Me886ad972015-07-22 11:00:51 +0300952const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800953{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300954 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300955 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700956 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300957 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700958 }
959 }
960 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800961}
962
963
Dmitry-Me886ad972015-07-22 11:00:51 +0300964const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800965{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300966 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300967 const XMLElement* element = node->ToElementWithName( name );
968 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400969 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700970 }
971 }
972 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800973}
974
975
Dmitry-Me886ad972015-07-22 11:00:51 +0300976const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800977{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300978 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300979 const XMLElement* element = node->ToElementWithName( name );
980 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400981 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700982 }
983 }
984 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800985}
986
987
Dmitry-Me10b8ecc2017-04-12 17:57:44 +0300988char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -0800989{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700990 // This is a recursive method, but thinking about it "at the current level"
991 // it is a pretty simple flat list:
992 // <foo/>
993 // <!-- comment -->
994 //
995 // With a special case:
996 // <foo>
997 // </foo>
998 // <!-- comment -->
999 //
1000 // Where the closing element (/foo) *must* be the next thing after the opening
1001 // element, and the names must match. BUT the tricky bit is that the closing
1002 // element will be read by the child.
1003 //
1004 // 'endTag' is the end tag for this node, it is returned by a call to a child.
1005 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001006
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001007 while( p && *p ) {
1008 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -08001009
Lee Thomason624d43f2012-10-12 10:58:48 -07001010 p = _document->Identify( p, &node );
Dmitry-Me43364312016-11-07 18:48:50 +03001011 TIXMLASSERT( p );
Dmitry-Me9fcb8762015-03-05 17:53:34 +03001012 if ( node == 0 ) {
1013 break;
1014 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001015
kezenatore3531812016-11-29 19:49:07 +10001016 int initialLineNum = node->_parseLineNum;
kezenatorec694152016-11-26 17:21:43 +10001017
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001018 StrPair endTag;
kezenator4f756162016-11-29 19:46:27 +10001019 p = node->ParseDeep( p, &endTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001020 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001021 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -07001022 if ( !_document->Error() ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001023 _document->SetError( XML_ERROR_PARSING, initialLineNum, 0);
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001024 }
1025 break;
1026 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001027
Sarat Addepalli3df007e2015-05-20 10:43:51 +05301028 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301029 if ( decl ) {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001030 // Declarations are only allowed at document level
1031 bool wellLocated = ( ToDocument() != 0 );
1032 if ( wellLocated ) {
1033 // Multiple declarations are allowed but all declarations
1034 // must occur before anything else
1035 for ( const XMLNode* existingNode = _document->FirstChild(); existingNode; existingNode = existingNode->NextSibling() ) {
1036 if ( !existingNode->ToDeclaration() ) {
1037 wellLocated = false;
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301038 break;
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001039 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301040 }
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001041 }
1042 if ( !wellLocated ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07001043 _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, "XMLDeclaration value=%s", decl->Value());
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001044 DeleteNode( node );
1045 break;
1046 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301047 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301048
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001049 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001050 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -05001051 // We read the end tag. Return it to the parent.
1052 if ( ele->ClosingType() == XMLElement::CLOSING ) {
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001053 if ( parentEndTag ) {
1054 ele->_value.TransferTo( parentEndTag );
JayXone4bf6e32014-12-26 01:00:24 -05001055 }
1056 node->_memPool->SetTracked(); // created and then immediately deleted.
1057 DeleteNode( node );
1058 return p;
1059 }
1060
1061 // Handle an end tag returned to this level.
1062 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001063 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001064 if ( endTag.Empty() ) {
1065 if ( ele->ClosingType() == XMLElement::OPEN ) {
1066 mismatch = true;
1067 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001068 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001069 else {
1070 if ( ele->ClosingType() != XMLElement::OPEN ) {
1071 mismatch = true;
1072 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001073 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001074 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001075 }
1076 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001077 if ( mismatch ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07001078 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, "XMLElement name=%s", ele->Name());
JayXondbfdd8f2014-12-12 20:07:14 -05001079 DeleteNode( node );
1080 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001081 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001082 }
JayXondbfdd8f2014-12-12 20:07:14 -05001083 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001084 }
1085 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001086}
1087
Lee Thomason816d3fa2017-06-05 14:35:55 -07001088/*static*/ void XMLNode::DeleteNode( XMLNode* node )
Dmitry-Mee3225b12014-09-03 11:03:11 +04001089{
1090 if ( node == 0 ) {
1091 return;
1092 }
Lee Thomason816d3fa2017-06-05 14:35:55 -07001093 TIXMLASSERT(node->_document);
1094 if (!node->ToDocument()) {
1095 node->_document->MarkInUse(node);
1096 }
1097
Dmitry-Mee3225b12014-09-03 11:03:11 +04001098 MemPool* pool = node->_memPool;
1099 node->~XMLNode();
1100 pool->Free( node );
1101}
1102
Lee Thomason3cebdc42015-01-05 17:16:28 -08001103void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001104{
1105 TIXMLASSERT( insertThis );
1106 TIXMLASSERT( insertThis->_document == _document );
1107
Lee Thomason816d3fa2017-06-05 14:35:55 -07001108 if (insertThis->_parent) {
Dmitry-Me74e39402015-01-01 16:26:17 +03001109 insertThis->_parent->Unlink( insertThis );
Lee Thomason816d3fa2017-06-05 14:35:55 -07001110 }
1111 else {
1112 insertThis->_document->MarkInUse(insertThis);
Dmitry-Me74e39402015-01-01 16:26:17 +03001113 insertThis->_memPool->SetTracked();
Lee Thomason816d3fa2017-06-05 14:35:55 -07001114 }
Dmitry-Me74e39402015-01-01 16:26:17 +03001115}
1116
Dmitry-Meecb9b072016-10-12 16:44:59 +03001117const XMLElement* XMLNode::ToElementWithName( const char* name ) const
1118{
1119 const XMLElement* element = this->ToElement();
1120 if ( element == 0 ) {
1121 return 0;
1122 }
1123 if ( name == 0 ) {
1124 return element;
1125 }
1126 if ( XMLUtil::StringEqual( element->Name(), name ) ) {
1127 return element;
1128 }
1129 return 0;
1130}
1131
Lee Thomason5492a1c2012-01-23 15:32:10 -08001132// --------- XMLText ---------- //
kezenator4f756162016-11-29 19:46:27 +10001133char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001134{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001135 const char* start = p;
1136 if ( this->CData() ) {
kezenator4f756162016-11-29 19:46:27 +10001137 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001138 if ( !p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001139 _document->SetError( XML_ERROR_PARSING_CDATA, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001140 }
1141 return p;
1142 }
1143 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001144 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1145 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001146 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001147 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001148
kezenator4f756162016-11-29 19:46:27 +10001149 p = _value.ParseText( p, "<", flags, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001150 if ( p && *p ) {
1151 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001152 }
1153 if ( !p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001154 _document->SetError( XML_ERROR_PARSING_TEXT, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001155 }
1156 }
1157 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001158}
1159
1160
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001161XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1162{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001163 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001164 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001165 }
1166 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1167 text->SetCData( this->CData() );
1168 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001169}
1170
1171
1172bool XMLText::ShallowEqual( const XMLNode* compare ) const
1173{
Dmitry-Meba68a3a2017-03-21 11:39:48 +03001174 TIXMLASSERT( compare );
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001175 const XMLText* text = compare->ToText();
1176 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001177}
1178
1179
Lee Thomason56bdd022012-02-09 18:16:58 -08001180bool XMLText::Accept( XMLVisitor* visitor ) const
1181{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001182 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001183 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001184}
1185
1186
Lee Thomason3f57d272012-01-11 15:30:03 -08001187// --------- XMLComment ---------- //
1188
Lee Thomasone4422302012-01-20 17:59:50 -08001189XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001190{
1191}
1192
1193
Lee Thomasonce0763e2012-01-11 15:43:54 -08001194XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001195{
Lee Thomason3f57d272012-01-11 15:30:03 -08001196}
1197
1198
kezenator4f756162016-11-29 19:46:27 +10001199char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason3f57d272012-01-11 15:30:03 -08001200{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001201 // Comment parses as text.
1202 const char* start = p;
kezenator4f756162016-11-29 19:46:27 +10001203 p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001204 if ( p == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001205 _document->SetError( XML_ERROR_PARSING_COMMENT, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001206 }
1207 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001208}
1209
1210
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001211XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1212{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001213 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001214 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001215 }
1216 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1217 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001218}
1219
1220
1221bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1222{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001223 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001224 const XMLComment* comment = compare->ToComment();
1225 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001226}
1227
1228
Lee Thomason751da522012-02-10 08:50:51 -08001229bool XMLComment::Accept( XMLVisitor* visitor ) const
1230{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001231 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001232 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001233}
Lee Thomason56bdd022012-02-09 18:16:58 -08001234
1235
Lee Thomason50f97b22012-02-11 16:33:40 -08001236// --------- XMLDeclaration ---------- //
1237
1238XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1239{
1240}
1241
1242
1243XMLDeclaration::~XMLDeclaration()
1244{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001245 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001246}
1247
1248
kezenator4f756162016-11-29 19:46:27 +10001249char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001250{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001251 // Declaration parses as text.
1252 const char* start = p;
kezenator4f756162016-11-29 19:46:27 +10001253 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001254 if ( p == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001255 _document->SetError( XML_ERROR_PARSING_DECLARATION, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001256 }
1257 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001258}
1259
1260
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001261XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1262{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001263 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001264 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001265 }
1266 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1267 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001268}
1269
1270
1271bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1272{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001273 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001274 const XMLDeclaration* declaration = compare->ToDeclaration();
1275 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001276}
1277
1278
1279
Lee Thomason50f97b22012-02-11 16:33:40 -08001280bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1281{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001282 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001283 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001284}
1285
1286// --------- XMLUnknown ---------- //
1287
1288XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1289{
1290}
1291
1292
1293XMLUnknown::~XMLUnknown()
1294{
1295}
1296
1297
kezenator4f756162016-11-29 19:46:27 +10001298char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001299{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001300 // Unknown parses as text.
1301 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001302
kezenator4f756162016-11-29 19:46:27 +10001303 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001304 if ( !p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001305 _document->SetError( XML_ERROR_PARSING_UNKNOWN, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001306 }
1307 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001308}
1309
1310
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001311XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1312{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001313 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001314 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001315 }
1316 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1317 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001318}
1319
1320
1321bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1322{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001323 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001324 const XMLUnknown* unknown = compare->ToUnknown();
1325 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001326}
1327
1328
Lee Thomason50f97b22012-02-11 16:33:40 -08001329bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1330{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001331 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001332 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001333}
1334
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001335// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001336
1337const char* XMLAttribute::Name() const
1338{
1339 return _name.GetStr();
1340}
1341
1342const char* XMLAttribute::Value() const
1343{
1344 return _value.GetStr();
1345}
1346
kezenator4f756162016-11-29 19:46:27 +10001347char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001348{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001349 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001350 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001351 if ( !p || !*p ) {
1352 return 0;
1353 }
Lee Thomason22aead12012-01-23 13:29:35 -08001354
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001355 // Skip white space before =
kezenator4f756162016-11-29 19:46:27 +10001356 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001357 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001358 return 0;
1359 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001360
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001361 ++p; // move up to opening quote
kezenator4f756162016-11-29 19:46:27 +10001362 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001363 if ( *p != '\"' && *p != '\'' ) {
1364 return 0;
1365 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001366
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001367 char endTag[2] = { *p, 0 };
1368 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001369
kezenator4f756162016-11-29 19:46:27 +10001370 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001371 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001372}
1373
1374
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001375void XMLAttribute::SetName( const char* n )
1376{
Lee Thomason624d43f2012-10-12 10:58:48 -07001377 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001378}
1379
1380
Lee Thomason2fa81722012-11-09 12:37:46 -08001381XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001382{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001383 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001384 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001385 }
1386 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001387}
1388
1389
Lee Thomason2fa81722012-11-09 12:37:46 -08001390XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001391{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001392 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001393 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001394 }
1395 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001396}
1397
1398
Lee Thomason51c12712016-06-04 20:18:49 -07001399XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1400{
1401 if (XMLUtil::ToInt64(Value(), value)) {
1402 return XML_SUCCESS;
1403 }
1404 return XML_WRONG_ATTRIBUTE_TYPE;
1405}
1406
1407
Lee Thomason2fa81722012-11-09 12:37:46 -08001408XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001409{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001410 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001411 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001412 }
1413 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001414}
1415
1416
Lee Thomason2fa81722012-11-09 12:37:46 -08001417XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001418{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001419 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001420 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001421 }
1422 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001423}
1424
1425
Lee Thomason2fa81722012-11-09 12:37:46 -08001426XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001427{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001428 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001429 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001430 }
1431 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001432}
1433
1434
1435void XMLAttribute::SetAttribute( const char* v )
1436{
Lee Thomason624d43f2012-10-12 10:58:48 -07001437 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001438}
1439
1440
Lee Thomason1ff38e02012-02-14 18:18:16 -08001441void XMLAttribute::SetAttribute( int v )
1442{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001443 char buf[BUF_SIZE];
1444 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001445 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001446}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001447
1448
1449void XMLAttribute::SetAttribute( unsigned v )
1450{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001451 char buf[BUF_SIZE];
1452 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001453 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001454}
1455
1456
Lee Thomason51c12712016-06-04 20:18:49 -07001457void XMLAttribute::SetAttribute(int64_t v)
1458{
1459 char buf[BUF_SIZE];
1460 XMLUtil::ToStr(v, buf, BUF_SIZE);
1461 _value.SetStr(buf);
1462}
1463
1464
1465
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001466void XMLAttribute::SetAttribute( bool v )
1467{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001468 char buf[BUF_SIZE];
1469 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001470 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001471}
1472
1473void XMLAttribute::SetAttribute( double v )
1474{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001475 char buf[BUF_SIZE];
1476 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001477 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001478}
1479
1480void XMLAttribute::SetAttribute( float v )
1481{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001482 char buf[BUF_SIZE];
1483 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001484 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001485}
1486
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001487
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001488// --------- XMLElement ---------- //
1489XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Dmitry-Mee5035632017-04-05 18:02:40 +03001490 _closingType( OPEN ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001491 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001492{
1493}
1494
1495
1496XMLElement::~XMLElement()
1497{
Lee Thomason624d43f2012-10-12 10:58:48 -07001498 while( _rootAttribute ) {
1499 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001500 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001501 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001502 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001503}
1504
1505
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001506const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1507{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001508 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001509 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1510 return a;
1511 }
1512 }
1513 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001514}
1515
1516
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001517const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001518{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001519 const XMLAttribute* a = FindAttribute( name );
1520 if ( !a ) {
1521 return 0;
1522 }
1523 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1524 return a->Value();
1525 }
1526 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001527}
1528
Josh Wittnercf3dd092016-10-11 18:57:17 -07001529int XMLElement::IntAttribute(const char* name, int defaultValue) const
1530{
1531 int i = defaultValue;
1532 QueryIntAttribute(name, &i);
1533 return i;
1534}
1535
1536unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
1537{
1538 unsigned i = defaultValue;
1539 QueryUnsignedAttribute(name, &i);
1540 return i;
1541}
1542
1543int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
1544{
1545 int64_t i = defaultValue;
1546 QueryInt64Attribute(name, &i);
1547 return i;
1548}
1549
1550bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
1551{
1552 bool b = defaultValue;
1553 QueryBoolAttribute(name, &b);
1554 return b;
1555}
1556
1557double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
1558{
1559 double d = defaultValue;
1560 QueryDoubleAttribute(name, &d);
1561 return d;
1562}
1563
1564float XMLElement::FloatAttribute(const char* name, float defaultValue) const
1565{
1566 float f = defaultValue;
1567 QueryFloatAttribute(name, &f);
1568 return f;
1569}
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001570
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001571const char* XMLElement::GetText() const
1572{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001573 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001574 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001575 }
1576 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001577}
1578
1579
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001580void XMLElement::SetText( const char* inText )
1581{
Uli Kusterer869bb592014-01-21 01:36:16 +01001582 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001583 FirstChild()->SetValue( inText );
1584 else {
1585 XMLText* theText = GetDocument()->NewText( inText );
1586 InsertFirstChild( theText );
1587 }
1588}
1589
Lee Thomason5bb2d802014-01-24 10:42:57 -08001590
1591void XMLElement::SetText( int v )
1592{
1593 char buf[BUF_SIZE];
1594 XMLUtil::ToStr( v, buf, BUF_SIZE );
1595 SetText( buf );
1596}
1597
1598
1599void XMLElement::SetText( unsigned v )
1600{
1601 char buf[BUF_SIZE];
1602 XMLUtil::ToStr( v, buf, BUF_SIZE );
1603 SetText( buf );
1604}
1605
1606
Lee Thomason51c12712016-06-04 20:18:49 -07001607void XMLElement::SetText(int64_t v)
1608{
1609 char buf[BUF_SIZE];
1610 XMLUtil::ToStr(v, buf, BUF_SIZE);
1611 SetText(buf);
1612}
1613
1614
1615void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001616{
1617 char buf[BUF_SIZE];
1618 XMLUtil::ToStr( v, buf, BUF_SIZE );
1619 SetText( buf );
1620}
1621
1622
1623void XMLElement::SetText( float v )
1624{
1625 char buf[BUF_SIZE];
1626 XMLUtil::ToStr( v, buf, BUF_SIZE );
1627 SetText( buf );
1628}
1629
1630
1631void XMLElement::SetText( double v )
1632{
1633 char buf[BUF_SIZE];
1634 XMLUtil::ToStr( v, buf, BUF_SIZE );
1635 SetText( buf );
1636}
1637
1638
MortenMacFly4ee49f12013-01-14 20:03:14 +01001639XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001640{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001641 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001642 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001643 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001644 return XML_SUCCESS;
1645 }
1646 return XML_CAN_NOT_CONVERT_TEXT;
1647 }
1648 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001649}
1650
1651
MortenMacFly4ee49f12013-01-14 20:03:14 +01001652XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001653{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001654 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001655 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001656 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001657 return XML_SUCCESS;
1658 }
1659 return XML_CAN_NOT_CONVERT_TEXT;
1660 }
1661 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001662}
1663
1664
Lee Thomason51c12712016-06-04 20:18:49 -07001665XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1666{
1667 if (FirstChild() && FirstChild()->ToText()) {
1668 const char* t = FirstChild()->Value();
1669 if (XMLUtil::ToInt64(t, ival)) {
1670 return XML_SUCCESS;
1671 }
1672 return XML_CAN_NOT_CONVERT_TEXT;
1673 }
1674 return XML_NO_TEXT_NODE;
1675}
1676
1677
MortenMacFly4ee49f12013-01-14 20:03:14 +01001678XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001679{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001680 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001681 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001682 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001683 return XML_SUCCESS;
1684 }
1685 return XML_CAN_NOT_CONVERT_TEXT;
1686 }
1687 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001688}
1689
1690
MortenMacFly4ee49f12013-01-14 20:03:14 +01001691XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001692{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001693 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001694 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001695 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001696 return XML_SUCCESS;
1697 }
1698 return XML_CAN_NOT_CONVERT_TEXT;
1699 }
1700 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001701}
1702
1703
MortenMacFly4ee49f12013-01-14 20:03:14 +01001704XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001705{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001706 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001707 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001708 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001709 return XML_SUCCESS;
1710 }
1711 return XML_CAN_NOT_CONVERT_TEXT;
1712 }
1713 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001714}
1715
Josh Wittnercf3dd092016-10-11 18:57:17 -07001716int XMLElement::IntText(int defaultValue) const
1717{
1718 int i = defaultValue;
1719 QueryIntText(&i);
1720 return i;
1721}
1722
1723unsigned XMLElement::UnsignedText(unsigned defaultValue) const
1724{
1725 unsigned i = defaultValue;
1726 QueryUnsignedText(&i);
1727 return i;
1728}
1729
1730int64_t XMLElement::Int64Text(int64_t defaultValue) const
1731{
1732 int64_t i = defaultValue;
1733 QueryInt64Text(&i);
1734 return i;
1735}
1736
1737bool XMLElement::BoolText(bool defaultValue) const
1738{
1739 bool b = defaultValue;
1740 QueryBoolText(&b);
1741 return b;
1742}
1743
1744double XMLElement::DoubleText(double defaultValue) const
1745{
1746 double d = defaultValue;
1747 QueryDoubleText(&d);
1748 return d;
1749}
1750
1751float XMLElement::FloatText(float defaultValue) const
1752{
1753 float f = defaultValue;
1754 QueryFloatText(&f);
1755 return f;
1756}
Lee Thomason21be8822012-07-15 17:27:22 -07001757
1758
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001759XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1760{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001761 XMLAttribute* last = 0;
1762 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001763 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001764 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001765 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001766 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1767 break;
1768 }
1769 }
1770 if ( !attrib ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001771 attrib = CreateAttribute();
1772 TIXMLASSERT( attrib );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001773 if ( last ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001774 TIXMLASSERT( last->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001775 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001776 }
1777 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001778 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001779 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001780 }
1781 attrib->SetName( name );
1782 }
1783 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001784}
1785
1786
U-Stream\Leeae25a442012-02-17 17:48:16 -08001787void XMLElement::DeleteAttribute( const char* name )
1788{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001789 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001790 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001791 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1792 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001793 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001794 }
1795 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001796 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001797 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001798 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001799 break;
1800 }
1801 prev = a;
1802 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001803}
1804
1805
kezenator4f756162016-11-29 19:46:27 +10001806char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001807{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001808 const char* start = p;
1809 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001810
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001811 // Read the attributes.
1812 while( p ) {
kezenator4f756162016-11-29 19:46:27 +10001813 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001814 if ( !(*p) ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07001815 _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, "XMLElement name=%s", Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001816 return 0;
1817 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001818
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001819 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001820 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001821 XMLAttribute* attrib = CreateAttribute();
1822 TIXMLASSERT( attrib );
kezenatorec694152016-11-26 17:21:43 +10001823 attrib->_parseLineNum = _document->_parseCurLineNum;
Lee Thomasond1983222012-02-06 08:41:24 -08001824
kezenatorec694152016-11-26 17:21:43 +10001825 int attrLineNum = attrib->_parseLineNum;
1826
kezenator4f756162016-11-29 19:46:27 +10001827 p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001828 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001829 DeleteAttribute( attrib );
Lee Thomasonf49b9652017-10-11 10:57:49 -07001830 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, attrLineNum, "XMLElement name=%s", Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001831 return 0;
1832 }
1833 // There is a minor bug here: if the attribute in the source xml
1834 // document is duplicated, it will not be detected and the
1835 // attribute will be doubly added. However, tracking the 'prevAttribute'
1836 // avoids re-scanning the attribute list. Preferring performance for
1837 // now, may reconsider in the future.
1838 if ( prevAttribute ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001839 TIXMLASSERT( prevAttribute->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001840 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001841 }
1842 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001843 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001844 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001845 }
1846 prevAttribute = attrib;
1847 }
1848 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001849 else if ( *p == '>' ) {
1850 ++p;
1851 break;
1852 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001853 // end of the tag
1854 else if ( *p == '/' && *(p+1) == '>' ) {
1855 _closingType = CLOSED;
1856 return p+2; // done; sealed element.
1857 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001858 else {
Lee Thomasonaa188392017-09-19 17:54:31 -07001859 _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001860 return 0;
1861 }
1862 }
1863 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001864}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001865
Dmitry-Mee3225b12014-09-03 11:03:11 +04001866void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1867{
1868 if ( attribute == 0 ) {
1869 return;
1870 }
1871 MemPool* pool = attribute->_memPool;
1872 attribute->~XMLAttribute();
1873 pool->Free( attribute );
1874}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001875
Dmitry-Mea60caa22016-11-22 18:28:08 +03001876XMLAttribute* XMLElement::CreateAttribute()
1877{
1878 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
1879 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
Dmitry-Me7221b492017-03-03 15:45:51 +03001880 TIXMLASSERT( attrib );
Dmitry-Mea60caa22016-11-22 18:28:08 +03001881 attrib->_memPool = &_document->_attributePool;
1882 attrib->_memPool->SetTracked();
1883 return attrib;
1884}
1885
Lee Thomason67d61312012-01-24 16:01:51 -08001886//
1887// <ele></ele>
1888// <ele>foo<b>bar</b></ele>
1889//
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001890char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -08001891{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001892 // Read the element name.
kezenator4f756162016-11-29 19:46:27 +10001893 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomason67d61312012-01-24 16:01:51 -08001894
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001895 // The closing element is the </element> form. It is
1896 // parsed just like a regular element then deleted from
1897 // the DOM.
1898 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001899 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001900 ++p;
1901 }
Lee Thomason67d61312012-01-24 16:01:51 -08001902
Lee Thomason624d43f2012-10-12 10:58:48 -07001903 p = _value.ParseName( p );
1904 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001905 return 0;
1906 }
Lee Thomason67d61312012-01-24 16:01:51 -08001907
kezenator4f756162016-11-29 19:46:27 +10001908 p = ParseAttributes( p, curLineNumPtr );
Dmitry-Mee5035632017-04-05 18:02:40 +03001909 if ( !p || !*p || _closingType != OPEN ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001910 return p;
1911 }
Lee Thomason67d61312012-01-24 16:01:51 -08001912
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001913 p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001914 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001915}
1916
1917
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001918
1919XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1920{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001921 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001922 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001923 }
1924 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1925 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1926 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1927 }
1928 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001929}
1930
1931
1932bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1933{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001934 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001935 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001936 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001937
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001938 const XMLAttribute* a=FirstAttribute();
1939 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001940
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001941 while ( a && b ) {
1942 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1943 return false;
1944 }
1945 a = a->Next();
1946 b = b->Next();
1947 }
1948 if ( a || b ) {
1949 // different count
1950 return false;
1951 }
1952 return true;
1953 }
1954 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001955}
1956
1957
Lee Thomason751da522012-02-10 08:50:51 -08001958bool XMLElement::Accept( XMLVisitor* visitor ) const
1959{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001960 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001961 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001962 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1963 if ( !node->Accept( visitor ) ) {
1964 break;
1965 }
1966 }
1967 }
1968 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001969}
Lee Thomason56bdd022012-02-09 18:16:58 -08001970
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001971
Lee Thomason3f57d272012-01-11 15:30:03 -08001972// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001973
1974// Warning: List must match 'enum XMLError'
1975const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1976 "XML_SUCCESS",
1977 "XML_NO_ATTRIBUTE",
1978 "XML_WRONG_ATTRIBUTE_TYPE",
1979 "XML_ERROR_FILE_NOT_FOUND",
1980 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1981 "XML_ERROR_FILE_READ_ERROR",
Lee Thomason8bba8b42017-06-20 09:18:41 -07001982 "UNUSED_XML_ERROR_ELEMENT_MISMATCH",
Lee Thomason331596e2014-09-11 14:56:43 -07001983 "XML_ERROR_PARSING_ELEMENT",
1984 "XML_ERROR_PARSING_ATTRIBUTE",
Lee Thomason8bba8b42017-06-20 09:18:41 -07001985 "UNUSED_XML_ERROR_IDENTIFYING_TAG",
Lee Thomason331596e2014-09-11 14:56:43 -07001986 "XML_ERROR_PARSING_TEXT",
1987 "XML_ERROR_PARSING_CDATA",
1988 "XML_ERROR_PARSING_COMMENT",
1989 "XML_ERROR_PARSING_DECLARATION",
1990 "XML_ERROR_PARSING_UNKNOWN",
1991 "XML_ERROR_EMPTY_DOCUMENT",
1992 "XML_ERROR_MISMATCHED_ELEMENT",
1993 "XML_ERROR_PARSING",
1994 "XML_CAN_NOT_CONVERT_TEXT",
1995 "XML_NO_TEXT_NODE"
1996};
1997
1998
Dmitry-Meae8a82a2017-03-03 15:40:32 +03001999XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002000 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002001 _writeBOM( false ),
2002 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07002003 _errorID(XML_SUCCESS),
Dmitry-Meae8a82a2017-03-03 15:40:32 +03002004 _whitespaceMode( whitespaceMode ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002005 _errorStr1(),
2006 _errorStr2(),
Dmitry-Mef89bd3e2017-01-18 18:33:55 +03002007 _errorLineNum( 0 ),
2008 _charBuffer( 0 ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002009 _parseCurLineNum( 0 ),
2010 _unlinked(),
2011 _elementPool(),
2012 _attributePool(),
2013 _textPool(),
2014 _commentPool()
U-Lama\Lee560bd472011-12-28 19:42:49 -08002015{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03002016 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
2017 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08002018}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002019
2020
Lee Thomason3f57d272012-01-11 15:30:03 -08002021XMLDocument::~XMLDocument()
2022{
Lee Thomasonf07b9522014-10-30 13:25:12 -07002023 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08002024}
2025
2026
Lee Thomason816d3fa2017-06-05 14:35:55 -07002027void XMLDocument::MarkInUse(XMLNode* node)
2028{
Dmitry-Mec2f677b2017-06-15 12:44:27 +03002029 TIXMLASSERT(node);
Lee Thomason816d3fa2017-06-05 14:35:55 -07002030 TIXMLASSERT(node->_parent == 0);
2031
2032 for (int i = 0; i < _unlinked.Size(); ++i) {
2033 if (node == _unlinked[i]) {
2034 _unlinked.SwapRemove(i);
2035 break;
2036 }
2037 }
2038}
2039
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002040void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08002041{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002042 DeleteChildren();
Lee Thomason816d3fa2017-06-05 14:35:55 -07002043 while( _unlinked.Size()) {
2044 DeleteNode(_unlinked[0]); // Will remove from _unlinked as part of delete.
2045 }
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002046
Dmitry-Meab37df82014-11-28 12:08:36 +03002047#ifdef DEBUG
2048 const bool hadError = Error();
2049#endif
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002050 ClearError();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002051
Lee Thomason624d43f2012-10-12 10:58:48 -07002052 delete [] _charBuffer;
2053 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07002054
2055#if 0
2056 _textPool.Trace( "text" );
2057 _elementPool.Trace( "element" );
2058 _commentPool.Trace( "comment" );
2059 _attributePool.Trace( "attribute" );
2060#endif
2061
2062#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002063 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002064 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
2065 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
2066 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
2067 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
2068 }
2069#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08002070}
2071
Lee Thomason3f57d272012-01-11 15:30:03 -08002072
Shuichiro Suzuki87cd4e02017-08-24 11:20:26 +09002073void XMLDocument::DeepCopy(XMLDocument* target) const
Lee Thomason7085f002017-06-01 18:09:43 -07002074{
2075 TIXMLASSERT(target);
Lee Thomason1346a172017-06-14 15:14:19 -07002076 if (target == this) {
2077 return; // technically success - a no-op.
2078 }
Lee Thomason7085f002017-06-01 18:09:43 -07002079
2080 target->Clear();
2081 for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {
2082 target->InsertEndChild(node->DeepClone(target));
2083 }
2084}
2085
Lee Thomason2c85a712012-01-31 08:24:24 -08002086XMLElement* XMLDocument::NewElement( const char* name )
2087{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002088 XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002089 ele->SetName( name );
2090 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08002091}
2092
2093
Lee Thomason1ff38e02012-02-14 18:18:16 -08002094XMLComment* XMLDocument::NewComment( const char* str )
2095{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002096 XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002097 comment->SetValue( str );
2098 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002099}
2100
2101
2102XMLText* XMLDocument::NewText( const char* str )
2103{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002104 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002105 text->SetValue( str );
2106 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002107}
2108
2109
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002110XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2111{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002112 XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002113 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2114 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002115}
2116
2117
2118XMLUnknown* XMLDocument::NewUnknown( const char* str )
2119{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002120 XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002121 unk->SetValue( str );
2122 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002123}
2124
Dmitry-Me01578db2014-08-19 10:18:48 +04002125static FILE* callfopen( const char* filepath, const char* mode )
2126{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002127 TIXMLASSERT( filepath );
2128 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002129#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2130 FILE* fp = 0;
2131 errno_t err = fopen_s( &fp, filepath, mode );
2132 if ( err ) {
2133 return 0;
2134 }
2135#else
2136 FILE* fp = fopen( filepath, mode );
2137#endif
2138 return fp;
2139}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08002140
2141void XMLDocument::DeleteNode( XMLNode* node ) {
2142 TIXMLASSERT( node );
2143 TIXMLASSERT(node->_document == this );
2144 if (node->_parent) {
2145 node->_parent->DeleteChild( node );
2146 }
2147 else {
2148 // Isn't in the tree.
2149 // Use the parent delete.
2150 // Also, we need to mark it tracked: we 'know'
2151 // it was never used.
2152 node->_memPool->SetTracked();
2153 // Call the static XMLNode version:
2154 XMLNode::DeleteNode(node);
2155 }
2156}
2157
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002158
Lee Thomason2fa81722012-11-09 12:37:46 -08002159XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002160{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002161 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04002162 FILE* fp = callfopen( filename, "rb" );
2163 if ( !fp ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07002164 SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename ? filename : "<null>");
Lee Thomason624d43f2012-10-12 10:58:48 -07002165 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002166 }
2167 LoadFile( fp );
2168 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002169 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002170}
2171
Dmitry-Me901fed52015-09-25 10:29:51 +03002172// This is likely overengineered template art to have a check that unsigned long value incremented
2173// by one still fits into size_t. If size_t type is larger than unsigned long type
2174// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
2175// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
2176// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
2177// types sizes relate to each other.
2178template
2179<bool = (sizeof(unsigned long) >= sizeof(size_t))>
2180struct LongFitsIntoSizeTMinusOne {
2181 static bool Fits( unsigned long value )
2182 {
2183 return value < (size_t)-1;
2184 }
2185};
2186
2187template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02002188struct LongFitsIntoSizeTMinusOne<false> {
2189 static bool Fits( unsigned long )
2190 {
2191 return true;
2192 }
2193};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002194
Lee Thomason2fa81722012-11-09 12:37:46 -08002195XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002196{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002197 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002198
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002199 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002200 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002201 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002202 return _errorID;
2203 }
2204
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002205 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002206 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002207 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002208 if ( filelength == -1L ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002209 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002210 return _errorID;
2211 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002212 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002213
Dmitry-Me901fed52015-09-25 10:29:51 +03002214 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002215 // Cannot handle files which won't fit in buffer together with null terminator
Lee Thomasonaa188392017-09-19 17:54:31 -07002216 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002217 return _errorID;
2218 }
2219
Dmitry-Me72801b82015-05-07 09:41:39 +03002220 if ( filelength == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002221 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002222 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002223 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002224
Dmitry-Me72801b82015-05-07 09:41:39 +03002225 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002226 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002227 _charBuffer = new char[size+1];
2228 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002229 if ( read != size ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002230 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002231 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002232 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002233
Lee Thomason624d43f2012-10-12 10:58:48 -07002234 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002235
Dmitry-Me97476b72015-01-01 16:15:57 +03002236 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002237 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002238}
2239
2240
Lee Thomason2fa81722012-11-09 12:37:46 -08002241XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002242{
Dmitry-Me01578db2014-08-19 10:18:48 +04002243 FILE* fp = callfopen( filename, "w" );
2244 if ( !fp ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07002245 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename ? filename : "<null>");
Lee Thomason624d43f2012-10-12 10:58:48 -07002246 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002247 }
2248 SaveFile(fp, compact);
2249 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002250 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002251}
2252
2253
Lee Thomason2fa81722012-11-09 12:37:46 -08002254XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002255{
Ant Mitchell189198f2015-03-24 16:20:36 +00002256 // Clear any error from the last save, otherwise it will get reported
2257 // for *this* call.
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002258 ClearError();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002259 XMLPrinter stream( fp, compact );
2260 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002261 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002262}
2263
Lee Thomason1ff38e02012-02-14 18:18:16 -08002264
Lee Thomason2fa81722012-11-09 12:37:46 -08002265XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002266{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002267 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002268
Lee Thomason82d32002014-02-21 22:47:18 -08002269 if ( len == 0 || !p || !*p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002270 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002271 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002272 }
2273 if ( len == (size_t)(-1) ) {
2274 len = strlen( p );
2275 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002276 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002277 _charBuffer = new char[ len+1 ];
2278 memcpy( _charBuffer, p, len );
2279 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002280
Dmitry-Me97476b72015-01-01 16:15:57 +03002281 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002282 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002283 // clean up now essentially dangling memory.
2284 // and the parse fail can put objects in the
2285 // pools that are dead and inaccessible.
2286 DeleteChildren();
2287 _elementPool.Clear();
2288 _attributePool.Clear();
2289 _textPool.Clear();
2290 _commentPool.Clear();
2291 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002292 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002293}
2294
2295
PKEuS1c5f99e2013-07-06 11:28:39 +02002296void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002297{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002298 if ( streamer ) {
2299 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002300 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002301 else {
2302 XMLPrinter stdoutStreamer( stdout );
2303 Accept( &stdoutStreamer );
2304 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002305}
2306
2307
Lee Thomasonaa188392017-09-19 17:54:31 -07002308void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... )
Lee Thomason67d61312012-01-24 16:01:51 -08002309{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002310 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002311 _errorID = error;
Lee Thomason714ccfe2017-10-10 17:08:12 -07002312 _errorLineNum = lineNum;
Lee Thomasonaa188392017-09-19 17:54:31 -07002313 _errorStr.Reset();
Lee Thomason584af572016-09-05 14:14:16 -07002314
Lee Thomasonaa188392017-09-19 17:54:31 -07002315 if (format) {
2316 size_t BUFFER_SIZE = 1000;
2317 char* buffer = new char[BUFFER_SIZE];
Lee Thomasonf49b9652017-10-11 10:57:49 -07002318 TIXML_SNPRINTF(buffer, BUFFER_SIZE, "Error=%s ErrorID=%d (0x%x) Line number=%d: ", ErrorIDToName(error), int(error), int(error), lineNum);
Lee Thomasonaa188392017-09-19 17:54:31 -07002319 size_t len = strlen(buffer);
2320
2321 va_list va;
2322 va_start( va, format );
2323 int result = TIXML_VSNPRINTF( buffer + len, BUFFER_SIZE - len, format, va );
2324 va_end( va );
2325
2326 _errorStr.SetStr(buffer);
2327 delete [] buffer;
2328 }
Lee Thomason67d61312012-01-24 16:01:51 -08002329}
2330
Lee Thomasonaa188392017-09-19 17:54:31 -07002331
Lee Thomasone90e9012016-12-24 07:34:39 -08002332/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
Lee Thomason331596e2014-09-11 14:56:43 -07002333{
kezenator5a700712016-11-26 13:54:42 +10002334 TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2335 const char* errorName = _errorNames[errorID];
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002336 TIXMLASSERT( errorName && errorName[0] );
2337 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002338}
Lee Thomason5cae8972012-01-24 18:03:07 -08002339
Lee Thomasonf49b9652017-10-11 10:57:49 -07002340const char* XMLDocument::ErrorStr() const
Lee Thomason8c9e3132017-06-26 16:55:01 -07002341{
Lee Thomasonaa188392017-09-19 17:54:31 -07002342 return _errorStr.Empty() ? "" : _errorStr.GetStr();
Lee Thomason8c9e3132017-06-26 16:55:01 -07002343}
2344
Lee Thomasonf49b9652017-10-11 10:57:49 -07002345
2346void XMLDocument::PrintError() const
2347{
2348 printf("%s\n", ErrorStr());
2349}
2350
kezenator5a700712016-11-26 13:54:42 +10002351const char* XMLDocument::ErrorName() const
2352{
Lee Thomasone90e9012016-12-24 07:34:39 -08002353 return ErrorIDToName(_errorID);
kezenator5a700712016-11-26 13:54:42 +10002354}
2355
Dmitry-Me97476b72015-01-01 16:15:57 +03002356void XMLDocument::Parse()
2357{
2358 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2359 TIXMLASSERT( _charBuffer );
kezenatorec694152016-11-26 17:21:43 +10002360 _parseCurLineNum = 1;
2361 _parseLineNum = 1;
Lee Thomason3cebdc42015-01-05 17:16:28 -08002362 char* p = _charBuffer;
kezenator4f756162016-11-29 19:46:27 +10002363 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mee28be752015-01-09 14:59:30 +03002364 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002365 if ( !*p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002366 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002367 return;
2368 }
kezenator4f756162016-11-29 19:46:27 +10002369 ParseDeep(p, 0, &_parseCurLineNum );
Dmitry-Me97476b72015-01-01 16:15:57 +03002370}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002371
PKEuS1bfb9542013-08-04 13:51:17 +02002372XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002373 _elementJustOpened( false ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002374 _stack(),
Lee Thomason624d43f2012-10-12 10:58:48 -07002375 _firstElement( true ),
2376 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002377 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002378 _textDepth( -1 ),
2379 _processEntities( true ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002380 _compactMode( compact ),
2381 _buffer()
Lee Thomason5cae8972012-01-24 18:03:07 -08002382{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002383 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002384 _entityFlag[i] = false;
2385 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002386 }
2387 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002388 const char entityValue = entities[i].value;
Dmitry-Mea28eb072017-08-25 18:34:18 +03002389 const unsigned char flagIndex = (unsigned char)entityValue;
2390 TIXMLASSERT( flagIndex < ENTITY_RANGE );
2391 _entityFlag[flagIndex] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002392 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002393 _restrictedEntityFlag[(unsigned char)'&'] = true;
2394 _restrictedEntityFlag[(unsigned char)'<'] = true;
2395 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002396 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002397}
2398
2399
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002400void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002401{
2402 va_list va;
2403 va_start( va, format );
2404
Lee Thomason624d43f2012-10-12 10:58:48 -07002405 if ( _fp ) {
2406 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002407 }
2408 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002409 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002410 // Close out and re-start the va-args
2411 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002412 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002413 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002414 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002415 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002416 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002417 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002418 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002419}
2420
2421
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002422void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002423{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002424 for( int i=0; i<depth; ++i ) {
2425 Print( " " );
2426 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002427}
2428
2429
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002430void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002431{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002432 // Look for runs of bytes between entities to print.
2433 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002434
Lee Thomason624d43f2012-10-12 10:58:48 -07002435 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002436 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002437 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002438 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002439 // Remember, char is sometimes signed. (How many times has that bitten me?)
2440 if ( *q > 0 && *q < ENTITY_RANGE ) {
2441 // Check for entities. If one is found, flush
2442 // the stream up until the entity, write the
2443 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002444 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002445 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002446 const size_t delta = q - p;
2447 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002448 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002449 Print( "%.*s", toPrint, p );
2450 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002451 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002452 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002453 for( int i=0; i<NUM_ENTITIES; ++i ) {
2454 if ( entities[i].value == *q ) {
2455 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002456 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002457 break;
2458 }
2459 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002460 if ( !entityPatternPrinted ) {
2461 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2462 TIXMLASSERT( false );
2463 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002464 ++p;
2465 }
2466 }
2467 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002468 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002469 }
2470 }
2471 // Flush the remaining string. This will be the entire
2472 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002473 TIXMLASSERT( p <= q );
2474 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002475 Print( "%s", p );
2476 }
Lee Thomason857b8682012-01-25 17:50:25 -08002477}
2478
U-Stream\Leeae25a442012-02-17 17:48:16 -08002479
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002480void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002481{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002482 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002483 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 -07002484 Print( "%s", bom );
2485 }
2486 if ( writeDec ) {
2487 PushDeclaration( "xml version=\"1.0\"" );
2488 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002489}
2490
2491
Uli Kusterer593a33d2014-02-01 12:48:51 +01002492void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002493{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002494 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002495 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002496
Uli Kusterer593a33d2014-02-01 12:48:51 +01002497 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002498 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002499 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002500 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002501 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002502 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002503
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002504 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002505 _elementJustOpened = true;
2506 _firstElement = false;
2507 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002508}
2509
2510
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002511void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002512{
Lee Thomason624d43f2012-10-12 10:58:48 -07002513 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002514 Print( " %s=\"", name );
2515 PrintString( value, false );
2516 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002517}
2518
2519
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002520void XMLPrinter::PushAttribute( const char* name, int v )
2521{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002522 char buf[BUF_SIZE];
2523 XMLUtil::ToStr( v, buf, BUF_SIZE );
2524 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002525}
2526
2527
2528void XMLPrinter::PushAttribute( const char* name, unsigned v )
2529{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002530 char buf[BUF_SIZE];
2531 XMLUtil::ToStr( v, buf, BUF_SIZE );
2532 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002533}
2534
2535
Lee Thomason51c12712016-06-04 20:18:49 -07002536void XMLPrinter::PushAttribute(const char* name, int64_t v)
2537{
2538 char buf[BUF_SIZE];
2539 XMLUtil::ToStr(v, buf, BUF_SIZE);
2540 PushAttribute(name, buf);
2541}
2542
2543
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002544void XMLPrinter::PushAttribute( const char* name, bool v )
2545{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002546 char buf[BUF_SIZE];
2547 XMLUtil::ToStr( v, buf, BUF_SIZE );
2548 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002549}
2550
2551
2552void XMLPrinter::PushAttribute( const char* name, double v )
2553{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002554 char buf[BUF_SIZE];
2555 XMLUtil::ToStr( v, buf, BUF_SIZE );
2556 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002557}
2558
2559
Uli Kustererca412e82014-02-01 13:35:05 +01002560void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002561{
Lee Thomason624d43f2012-10-12 10:58:48 -07002562 --_depth;
2563 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002564
Lee Thomason624d43f2012-10-12 10:58:48 -07002565 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002566 Print( "/>" );
2567 }
2568 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002569 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002570 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002571 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002572 }
2573 Print( "</%s>", name );
2574 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002575
Lee Thomason624d43f2012-10-12 10:58:48 -07002576 if ( _textDepth == _depth ) {
2577 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002578 }
Uli Kustererca412e82014-02-01 13:35:05 +01002579 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002580 Print( "\n" );
2581 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002582 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002583}
2584
2585
Dmitry-Mea092bc12014-12-23 17:57:05 +03002586void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002587{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002588 if ( !_elementJustOpened ) {
2589 return;
2590 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002591 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002592 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002593}
2594
2595
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002596void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002597{
Lee Thomason624d43f2012-10-12 10:58:48 -07002598 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002599
Dmitry-Mea092bc12014-12-23 17:57:05 +03002600 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002601 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002602 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002603 }
2604 else {
2605 PrintString( text, true );
2606 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002607}
2608
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002609void XMLPrinter::PushText( int64_t value )
2610{
2611 char buf[BUF_SIZE];
2612 XMLUtil::ToStr( value, buf, BUF_SIZE );
2613 PushText( buf, false );
2614}
2615
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002616void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002617{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002618 char buf[BUF_SIZE];
2619 XMLUtil::ToStr( value, buf, BUF_SIZE );
2620 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002621}
2622
2623
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002624void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002625{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002626 char buf[BUF_SIZE];
2627 XMLUtil::ToStr( value, buf, BUF_SIZE );
2628 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002629}
2630
2631
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002632void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002633{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002634 char buf[BUF_SIZE];
2635 XMLUtil::ToStr( value, buf, BUF_SIZE );
2636 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002637}
2638
2639
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002640void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002641{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002642 char buf[BUF_SIZE];
2643 XMLUtil::ToStr( value, buf, BUF_SIZE );
2644 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002645}
2646
2647
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002648void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002649{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002650 char buf[BUF_SIZE];
2651 XMLUtil::ToStr( value, buf, BUF_SIZE );
2652 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002653}
2654
Lee Thomason5cae8972012-01-24 18:03:07 -08002655
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002656void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002657{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002658 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002659 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002660 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002661 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002662 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002663 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002664 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002665}
Lee Thomason751da522012-02-10 08:50:51 -08002666
2667
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002668void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002669{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002670 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002671 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002672 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002673 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002674 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002675 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002676 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002677}
2678
2679
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002680void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002681{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002682 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002683 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002684 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002685 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002686 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002687 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002688 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002689}
2690
2691
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002692bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002693{
Lee Thomason624d43f2012-10-12 10:58:48 -07002694 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002695 if ( doc.HasBOM() ) {
2696 PushHeader( true, false );
2697 }
2698 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002699}
2700
2701
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002702bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002703{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002704 const XMLElement* parentElem = 0;
2705 if ( element.Parent() ) {
2706 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002707 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002708 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002709 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002710 while ( attribute ) {
2711 PushAttribute( attribute->Name(), attribute->Value() );
2712 attribute = attribute->Next();
2713 }
2714 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002715}
2716
2717
Uli Kustererca412e82014-02-01 13:35:05 +01002718bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002719{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002720 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002721 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002722}
2723
2724
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002725bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002726{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002727 PushText( text.Value(), text.CData() );
2728 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002729}
2730
2731
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002732bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002733{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002734 PushComment( comment.Value() );
2735 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002736}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002737
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002738bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002739{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002740 PushDeclaration( declaration.Value() );
2741 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002742}
2743
2744
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002745bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002746{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002747 PushUnknown( unknown.Value() );
2748 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002749}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002750
Lee Thomason685b8952012-11-12 13:00:06 -08002751} // namespace tinyxml2
2752