blob: 0c903fe2b7472ada3315a9bb008a073be774e041 [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 if ( this->CData() ) {
kezenator4f756162016-11-29 19:46:27 +10001136 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001137 if ( !p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001138 _document->SetError( XML_ERROR_PARSING_CDATA, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001139 }
1140 return p;
1141 }
1142 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001143 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1144 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001145 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001146 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001147
kezenator4f756162016-11-29 19:46:27 +10001148 p = _value.ParseText( p, "<", flags, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001149 if ( p && *p ) {
1150 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001151 }
1152 if ( !p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001153 _document->SetError( XML_ERROR_PARSING_TEXT, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001154 }
1155 }
1156 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001157}
1158
1159
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001160XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1161{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001162 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001163 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001164 }
1165 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1166 text->SetCData( this->CData() );
1167 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001168}
1169
1170
1171bool XMLText::ShallowEqual( const XMLNode* compare ) const
1172{
Dmitry-Meba68a3a2017-03-21 11:39:48 +03001173 TIXMLASSERT( compare );
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001174 const XMLText* text = compare->ToText();
1175 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001176}
1177
1178
Lee Thomason56bdd022012-02-09 18:16:58 -08001179bool XMLText::Accept( XMLVisitor* visitor ) const
1180{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001181 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001182 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001183}
1184
1185
Lee Thomason3f57d272012-01-11 15:30:03 -08001186// --------- XMLComment ---------- //
1187
Lee Thomasone4422302012-01-20 17:59:50 -08001188XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001189{
1190}
1191
1192
Lee Thomasonce0763e2012-01-11 15:43:54 -08001193XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001194{
Lee Thomason3f57d272012-01-11 15:30:03 -08001195}
1196
1197
kezenator4f756162016-11-29 19:46:27 +10001198char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason3f57d272012-01-11 15:30:03 -08001199{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001200 // Comment parses as text.
kezenator4f756162016-11-29 19:46:27 +10001201 p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001202 if ( p == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001203 _document->SetError( XML_ERROR_PARSING_COMMENT, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001204 }
1205 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001206}
1207
1208
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001209XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1210{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001211 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001212 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001213 }
1214 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1215 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001216}
1217
1218
1219bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1220{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001221 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001222 const XMLComment* comment = compare->ToComment();
1223 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001224}
1225
1226
Lee Thomason751da522012-02-10 08:50:51 -08001227bool XMLComment::Accept( XMLVisitor* visitor ) const
1228{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001229 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001230 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001231}
Lee Thomason56bdd022012-02-09 18:16:58 -08001232
1233
Lee Thomason50f97b22012-02-11 16:33:40 -08001234// --------- XMLDeclaration ---------- //
1235
1236XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1237{
1238}
1239
1240
1241XMLDeclaration::~XMLDeclaration()
1242{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001243 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001244}
1245
1246
kezenator4f756162016-11-29 19:46:27 +10001247char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001248{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001249 // Declaration parses as text.
kezenator4f756162016-11-29 19:46:27 +10001250 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001251 if ( p == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001252 _document->SetError( XML_ERROR_PARSING_DECLARATION, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001253 }
1254 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001255}
1256
1257
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001258XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1259{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001260 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001261 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001262 }
1263 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1264 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001265}
1266
1267
1268bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1269{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001270 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001271 const XMLDeclaration* declaration = compare->ToDeclaration();
1272 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001273}
1274
1275
1276
Lee Thomason50f97b22012-02-11 16:33:40 -08001277bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1278{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001279 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001280 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001281}
1282
1283// --------- XMLUnknown ---------- //
1284
1285XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1286{
1287}
1288
1289
1290XMLUnknown::~XMLUnknown()
1291{
1292}
1293
1294
kezenator4f756162016-11-29 19:46:27 +10001295char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001296{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001297 // Unknown parses as text.
kezenator4f756162016-11-29 19:46:27 +10001298 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001299 if ( !p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001300 _document->SetError( XML_ERROR_PARSING_UNKNOWN, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001301 }
1302 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001303}
1304
1305
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001306XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1307{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001308 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001309 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001310 }
1311 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1312 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001313}
1314
1315
1316bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1317{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001318 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001319 const XMLUnknown* unknown = compare->ToUnknown();
1320 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001321}
1322
1323
Lee Thomason50f97b22012-02-11 16:33:40 -08001324bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1325{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001326 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001327 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001328}
1329
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001330// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001331
1332const char* XMLAttribute::Name() const
1333{
1334 return _name.GetStr();
1335}
1336
1337const char* XMLAttribute::Value() const
1338{
1339 return _value.GetStr();
1340}
1341
kezenator4f756162016-11-29 19:46:27 +10001342char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001343{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001344 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001345 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001346 if ( !p || !*p ) {
1347 return 0;
1348 }
Lee Thomason22aead12012-01-23 13:29:35 -08001349
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001350 // Skip white space before =
kezenator4f756162016-11-29 19:46:27 +10001351 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001352 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001353 return 0;
1354 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001355
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001356 ++p; // move up to opening quote
kezenator4f756162016-11-29 19:46:27 +10001357 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001358 if ( *p != '\"' && *p != '\'' ) {
1359 return 0;
1360 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001361
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001362 char endTag[2] = { *p, 0 };
1363 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001364
kezenator4f756162016-11-29 19:46:27 +10001365 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001366 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001367}
1368
1369
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001370void XMLAttribute::SetName( const char* n )
1371{
Lee Thomason624d43f2012-10-12 10:58:48 -07001372 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001373}
1374
1375
Lee Thomason2fa81722012-11-09 12:37:46 -08001376XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001377{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001378 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001379 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001380 }
1381 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001382}
1383
1384
Lee Thomason2fa81722012-11-09 12:37:46 -08001385XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001386{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001387 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001388 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001389 }
1390 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001391}
1392
1393
Lee Thomason51c12712016-06-04 20:18:49 -07001394XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1395{
1396 if (XMLUtil::ToInt64(Value(), value)) {
1397 return XML_SUCCESS;
1398 }
1399 return XML_WRONG_ATTRIBUTE_TYPE;
1400}
1401
1402
Lee Thomason2fa81722012-11-09 12:37:46 -08001403XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001404{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001405 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001406 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001407 }
1408 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001409}
1410
1411
Lee Thomason2fa81722012-11-09 12:37:46 -08001412XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001413{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001414 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001415 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001416 }
1417 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001418}
1419
1420
Lee Thomason2fa81722012-11-09 12:37:46 -08001421XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001422{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001423 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001424 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001425 }
1426 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001427}
1428
1429
1430void XMLAttribute::SetAttribute( const char* v )
1431{
Lee Thomason624d43f2012-10-12 10:58:48 -07001432 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001433}
1434
1435
Lee Thomason1ff38e02012-02-14 18:18:16 -08001436void XMLAttribute::SetAttribute( int v )
1437{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001438 char buf[BUF_SIZE];
1439 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001440 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001441}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001442
1443
1444void XMLAttribute::SetAttribute( unsigned v )
1445{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001446 char buf[BUF_SIZE];
1447 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001448 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001449}
1450
1451
Lee Thomason51c12712016-06-04 20:18:49 -07001452void XMLAttribute::SetAttribute(int64_t v)
1453{
1454 char buf[BUF_SIZE];
1455 XMLUtil::ToStr(v, buf, BUF_SIZE);
1456 _value.SetStr(buf);
1457}
1458
1459
1460
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001461void XMLAttribute::SetAttribute( bool v )
1462{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001463 char buf[BUF_SIZE];
1464 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001465 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001466}
1467
1468void XMLAttribute::SetAttribute( double v )
1469{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001470 char buf[BUF_SIZE];
1471 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001472 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001473}
1474
1475void XMLAttribute::SetAttribute( float v )
1476{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001477 char buf[BUF_SIZE];
1478 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001479 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001480}
1481
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001482
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001483// --------- XMLElement ---------- //
1484XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Dmitry-Mee5035632017-04-05 18:02:40 +03001485 _closingType( OPEN ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001486 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001487{
1488}
1489
1490
1491XMLElement::~XMLElement()
1492{
Lee Thomason624d43f2012-10-12 10:58:48 -07001493 while( _rootAttribute ) {
1494 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001495 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001496 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001497 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001498}
1499
1500
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001501const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1502{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001503 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001504 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1505 return a;
1506 }
1507 }
1508 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001509}
1510
1511
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001512const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001513{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001514 const XMLAttribute* a = FindAttribute( name );
1515 if ( !a ) {
1516 return 0;
1517 }
1518 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1519 return a->Value();
1520 }
1521 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001522}
1523
Josh Wittnercf3dd092016-10-11 18:57:17 -07001524int XMLElement::IntAttribute(const char* name, int defaultValue) const
1525{
1526 int i = defaultValue;
1527 QueryIntAttribute(name, &i);
1528 return i;
1529}
1530
1531unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
1532{
1533 unsigned i = defaultValue;
1534 QueryUnsignedAttribute(name, &i);
1535 return i;
1536}
1537
1538int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
1539{
1540 int64_t i = defaultValue;
1541 QueryInt64Attribute(name, &i);
1542 return i;
1543}
1544
1545bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
1546{
1547 bool b = defaultValue;
1548 QueryBoolAttribute(name, &b);
1549 return b;
1550}
1551
1552double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
1553{
1554 double d = defaultValue;
1555 QueryDoubleAttribute(name, &d);
1556 return d;
1557}
1558
1559float XMLElement::FloatAttribute(const char* name, float defaultValue) const
1560{
1561 float f = defaultValue;
1562 QueryFloatAttribute(name, &f);
1563 return f;
1564}
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001565
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001566const char* XMLElement::GetText() const
1567{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001568 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001569 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001570 }
1571 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001572}
1573
1574
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001575void XMLElement::SetText( const char* inText )
1576{
Uli Kusterer869bb592014-01-21 01:36:16 +01001577 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001578 FirstChild()->SetValue( inText );
1579 else {
1580 XMLText* theText = GetDocument()->NewText( inText );
1581 InsertFirstChild( theText );
1582 }
1583}
1584
Lee Thomason5bb2d802014-01-24 10:42:57 -08001585
1586void XMLElement::SetText( int v )
1587{
1588 char buf[BUF_SIZE];
1589 XMLUtil::ToStr( v, buf, BUF_SIZE );
1590 SetText( buf );
1591}
1592
1593
1594void XMLElement::SetText( unsigned v )
1595{
1596 char buf[BUF_SIZE];
1597 XMLUtil::ToStr( v, buf, BUF_SIZE );
1598 SetText( buf );
1599}
1600
1601
Lee Thomason51c12712016-06-04 20:18:49 -07001602void XMLElement::SetText(int64_t v)
1603{
1604 char buf[BUF_SIZE];
1605 XMLUtil::ToStr(v, buf, BUF_SIZE);
1606 SetText(buf);
1607}
1608
1609
1610void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001611{
1612 char buf[BUF_SIZE];
1613 XMLUtil::ToStr( v, buf, BUF_SIZE );
1614 SetText( buf );
1615}
1616
1617
1618void XMLElement::SetText( float v )
1619{
1620 char buf[BUF_SIZE];
1621 XMLUtil::ToStr( v, buf, BUF_SIZE );
1622 SetText( buf );
1623}
1624
1625
1626void XMLElement::SetText( double v )
1627{
1628 char buf[BUF_SIZE];
1629 XMLUtil::ToStr( v, buf, BUF_SIZE );
1630 SetText( buf );
1631}
1632
1633
MortenMacFly4ee49f12013-01-14 20:03:14 +01001634XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001635{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001636 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001637 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001638 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001639 return XML_SUCCESS;
1640 }
1641 return XML_CAN_NOT_CONVERT_TEXT;
1642 }
1643 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001644}
1645
1646
MortenMacFly4ee49f12013-01-14 20:03:14 +01001647XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001648{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001649 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001650 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001651 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001652 return XML_SUCCESS;
1653 }
1654 return XML_CAN_NOT_CONVERT_TEXT;
1655 }
1656 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001657}
1658
1659
Lee Thomason51c12712016-06-04 20:18:49 -07001660XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1661{
1662 if (FirstChild() && FirstChild()->ToText()) {
1663 const char* t = FirstChild()->Value();
1664 if (XMLUtil::ToInt64(t, ival)) {
1665 return XML_SUCCESS;
1666 }
1667 return XML_CAN_NOT_CONVERT_TEXT;
1668 }
1669 return XML_NO_TEXT_NODE;
1670}
1671
1672
MortenMacFly4ee49f12013-01-14 20:03:14 +01001673XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001674{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001675 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001676 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001677 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001678 return XML_SUCCESS;
1679 }
1680 return XML_CAN_NOT_CONVERT_TEXT;
1681 }
1682 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001683}
1684
1685
MortenMacFly4ee49f12013-01-14 20:03:14 +01001686XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001687{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001688 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001689 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001690 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001691 return XML_SUCCESS;
1692 }
1693 return XML_CAN_NOT_CONVERT_TEXT;
1694 }
1695 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001696}
1697
1698
MortenMacFly4ee49f12013-01-14 20:03:14 +01001699XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001700{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001701 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001702 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001703 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001704 return XML_SUCCESS;
1705 }
1706 return XML_CAN_NOT_CONVERT_TEXT;
1707 }
1708 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001709}
1710
Josh Wittnercf3dd092016-10-11 18:57:17 -07001711int XMLElement::IntText(int defaultValue) const
1712{
1713 int i = defaultValue;
1714 QueryIntText(&i);
1715 return i;
1716}
1717
1718unsigned XMLElement::UnsignedText(unsigned defaultValue) const
1719{
1720 unsigned i = defaultValue;
1721 QueryUnsignedText(&i);
1722 return i;
1723}
1724
1725int64_t XMLElement::Int64Text(int64_t defaultValue) const
1726{
1727 int64_t i = defaultValue;
1728 QueryInt64Text(&i);
1729 return i;
1730}
1731
1732bool XMLElement::BoolText(bool defaultValue) const
1733{
1734 bool b = defaultValue;
1735 QueryBoolText(&b);
1736 return b;
1737}
1738
1739double XMLElement::DoubleText(double defaultValue) const
1740{
1741 double d = defaultValue;
1742 QueryDoubleText(&d);
1743 return d;
1744}
1745
1746float XMLElement::FloatText(float defaultValue) const
1747{
1748 float f = defaultValue;
1749 QueryFloatText(&f);
1750 return f;
1751}
Lee Thomason21be8822012-07-15 17:27:22 -07001752
1753
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001754XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1755{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001756 XMLAttribute* last = 0;
1757 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001758 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001759 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001760 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001761 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1762 break;
1763 }
1764 }
1765 if ( !attrib ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001766 attrib = CreateAttribute();
1767 TIXMLASSERT( attrib );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001768 if ( last ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001769 TIXMLASSERT( last->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001770 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001771 }
1772 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001773 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001774 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001775 }
1776 attrib->SetName( name );
1777 }
1778 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001779}
1780
1781
U-Stream\Leeae25a442012-02-17 17:48:16 -08001782void XMLElement::DeleteAttribute( const char* name )
1783{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001784 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001785 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001786 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1787 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001788 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001789 }
1790 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001791 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001792 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001793 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001794 break;
1795 }
1796 prev = a;
1797 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001798}
1799
1800
kezenator4f756162016-11-29 19:46:27 +10001801char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001802{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001803 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001804
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001805 // Read the attributes.
1806 while( p ) {
kezenator4f756162016-11-29 19:46:27 +10001807 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001808 if ( !(*p) ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07001809 _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, "XMLElement name=%s", Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001810 return 0;
1811 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001812
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001813 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001814 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001815 XMLAttribute* attrib = CreateAttribute();
1816 TIXMLASSERT( attrib );
kezenatorec694152016-11-26 17:21:43 +10001817 attrib->_parseLineNum = _document->_parseCurLineNum;
Lee Thomasond1983222012-02-06 08:41:24 -08001818
kezenatorec694152016-11-26 17:21:43 +10001819 int attrLineNum = attrib->_parseLineNum;
1820
kezenator4f756162016-11-29 19:46:27 +10001821 p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001822 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001823 DeleteAttribute( attrib );
Lee Thomasonf49b9652017-10-11 10:57:49 -07001824 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, attrLineNum, "XMLElement name=%s", Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001825 return 0;
1826 }
1827 // There is a minor bug here: if the attribute in the source xml
1828 // document is duplicated, it will not be detected and the
1829 // attribute will be doubly added. However, tracking the 'prevAttribute'
1830 // avoids re-scanning the attribute list. Preferring performance for
1831 // now, may reconsider in the future.
1832 if ( prevAttribute ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001833 TIXMLASSERT( prevAttribute->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001834 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001835 }
1836 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001837 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001838 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001839 }
1840 prevAttribute = attrib;
1841 }
1842 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001843 else if ( *p == '>' ) {
1844 ++p;
1845 break;
1846 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001847 // end of the tag
1848 else if ( *p == '/' && *(p+1) == '>' ) {
1849 _closingType = CLOSED;
1850 return p+2; // done; sealed element.
1851 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001852 else {
Lee Thomasonaa188392017-09-19 17:54:31 -07001853 _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001854 return 0;
1855 }
1856 }
1857 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001858}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001859
Dmitry-Mee3225b12014-09-03 11:03:11 +04001860void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1861{
1862 if ( attribute == 0 ) {
1863 return;
1864 }
1865 MemPool* pool = attribute->_memPool;
1866 attribute->~XMLAttribute();
1867 pool->Free( attribute );
1868}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001869
Dmitry-Mea60caa22016-11-22 18:28:08 +03001870XMLAttribute* XMLElement::CreateAttribute()
1871{
1872 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
1873 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
Dmitry-Me7221b492017-03-03 15:45:51 +03001874 TIXMLASSERT( attrib );
Dmitry-Mea60caa22016-11-22 18:28:08 +03001875 attrib->_memPool = &_document->_attributePool;
1876 attrib->_memPool->SetTracked();
1877 return attrib;
1878}
1879
Lee Thomason67d61312012-01-24 16:01:51 -08001880//
1881// <ele></ele>
1882// <ele>foo<b>bar</b></ele>
1883//
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001884char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -08001885{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001886 // Read the element name.
kezenator4f756162016-11-29 19:46:27 +10001887 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomason67d61312012-01-24 16:01:51 -08001888
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001889 // The closing element is the </element> form. It is
1890 // parsed just like a regular element then deleted from
1891 // the DOM.
1892 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001893 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001894 ++p;
1895 }
Lee Thomason67d61312012-01-24 16:01:51 -08001896
Lee Thomason624d43f2012-10-12 10:58:48 -07001897 p = _value.ParseName( p );
1898 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001899 return 0;
1900 }
Lee Thomason67d61312012-01-24 16:01:51 -08001901
kezenator4f756162016-11-29 19:46:27 +10001902 p = ParseAttributes( p, curLineNumPtr );
Dmitry-Mee5035632017-04-05 18:02:40 +03001903 if ( !p || !*p || _closingType != OPEN ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001904 return p;
1905 }
Lee Thomason67d61312012-01-24 16:01:51 -08001906
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001907 p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001908 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001909}
1910
1911
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001912
1913XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1914{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001915 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001916 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001917 }
1918 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1919 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1920 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1921 }
1922 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001923}
1924
1925
1926bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1927{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001928 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001929 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001930 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001931
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001932 const XMLAttribute* a=FirstAttribute();
1933 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001934
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001935 while ( a && b ) {
1936 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1937 return false;
1938 }
1939 a = a->Next();
1940 b = b->Next();
1941 }
1942 if ( a || b ) {
1943 // different count
1944 return false;
1945 }
1946 return true;
1947 }
1948 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001949}
1950
1951
Lee Thomason751da522012-02-10 08:50:51 -08001952bool XMLElement::Accept( XMLVisitor* visitor ) const
1953{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001954 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001955 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001956 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1957 if ( !node->Accept( visitor ) ) {
1958 break;
1959 }
1960 }
1961 }
1962 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001963}
Lee Thomason56bdd022012-02-09 18:16:58 -08001964
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001965
Lee Thomason3f57d272012-01-11 15:30:03 -08001966// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001967
1968// Warning: List must match 'enum XMLError'
1969const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1970 "XML_SUCCESS",
1971 "XML_NO_ATTRIBUTE",
1972 "XML_WRONG_ATTRIBUTE_TYPE",
1973 "XML_ERROR_FILE_NOT_FOUND",
1974 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1975 "XML_ERROR_FILE_READ_ERROR",
Lee Thomason8bba8b42017-06-20 09:18:41 -07001976 "UNUSED_XML_ERROR_ELEMENT_MISMATCH",
Lee Thomason331596e2014-09-11 14:56:43 -07001977 "XML_ERROR_PARSING_ELEMENT",
1978 "XML_ERROR_PARSING_ATTRIBUTE",
Lee Thomason8bba8b42017-06-20 09:18:41 -07001979 "UNUSED_XML_ERROR_IDENTIFYING_TAG",
Lee Thomason331596e2014-09-11 14:56:43 -07001980 "XML_ERROR_PARSING_TEXT",
1981 "XML_ERROR_PARSING_CDATA",
1982 "XML_ERROR_PARSING_COMMENT",
1983 "XML_ERROR_PARSING_DECLARATION",
1984 "XML_ERROR_PARSING_UNKNOWN",
1985 "XML_ERROR_EMPTY_DOCUMENT",
1986 "XML_ERROR_MISMATCHED_ELEMENT",
1987 "XML_ERROR_PARSING",
1988 "XML_CAN_NOT_CONVERT_TEXT",
1989 "XML_NO_TEXT_NODE"
1990};
1991
1992
Dmitry-Meae8a82a2017-03-03 15:40:32 +03001993XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001994 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001995 _writeBOM( false ),
1996 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07001997 _errorID(XML_SUCCESS),
Dmitry-Meae8a82a2017-03-03 15:40:32 +03001998 _whitespaceMode( whitespaceMode ),
Lee Thomason0c0f98b2017-10-11 11:03:49 -07001999 _errorStr(),
Dmitry-Mef89bd3e2017-01-18 18:33:55 +03002000 _errorLineNum( 0 ),
2001 _charBuffer( 0 ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002002 _parseCurLineNum( 0 ),
2003 _unlinked(),
2004 _elementPool(),
2005 _attributePool(),
2006 _textPool(),
2007 _commentPool()
U-Lama\Lee560bd472011-12-28 19:42:49 -08002008{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03002009 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
2010 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08002011}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002012
2013
Lee Thomason3f57d272012-01-11 15:30:03 -08002014XMLDocument::~XMLDocument()
2015{
Lee Thomasonf07b9522014-10-30 13:25:12 -07002016 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08002017}
2018
2019
Lee Thomason816d3fa2017-06-05 14:35:55 -07002020void XMLDocument::MarkInUse(XMLNode* node)
2021{
Dmitry-Mec2f677b2017-06-15 12:44:27 +03002022 TIXMLASSERT(node);
Lee Thomason816d3fa2017-06-05 14:35:55 -07002023 TIXMLASSERT(node->_parent == 0);
2024
2025 for (int i = 0; i < _unlinked.Size(); ++i) {
2026 if (node == _unlinked[i]) {
2027 _unlinked.SwapRemove(i);
2028 break;
2029 }
2030 }
2031}
2032
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002033void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08002034{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002035 DeleteChildren();
Lee Thomason816d3fa2017-06-05 14:35:55 -07002036 while( _unlinked.Size()) {
2037 DeleteNode(_unlinked[0]); // Will remove from _unlinked as part of delete.
2038 }
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002039
Peter Matula50689912018-01-09 12:52:26 +01002040#ifdef TINYXML2_DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002041 const bool hadError = Error();
2042#endif
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002043 ClearError();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002044
Lee Thomason624d43f2012-10-12 10:58:48 -07002045 delete [] _charBuffer;
2046 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07002047
2048#if 0
2049 _textPool.Trace( "text" );
2050 _elementPool.Trace( "element" );
2051 _commentPool.Trace( "comment" );
2052 _attributePool.Trace( "attribute" );
2053#endif
2054
Peter Matula50689912018-01-09 12:52:26 +01002055#ifdef TINYXML2_DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002056 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002057 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
2058 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
2059 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
2060 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
2061 }
2062#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08002063}
2064
Lee Thomason3f57d272012-01-11 15:30:03 -08002065
Shuichiro Suzuki87cd4e02017-08-24 11:20:26 +09002066void XMLDocument::DeepCopy(XMLDocument* target) const
Lee Thomason7085f002017-06-01 18:09:43 -07002067{
2068 TIXMLASSERT(target);
Lee Thomason1346a172017-06-14 15:14:19 -07002069 if (target == this) {
2070 return; // technically success - a no-op.
2071 }
Lee Thomason7085f002017-06-01 18:09:43 -07002072
2073 target->Clear();
2074 for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {
2075 target->InsertEndChild(node->DeepClone(target));
2076 }
2077}
2078
Lee Thomason2c85a712012-01-31 08:24:24 -08002079XMLElement* XMLDocument::NewElement( const char* name )
2080{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002081 XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002082 ele->SetName( name );
2083 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08002084}
2085
2086
Lee Thomason1ff38e02012-02-14 18:18:16 -08002087XMLComment* XMLDocument::NewComment( const char* str )
2088{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002089 XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002090 comment->SetValue( str );
2091 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002092}
2093
2094
2095XMLText* XMLDocument::NewText( const char* str )
2096{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002097 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002098 text->SetValue( str );
2099 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002100}
2101
2102
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002103XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2104{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002105 XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002106 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2107 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002108}
2109
2110
2111XMLUnknown* XMLDocument::NewUnknown( const char* str )
2112{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002113 XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002114 unk->SetValue( str );
2115 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002116}
2117
Dmitry-Me01578db2014-08-19 10:18:48 +04002118static FILE* callfopen( const char* filepath, const char* mode )
2119{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002120 TIXMLASSERT( filepath );
2121 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002122#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2123 FILE* fp = 0;
2124 errno_t err = fopen_s( &fp, filepath, mode );
2125 if ( err ) {
2126 return 0;
2127 }
2128#else
2129 FILE* fp = fopen( filepath, mode );
2130#endif
2131 return fp;
2132}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08002133
2134void XMLDocument::DeleteNode( XMLNode* node ) {
2135 TIXMLASSERT( node );
2136 TIXMLASSERT(node->_document == this );
2137 if (node->_parent) {
2138 node->_parent->DeleteChild( node );
2139 }
2140 else {
2141 // Isn't in the tree.
2142 // Use the parent delete.
2143 // Also, we need to mark it tracked: we 'know'
2144 // it was never used.
2145 node->_memPool->SetTracked();
2146 // Call the static XMLNode version:
2147 XMLNode::DeleteNode(node);
2148 }
2149}
2150
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002151
Lee Thomason2fa81722012-11-09 12:37:46 -08002152XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002153{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002154 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04002155 FILE* fp = callfopen( filename, "rb" );
2156 if ( !fp ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07002157 SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename ? filename : "<null>");
Lee Thomason624d43f2012-10-12 10:58:48 -07002158 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002159 }
2160 LoadFile( fp );
2161 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002162 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002163}
2164
Dmitry-Me901fed52015-09-25 10:29:51 +03002165// This is likely overengineered template art to have a check that unsigned long value incremented
2166// by one still fits into size_t. If size_t type is larger than unsigned long type
2167// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
2168// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
2169// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
2170// types sizes relate to each other.
2171template
2172<bool = (sizeof(unsigned long) >= sizeof(size_t))>
2173struct LongFitsIntoSizeTMinusOne {
2174 static bool Fits( unsigned long value )
2175 {
2176 return value < (size_t)-1;
2177 }
2178};
2179
2180template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02002181struct LongFitsIntoSizeTMinusOne<false> {
2182 static bool Fits( unsigned long )
2183 {
2184 return true;
2185 }
2186};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002187
Lee Thomason2fa81722012-11-09 12:37:46 -08002188XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002189{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002190 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002191
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002192 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002193 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002194 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002195 return _errorID;
2196 }
2197
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002198 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002199 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002200 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002201 if ( filelength == -1L ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002202 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002203 return _errorID;
2204 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002205 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002206
Dmitry-Me901fed52015-09-25 10:29:51 +03002207 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002208 // Cannot handle files which won't fit in buffer together with null terminator
Lee Thomasonaa188392017-09-19 17:54:31 -07002209 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002210 return _errorID;
2211 }
2212
Dmitry-Me72801b82015-05-07 09:41:39 +03002213 if ( filelength == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002214 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002215 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002216 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002217
Dmitry-Me72801b82015-05-07 09:41:39 +03002218 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002219 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002220 _charBuffer = new char[size+1];
2221 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002222 if ( read != size ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002223 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002224 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002225 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002226
Lee Thomason624d43f2012-10-12 10:58:48 -07002227 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002228
Dmitry-Me97476b72015-01-01 16:15:57 +03002229 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002230 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002231}
2232
2233
Lee Thomason2fa81722012-11-09 12:37:46 -08002234XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002235{
Dmitry-Me01578db2014-08-19 10:18:48 +04002236 FILE* fp = callfopen( filename, "w" );
2237 if ( !fp ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07002238 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename ? filename : "<null>");
Lee Thomason624d43f2012-10-12 10:58:48 -07002239 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002240 }
2241 SaveFile(fp, compact);
2242 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002243 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002244}
2245
2246
Lee Thomason2fa81722012-11-09 12:37:46 -08002247XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002248{
Ant Mitchell189198f2015-03-24 16:20:36 +00002249 // Clear any error from the last save, otherwise it will get reported
2250 // for *this* call.
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002251 ClearError();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002252 XMLPrinter stream( fp, compact );
2253 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002254 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002255}
2256
Lee Thomason1ff38e02012-02-14 18:18:16 -08002257
Lee Thomason2fa81722012-11-09 12:37:46 -08002258XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002259{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002260 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002261
Lee Thomason82d32002014-02-21 22:47:18 -08002262 if ( len == 0 || !p || !*p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002263 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002264 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002265 }
2266 if ( len == (size_t)(-1) ) {
2267 len = strlen( p );
2268 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002269 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002270 _charBuffer = new char[ len+1 ];
2271 memcpy( _charBuffer, p, len );
2272 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002273
Dmitry-Me97476b72015-01-01 16:15:57 +03002274 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002275 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002276 // clean up now essentially dangling memory.
2277 // and the parse fail can put objects in the
2278 // pools that are dead and inaccessible.
2279 DeleteChildren();
2280 _elementPool.Clear();
2281 _attributePool.Clear();
2282 _textPool.Clear();
2283 _commentPool.Clear();
2284 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002285 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002286}
2287
2288
PKEuS1c5f99e2013-07-06 11:28:39 +02002289void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002290{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002291 if ( streamer ) {
2292 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002293 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002294 else {
2295 XMLPrinter stdoutStreamer( stdout );
2296 Accept( &stdoutStreamer );
2297 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002298}
2299
2300
Lee Thomasonaa188392017-09-19 17:54:31 -07002301void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... )
Lee Thomason67d61312012-01-24 16:01:51 -08002302{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002303 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002304 _errorID = error;
Lee Thomason714ccfe2017-10-10 17:08:12 -07002305 _errorLineNum = lineNum;
Lee Thomasonaa188392017-09-19 17:54:31 -07002306 _errorStr.Reset();
Lee Thomason584af572016-09-05 14:14:16 -07002307
Lee Thomasona36f7ac2017-12-28 13:48:54 -08002308 size_t BUFFER_SIZE = 1000;
2309 char* buffer = new char[BUFFER_SIZE];
Lee Thomasonaa188392017-09-19 17:54:31 -07002310
Lee Thomasona36f7ac2017-12-28 13:48:54 -08002311 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 -07002312
Lee Thomasona36f7ac2017-12-28 13:48:54 -08002313 if (format) {
2314 size_t len = strlen(buffer);
2315 TIXML_SNPRINTF(buffer + len, BUFFER_SIZE - len, ": ");
2316 len = strlen(buffer);
2317
2318 va_list va;
2319 va_start(va, format);
2320 TIXML_VSNPRINTF(buffer + len, BUFFER_SIZE - len, format, va);
2321 va_end(va);
2322 }
2323 _errorStr.SetStr(buffer);
2324 delete[] buffer;
Lee Thomason67d61312012-01-24 16:01:51 -08002325}
2326
Lee Thomasonaa188392017-09-19 17:54:31 -07002327
Lee Thomasone90e9012016-12-24 07:34:39 -08002328/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
Lee Thomason331596e2014-09-11 14:56:43 -07002329{
kezenator5a700712016-11-26 13:54:42 +10002330 TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2331 const char* errorName = _errorNames[errorID];
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002332 TIXMLASSERT( errorName && errorName[0] );
2333 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002334}
Lee Thomason5cae8972012-01-24 18:03:07 -08002335
Lee Thomasonf49b9652017-10-11 10:57:49 -07002336const char* XMLDocument::ErrorStr() const
Lee Thomason8c9e3132017-06-26 16:55:01 -07002337{
Lee Thomasonaa188392017-09-19 17:54:31 -07002338 return _errorStr.Empty() ? "" : _errorStr.GetStr();
Lee Thomason8c9e3132017-06-26 16:55:01 -07002339}
2340
Lee Thomasonf49b9652017-10-11 10:57:49 -07002341
2342void XMLDocument::PrintError() const
2343{
2344 printf("%s\n", ErrorStr());
2345}
2346
kezenator5a700712016-11-26 13:54:42 +10002347const char* XMLDocument::ErrorName() const
2348{
Lee Thomasone90e9012016-12-24 07:34:39 -08002349 return ErrorIDToName(_errorID);
kezenator5a700712016-11-26 13:54:42 +10002350}
2351
Dmitry-Me97476b72015-01-01 16:15:57 +03002352void XMLDocument::Parse()
2353{
2354 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2355 TIXMLASSERT( _charBuffer );
kezenatorec694152016-11-26 17:21:43 +10002356 _parseCurLineNum = 1;
2357 _parseLineNum = 1;
Lee Thomason3cebdc42015-01-05 17:16:28 -08002358 char* p = _charBuffer;
kezenator4f756162016-11-29 19:46:27 +10002359 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mee28be752015-01-09 14:59:30 +03002360 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002361 if ( !*p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002362 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002363 return;
2364 }
kezenator4f756162016-11-29 19:46:27 +10002365 ParseDeep(p, 0, &_parseCurLineNum );
Dmitry-Me97476b72015-01-01 16:15:57 +03002366}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002367
PKEuS1bfb9542013-08-04 13:51:17 +02002368XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002369 _elementJustOpened( false ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002370 _stack(),
Lee Thomason624d43f2012-10-12 10:58:48 -07002371 _firstElement( true ),
2372 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002373 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002374 _textDepth( -1 ),
2375 _processEntities( true ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002376 _compactMode( compact ),
2377 _buffer()
Lee Thomason5cae8972012-01-24 18:03:07 -08002378{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002379 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002380 _entityFlag[i] = false;
2381 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002382 }
2383 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002384 const char entityValue = entities[i].value;
Dmitry-Mea28eb072017-08-25 18:34:18 +03002385 const unsigned char flagIndex = (unsigned char)entityValue;
2386 TIXMLASSERT( flagIndex < ENTITY_RANGE );
2387 _entityFlag[flagIndex] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002388 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002389 _restrictedEntityFlag[(unsigned char)'&'] = true;
2390 _restrictedEntityFlag[(unsigned char)'<'] = true;
2391 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002392 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002393}
2394
2395
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002396void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002397{
2398 va_list va;
2399 va_start( va, format );
2400
Lee Thomason624d43f2012-10-12 10:58:48 -07002401 if ( _fp ) {
2402 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002403 }
2404 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002405 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002406 // Close out and re-start the va-args
2407 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002408 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002409 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002410 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002411 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002412 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002413 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002414 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002415}
2416
2417
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002418void XMLPrinter::Write( const char* data, size_t size )
2419{
2420 if ( _fp ) {
2421 fwrite ( data , sizeof(char), size, _fp);
2422 }
2423 else {
Alex Alabuzhev90e69c92017-11-09 00:32:19 +00002424 char* p = _buffer.PushArr( static_cast<int>(size) ) - 1; // back up over the null terminator.
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002425 memcpy( p, data, size );
2426 p[size] = 0;
2427 }
2428}
2429
2430
2431void XMLPrinter::Putc( char ch )
2432{
2433 if ( _fp ) {
2434 fputc ( ch, _fp);
2435 }
2436 else {
2437 char* p = _buffer.PushArr( sizeof(char) ) - 1; // back up over the null terminator.
2438 p[0] = ch;
2439 p[1] = 0;
2440 }
2441}
2442
2443
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002444void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002445{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002446 for( int i=0; i<depth; ++i ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002447 Write( " " );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002448 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002449}
2450
2451
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002452void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002453{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002454 // Look for runs of bytes between entities to print.
2455 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002456
Lee Thomason624d43f2012-10-12 10:58:48 -07002457 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002458 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002459 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002460 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002461 // Remember, char is sometimes signed. (How many times has that bitten me?)
2462 if ( *q > 0 && *q < ENTITY_RANGE ) {
2463 // Check for entities. If one is found, flush
2464 // the stream up until the entity, write the
2465 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002466 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002467 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002468 const size_t delta = q - p;
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002469 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002470 Write( p, toPrint );
Dmitry-Med95172b2015-03-30 08:11:18 +03002471 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002472 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002473 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002474 for( int i=0; i<NUM_ENTITIES; ++i ) {
2475 if ( entities[i].value == *q ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002476 Putc( '&' );
Brad Anderson85aac022017-10-24 21:48:28 -06002477 Write( entities[i].pattern, entities[i].length );
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002478 Putc( ';' );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002479 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002480 break;
2481 }
2482 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002483 if ( !entityPatternPrinted ) {
2484 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2485 TIXMLASSERT( false );
2486 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002487 ++p;
2488 }
2489 }
2490 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002491 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002492 }
2493 }
2494 // Flush the remaining string. This will be the entire
2495 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002496 TIXMLASSERT( p <= q );
2497 if ( !_processEntities || ( p < q ) ) {
Brad Anderson85aac022017-10-24 21:48:28 -06002498 const size_t delta = q - p;
2499 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
2500 Write( p, toPrint );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002501 }
Lee Thomason857b8682012-01-25 17:50:25 -08002502}
2503
U-Stream\Leeae25a442012-02-17 17:48:16 -08002504
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002505void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002506{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002507 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002508 static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002509 Write( reinterpret_cast< const char* >( bom ) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002510 }
2511 if ( writeDec ) {
2512 PushDeclaration( "xml version=\"1.0\"" );
2513 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002514}
2515
2516
Uli Kusterer593a33d2014-02-01 12:48:51 +01002517void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002518{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002519 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002520 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002521
Uli Kusterer593a33d2014-02-01 12:48:51 +01002522 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002523 Putc( '\n' );
PKEuS1bfb9542013-08-04 13:51:17 +02002524 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002525 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002526 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002527 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002528
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002529 Write ( "<" );
2530 Write ( name );
2531
Lee Thomason624d43f2012-10-12 10:58:48 -07002532 _elementJustOpened = true;
2533 _firstElement = false;
2534 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002535}
2536
2537
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002538void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002539{
Lee Thomason624d43f2012-10-12 10:58:48 -07002540 TIXMLASSERT( _elementJustOpened );
Brad Anderson85aac022017-10-24 21:48:28 -06002541 Putc ( ' ' );
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002542 Write( name );
2543 Write( "=\"" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002544 PrintString( value, false );
Brad Anderson85aac022017-10-24 21:48:28 -06002545 Putc ( '\"' );
Lee Thomason5cae8972012-01-24 18:03:07 -08002546}
2547
2548
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002549void XMLPrinter::PushAttribute( const char* name, int v )
2550{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002551 char buf[BUF_SIZE];
2552 XMLUtil::ToStr( v, buf, BUF_SIZE );
2553 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002554}
2555
2556
2557void XMLPrinter::PushAttribute( const char* name, unsigned v )
2558{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002559 char buf[BUF_SIZE];
2560 XMLUtil::ToStr( v, buf, BUF_SIZE );
2561 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002562}
2563
2564
Lee Thomason51c12712016-06-04 20:18:49 -07002565void XMLPrinter::PushAttribute(const char* name, int64_t v)
2566{
2567 char buf[BUF_SIZE];
2568 XMLUtil::ToStr(v, buf, BUF_SIZE);
2569 PushAttribute(name, buf);
2570}
2571
2572
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002573void XMLPrinter::PushAttribute( const char* name, bool v )
2574{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002575 char buf[BUF_SIZE];
2576 XMLUtil::ToStr( v, buf, BUF_SIZE );
2577 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002578}
2579
2580
2581void XMLPrinter::PushAttribute( const char* name, double v )
2582{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002583 char buf[BUF_SIZE];
2584 XMLUtil::ToStr( v, buf, BUF_SIZE );
2585 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002586}
2587
2588
Uli Kustererca412e82014-02-01 13:35:05 +01002589void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002590{
Lee Thomason624d43f2012-10-12 10:58:48 -07002591 --_depth;
2592 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002593
Lee Thomason624d43f2012-10-12 10:58:48 -07002594 if ( _elementJustOpened ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002595 Write( "/>" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002596 }
2597 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002598 if ( _textDepth < 0 && !compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002599 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002600 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002601 }
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002602 Write ( "</" );
2603 Write ( name );
2604 Write ( ">" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002605 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002606
Lee Thomason624d43f2012-10-12 10:58:48 -07002607 if ( _textDepth == _depth ) {
2608 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002609 }
Uli Kustererca412e82014-02-01 13:35:05 +01002610 if ( _depth == 0 && !compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002611 Putc( '\n' );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002612 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002613 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002614}
2615
2616
Dmitry-Mea092bc12014-12-23 17:57:05 +03002617void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002618{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002619 if ( !_elementJustOpened ) {
2620 return;
2621 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002622 _elementJustOpened = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002623 Putc( '>' );
Lee Thomason5cae8972012-01-24 18:03:07 -08002624}
2625
2626
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002627void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002628{
Lee Thomason624d43f2012-10-12 10:58:48 -07002629 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002630
Dmitry-Mea092bc12014-12-23 17:57:05 +03002631 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002632 if ( cdata ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002633 Write( "<![CDATA[" );
2634 Write( text );
2635 Write( "]]>" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002636 }
2637 else {
2638 PrintString( text, true );
2639 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002640}
2641
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002642void XMLPrinter::PushText( int64_t value )
2643{
2644 char buf[BUF_SIZE];
2645 XMLUtil::ToStr( value, buf, BUF_SIZE );
2646 PushText( buf, false );
2647}
2648
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002649void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002650{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002651 char buf[BUF_SIZE];
2652 XMLUtil::ToStr( value, buf, BUF_SIZE );
2653 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002654}
2655
2656
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002657void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002658{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002659 char buf[BUF_SIZE];
2660 XMLUtil::ToStr( value, buf, BUF_SIZE );
2661 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002662}
2663
2664
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002665void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002666{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002667 char buf[BUF_SIZE];
2668 XMLUtil::ToStr( value, buf, BUF_SIZE );
2669 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002670}
2671
2672
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002673void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002674{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002675 char buf[BUF_SIZE];
2676 XMLUtil::ToStr( value, buf, BUF_SIZE );
2677 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002678}
2679
2680
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002681void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002682{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002683 char buf[BUF_SIZE];
2684 XMLUtil::ToStr( value, buf, BUF_SIZE );
2685 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002686}
2687
Lee Thomason5cae8972012-01-24 18:03:07 -08002688
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002689void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002690{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002691 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002692 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002693 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002694 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002695 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002696 _firstElement = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002697
2698 Write( "<!--" );
2699 Write( comment );
2700 Write( "-->" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002701}
Lee Thomason751da522012-02-10 08:50:51 -08002702
2703
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002704void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002705{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002706 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002707 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002708 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002709 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002710 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002711 _firstElement = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002712
2713 Write( "<?" );
2714 Write( value );
2715 Write( "?>" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002716}
2717
2718
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002719void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002720{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002721 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002722 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002723 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002724 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002725 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002726 _firstElement = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002727
2728 Write( "<!" );
2729 Write( value );
Brad Anderson85aac022017-10-24 21:48:28 -06002730 Putc( '>' );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002731}
2732
2733
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002734bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002735{
Lee Thomason624d43f2012-10-12 10:58:48 -07002736 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002737 if ( doc.HasBOM() ) {
2738 PushHeader( true, false );
2739 }
2740 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002741}
2742
2743
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002744bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002745{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002746 const XMLElement* parentElem = 0;
2747 if ( element.Parent() ) {
2748 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002749 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002750 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002751 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002752 while ( attribute ) {
2753 PushAttribute( attribute->Name(), attribute->Value() );
2754 attribute = attribute->Next();
2755 }
2756 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002757}
2758
2759
Uli Kustererca412e82014-02-01 13:35:05 +01002760bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002761{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002762 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002763 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002764}
2765
2766
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002767bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002768{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002769 PushText( text.Value(), text.CData() );
2770 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002771}
2772
2773
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002774bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002775{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002776 PushComment( comment.Value() );
2777 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002778}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002779
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002780bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002781{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002782 PushDeclaration( declaration.Value() );
2783 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002784}
2785
2786
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002787bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002788{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002789 PushUnknown( unknown.Value() );
2790 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002791}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002792
Lee Thomason685b8952012-11-12 13:00:06 -08002793} // namespace tinyxml2
2794