blob: 3c0fba010dc0d2a3ac342a7405dc03fb93b2ead4 [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 );
orbitcowboy0e7f2892019-01-15 11:28:49 +010048 const int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
Lee Thomason53db4a62015-06-11 22:52:08 -070049 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 {
orbitcowboy0e7f2892019-01-15 11:28:49 +010055 const int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
Lee Thomason53db4a62015-06-11 22:52:08 -070056 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;
orbitcowboy0e7f2892019-01-15 11:28:49 +0100200 const char endChar = *endTag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700201 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;
orbitcowboy0e7f2892019-01-15 11:28:49 +0100313 const char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
Dmitry-Me6f51c802015-03-14 13:25:03 +0300314 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 }
Lee Thomason7fd646a2019-08-10 17:40:19 -0700615 static const char* TRUE[] = { "true", "True", "TRUE", 0 };
616 static const char* FALSE[] = { "false", "False", "FALSE", 0 };
617
618 for (int i = 0; TRUE[i]; ++i) {
619 if (StringEqual(str, TRUE[i])) {
620 *value = true;
621 return true;
622 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700623 }
Lee Thomason7fd646a2019-08-10 17:40:19 -0700624 for (int i = 0; FALSE[i]; ++i) {
625 if (StringEqual(str, FALSE[i])) {
626 *value = false;
627 return true;
628 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700629 }
630 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700631}
632
633
634bool XMLUtil::ToFloat( const char* str, float* value )
635{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700636 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
637 return true;
638 }
639 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700640}
641
Lee Thomason51c12712016-06-04 20:18:49 -0700642
Lee Thomason21be8822012-07-15 17:27:22 -0700643bool XMLUtil::ToDouble( const char* str, double* value )
644{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700645 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
646 return true;
647 }
648 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700649}
650
651
Lee Thomason51c12712016-06-04 20:18:49 -0700652bool XMLUtil::ToInt64(const char* str, int64_t* value)
653{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700654 long long v = 0; // horrible syntax trick to make the compiler happy about %lld
655 if (TIXML_SSCANF(str, "%lld", &v) == 1) {
656 *value = (int64_t)v;
Lee Thomason51c12712016-06-04 20:18:49 -0700657 return true;
658 }
659 return false;
660}
661
662
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700663char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800664{
Dmitry-Me02384662015-03-03 16:02:13 +0300665 TIXMLASSERT( node );
666 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400667 char* const start = p;
kezenatorec694152016-11-26 17:21:43 +1000668 int const startLine = _parseCurLineNum;
kezenator4f756162016-11-29 19:46:27 +1000669 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300670 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300671 *node = 0;
672 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700673 return p;
674 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800675
Dmitry-Me962083b2015-05-26 11:38:30 +0300676 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700677 static const char* xmlHeader = { "<?" };
678 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700679 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300680 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700681 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800682
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700683 static const int xmlHeaderLen = 2;
684 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700685 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300686 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700687 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800688
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700689 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
690 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400691 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700692 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300693 returnNode = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000694 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700695 p += xmlHeaderLen;
696 }
697 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300698 returnNode = CreateUnlinkedNode<XMLComment>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000699 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700700 p += commentHeaderLen;
701 }
702 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300703 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700704 returnNode = text;
kezenatorec694152016-11-26 17:21:43 +1000705 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700706 p += cdataHeaderLen;
707 text->SetCData( true );
708 }
709 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300710 returnNode = CreateUnlinkedNode<XMLUnknown>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000711 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700712 p += dtdHeaderLen;
713 }
714 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300715 returnNode = CreateUnlinkedNode<XMLElement>( _elementPool );
kezenatorec694152016-11-26 17:21:43 +1000716 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700717 p += elementHeaderLen;
718 }
719 else {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300720 returnNode = CreateUnlinkedNode<XMLText>( _textPool );
kezenatorec694152016-11-26 17:21:43 +1000721 returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700722 p = start; // Back it up, all the text counts.
kezenatorec694152016-11-26 17:21:43 +1000723 _parseCurLineNum = startLine;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700724 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800725
Dmitry-Me02384662015-03-03 16:02:13 +0300726 TIXMLASSERT( returnNode );
727 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700728 *node = returnNode;
729 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800730}
731
732
Lee Thomason751da522012-02-10 08:50:51 -0800733bool XMLDocument::Accept( XMLVisitor* visitor ) const
734{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300735 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700736 if ( visitor->VisitEnter( *this ) ) {
737 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
738 if ( !node->Accept( visitor ) ) {
739 break;
740 }
741 }
742 }
743 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800744}
Lee Thomason56bdd022012-02-09 18:16:58 -0800745
746
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800747// --------- XMLNode ----------- //
748
749XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700750 _document( doc ),
751 _parent( 0 ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +0200752 _value(),
kezenatorec694152016-11-26 17:21:43 +1000753 _parseLineNum( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -0700754 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200755 _prev( 0 ), _next( 0 ),
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700756 _userData( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200757 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800758{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800759}
760
761
762XMLNode::~XMLNode()
763{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700764 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700765 if ( _parent ) {
766 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700767 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800768}
769
Gumichan010f1fa6d2018-02-01 14:16:24 +0100770const char* XMLNode::Value() const
Michael Daumling21626882013-10-22 17:03:37 +0200771{
Dmitry-Mecaa72a62016-08-10 17:34:34 +0300772 // Edge case: XMLDocuments don't have a Value. Return null.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530773 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530774 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200775 return _value.GetStr();
776}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800777
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800778void XMLNode::SetValue( const char* str, bool staticMem )
779{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700780 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700781 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700782 }
783 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700784 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700785 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800786}
787
Dmitry-Me3f63f212017-06-19 18:25:19 +0300788XMLNode* XMLNode::DeepClone(XMLDocument* target) const
Lee Thomason7085f002017-06-01 18:09:43 -0700789{
Dmitry-Me3f63f212017-06-19 18:25:19 +0300790 XMLNode* clone = this->ShallowClone(target);
Lee Thomason7085f002017-06-01 18:09:43 -0700791 if (!clone) return 0;
792
793 for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) {
Dmitry-Me3f63f212017-06-19 18:25:19 +0300794 XMLNode* childClone = child->DeepClone(target);
Lee Thomason7085f002017-06-01 18:09:43 -0700795 TIXMLASSERT(childClone);
796 clone->InsertEndChild(childClone);
797 }
798 return clone;
799}
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800800
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800801void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800802{
Lee Thomason624d43f2012-10-12 10:58:48 -0700803 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300804 TIXMLASSERT( _lastChild );
Dmitry-Me9cb4eca2016-08-18 18:10:59 +0300805 DeleteChild( _firstChild );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700806 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700807 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800808}
809
810
811void XMLNode::Unlink( XMLNode* child )
812{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300813 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300814 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300815 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700816 if ( child == _firstChild ) {
817 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700818 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700819 if ( child == _lastChild ) {
820 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700821 }
Lee Thomasond923c672012-01-23 08:44:25 -0800822
Lee Thomason624d43f2012-10-12 10:58:48 -0700823 if ( child->_prev ) {
824 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700825 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700826 if ( child->_next ) {
827 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700828 }
Lee Thomason8a763612017-06-16 09:30:16 -0700829 child->_next = 0;
830 child->_prev = 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700831 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800832}
833
834
U-Stream\Leeae25a442012-02-17 17:48:16 -0800835void XMLNode::DeleteChild( XMLNode* node )
836{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300837 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300838 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700839 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100840 Unlink( node );
Lee Thomason816d3fa2017-06-05 14:35:55 -0700841 TIXMLASSERT(node->_prev == 0);
842 TIXMLASSERT(node->_next == 0);
843 TIXMLASSERT(node->_parent == 0);
Dmitry-Mee3225b12014-09-03 11:03:11 +0400844 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800845}
846
847
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800848XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
849{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300850 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300851 if ( addThis->_document != _document ) {
852 TIXMLASSERT( false );
853 return 0;
854 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800855 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700856
Lee Thomason624d43f2012-10-12 10:58:48 -0700857 if ( _lastChild ) {
858 TIXMLASSERT( _firstChild );
859 TIXMLASSERT( _lastChild->_next == 0 );
860 _lastChild->_next = addThis;
861 addThis->_prev = _lastChild;
862 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800863
Lee Thomason624d43f2012-10-12 10:58:48 -0700864 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700865 }
866 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700867 TIXMLASSERT( _firstChild == 0 );
868 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800869
Lee Thomason624d43f2012-10-12 10:58:48 -0700870 addThis->_prev = 0;
871 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700872 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700873 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700874 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800875}
876
877
Lee Thomason1ff38e02012-02-14 18:18:16 -0800878XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
879{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300880 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300881 if ( addThis->_document != _document ) {
882 TIXMLASSERT( false );
883 return 0;
884 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800885 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700886
Lee Thomason624d43f2012-10-12 10:58:48 -0700887 if ( _firstChild ) {
888 TIXMLASSERT( _lastChild );
889 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800890
Lee Thomason624d43f2012-10-12 10:58:48 -0700891 _firstChild->_prev = addThis;
892 addThis->_next = _firstChild;
893 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800894
Lee Thomason624d43f2012-10-12 10:58:48 -0700895 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700896 }
897 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700898 TIXMLASSERT( _lastChild == 0 );
899 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800900
Lee Thomason624d43f2012-10-12 10:58:48 -0700901 addThis->_prev = 0;
902 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700903 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700904 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400905 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800906}
907
908
909XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
910{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300911 TIXMLASSERT( addThis );
912 if ( addThis->_document != _document ) {
913 TIXMLASSERT( false );
914 return 0;
915 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700916
Dmitry-Meabb2d042014-12-09 12:59:31 +0300917 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700918
Lee Thomason624d43f2012-10-12 10:58:48 -0700919 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300920 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700921 return 0;
922 }
Dmitry-Mee8f4a8b2017-09-15 19:34:36 +0300923 if ( afterThis == addThis ) {
924 // Current state: BeforeThis -> AddThis -> OneAfterAddThis
925 // Now AddThis must disappear from it's location and then
926 // reappear between BeforeThis and OneAfterAddThis.
927 // So just leave it where it is.
928 return addThis;
929 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800930
Lee Thomason624d43f2012-10-12 10:58:48 -0700931 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700932 // The last node or the only node.
933 return InsertEndChild( addThis );
934 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800935 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700936 addThis->_prev = afterThis;
937 addThis->_next = afterThis->_next;
938 afterThis->_next->_prev = addThis;
939 afterThis->_next = addThis;
940 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700941 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800942}
943
944
945
946
Dmitry-Me886ad972015-07-22 11:00:51 +0300947const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800948{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300949 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300950 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700951 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300952 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700953 }
954 }
955 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800956}
957
958
Dmitry-Me886ad972015-07-22 11:00:51 +0300959const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800960{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300961 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300962 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700963 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300964 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700965 }
966 }
967 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800968}
969
970
Dmitry-Me886ad972015-07-22 11:00:51 +0300971const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800972{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300973 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300974 const XMLElement* element = node->ToElementWithName( name );
975 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400976 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700977 }
978 }
979 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800980}
981
982
Dmitry-Me886ad972015-07-22 11:00:51 +0300983const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800984{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300985 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300986 const XMLElement* element = node->ToElementWithName( name );
987 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400988 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700989 }
990 }
991 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800992}
993
994
Dmitry-Me10b8ecc2017-04-12 17:57:44 +0300995char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -0800996{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700997 // This is a recursive method, but thinking about it "at the current level"
998 // it is a pretty simple flat list:
999 // <foo/>
1000 // <!-- comment -->
1001 //
1002 // With a special case:
1003 // <foo>
1004 // </foo>
1005 // <!-- comment -->
1006 //
1007 // Where the closing element (/foo) *must* be the next thing after the opening
1008 // element, and the names must match. BUT the tricky bit is that the closing
1009 // element will be read by the child.
1010 //
1011 // 'endTag' is the end tag for this node, it is returned by a call to a child.
1012 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001013
Lee Thomasond946dda2018-04-05 09:11:08 -07001014 XMLDocument::DepthTracker tracker(_document);
1015 if (_document->Error())
1016 return 0;
1017
1018 while( p && *p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001019 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -08001020
Lee Thomason624d43f2012-10-12 10:58:48 -07001021 p = _document->Identify( p, &node );
Dmitry-Me43364312016-11-07 18:48:50 +03001022 TIXMLASSERT( p );
Dmitry-Me9fcb8762015-03-05 17:53:34 +03001023 if ( node == 0 ) {
1024 break;
1025 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001026
orbitcowboy0e7f2892019-01-15 11:28:49 +01001027 const int initialLineNum = node->_parseLineNum;
kezenatorec694152016-11-26 17:21:43 +10001028
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001029 StrPair endTag;
kezenator4f756162016-11-29 19:46:27 +10001030 p = node->ParseDeep( p, &endTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001031 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001032 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -07001033 if ( !_document->Error() ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001034 _document->SetError( XML_ERROR_PARSING, initialLineNum, 0);
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001035 }
1036 break;
1037 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001038
orbitcowboy0e7f2892019-01-15 11:28:49 +01001039 const XMLDeclaration* const decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301040 if ( decl ) {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001041 // Declarations are only allowed at document level
Lee Thomasondb13a822018-07-28 14:56:20 -07001042 //
1043 // Multiple declarations are allowed but all declarations
1044 // must occur before anything else.
1045 //
1046 // Optimized due to a security test case. If the first node is
1047 // a declaration, and the last node is a declaration, then only
orbitcowboy0e7f2892019-01-15 11:28:49 +01001048 // declarations have so far been added.
Lee Thomasondb13a822018-07-28 14:56:20 -07001049 bool wellLocated = false;
1050
1051 if (ToDocument()) {
1052 if (FirstChild()) {
1053 wellLocated =
1054 FirstChild() &&
1055 FirstChild()->ToDeclaration() &&
1056 LastChild() &&
1057 LastChild()->ToDeclaration();
1058 }
1059 else {
1060 wellLocated = true;
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301061 }
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001062 }
1063 if ( !wellLocated ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07001064 _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, "XMLDeclaration value=%s", decl->Value());
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001065 DeleteNode( node );
1066 break;
1067 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301068 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301069
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001070 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001071 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -05001072 // We read the end tag. Return it to the parent.
1073 if ( ele->ClosingType() == XMLElement::CLOSING ) {
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001074 if ( parentEndTag ) {
1075 ele->_value.TransferTo( parentEndTag );
JayXone4bf6e32014-12-26 01:00:24 -05001076 }
1077 node->_memPool->SetTracked(); // created and then immediately deleted.
1078 DeleteNode( node );
1079 return p;
1080 }
1081
1082 // Handle an end tag returned to this level.
1083 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001084 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001085 if ( endTag.Empty() ) {
1086 if ( ele->ClosingType() == XMLElement::OPEN ) {
1087 mismatch = true;
1088 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001089 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001090 else {
1091 if ( ele->ClosingType() != XMLElement::OPEN ) {
1092 mismatch = true;
1093 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001094 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001095 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001096 }
1097 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001098 if ( mismatch ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07001099 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, "XMLElement name=%s", ele->Name());
JayXondbfdd8f2014-12-12 20:07:14 -05001100 DeleteNode( node );
1101 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001102 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001103 }
JayXondbfdd8f2014-12-12 20:07:14 -05001104 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001105 }
1106 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001107}
1108
Lee Thomason816d3fa2017-06-05 14:35:55 -07001109/*static*/ void XMLNode::DeleteNode( XMLNode* node )
Dmitry-Mee3225b12014-09-03 11:03:11 +04001110{
1111 if ( node == 0 ) {
1112 return;
1113 }
Lee Thomason816d3fa2017-06-05 14:35:55 -07001114 TIXMLASSERT(node->_document);
1115 if (!node->ToDocument()) {
1116 node->_document->MarkInUse(node);
1117 }
1118
Dmitry-Mee3225b12014-09-03 11:03:11 +04001119 MemPool* pool = node->_memPool;
1120 node->~XMLNode();
1121 pool->Free( node );
1122}
1123
Lee Thomason3cebdc42015-01-05 17:16:28 -08001124void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001125{
1126 TIXMLASSERT( insertThis );
1127 TIXMLASSERT( insertThis->_document == _document );
1128
Lee Thomason816d3fa2017-06-05 14:35:55 -07001129 if (insertThis->_parent) {
Dmitry-Me74e39402015-01-01 16:26:17 +03001130 insertThis->_parent->Unlink( insertThis );
Lee Thomason816d3fa2017-06-05 14:35:55 -07001131 }
1132 else {
1133 insertThis->_document->MarkInUse(insertThis);
Dmitry-Me74e39402015-01-01 16:26:17 +03001134 insertThis->_memPool->SetTracked();
Lee Thomason816d3fa2017-06-05 14:35:55 -07001135 }
Dmitry-Me74e39402015-01-01 16:26:17 +03001136}
1137
Dmitry-Meecb9b072016-10-12 16:44:59 +03001138const XMLElement* XMLNode::ToElementWithName( const char* name ) const
1139{
1140 const XMLElement* element = this->ToElement();
1141 if ( element == 0 ) {
1142 return 0;
1143 }
1144 if ( name == 0 ) {
1145 return element;
1146 }
1147 if ( XMLUtil::StringEqual( element->Name(), name ) ) {
1148 return element;
1149 }
1150 return 0;
1151}
1152
Lee Thomason5492a1c2012-01-23 15:32:10 -08001153// --------- XMLText ---------- //
kezenator4f756162016-11-29 19:46:27 +10001154char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001155{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001156 if ( this->CData() ) {
kezenator4f756162016-11-29 19:46:27 +10001157 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001158 if ( !p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001159 _document->SetError( XML_ERROR_PARSING_CDATA, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001160 }
1161 return p;
1162 }
1163 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001164 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1165 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001166 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001167 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001168
kezenator4f756162016-11-29 19:46:27 +10001169 p = _value.ParseText( p, "<", flags, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001170 if ( p && *p ) {
1171 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001172 }
1173 if ( !p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001174 _document->SetError( XML_ERROR_PARSING_TEXT, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001175 }
1176 }
1177 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001178}
1179
1180
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001181XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1182{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001183 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001184 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001185 }
1186 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1187 text->SetCData( this->CData() );
1188 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001189}
1190
1191
1192bool XMLText::ShallowEqual( const XMLNode* compare ) const
1193{
Dmitry-Meba68a3a2017-03-21 11:39:48 +03001194 TIXMLASSERT( compare );
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001195 const XMLText* text = compare->ToText();
1196 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001197}
1198
1199
Lee Thomason56bdd022012-02-09 18:16:58 -08001200bool XMLText::Accept( XMLVisitor* visitor ) const
1201{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001202 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001203 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001204}
1205
1206
Lee Thomason3f57d272012-01-11 15:30:03 -08001207// --------- XMLComment ---------- //
1208
Lee Thomasone4422302012-01-20 17:59:50 -08001209XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001210{
1211}
1212
1213
Lee Thomasonce0763e2012-01-11 15:43:54 -08001214XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001215{
Lee Thomason3f57d272012-01-11 15:30:03 -08001216}
1217
1218
kezenator4f756162016-11-29 19:46:27 +10001219char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason3f57d272012-01-11 15:30:03 -08001220{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001221 // Comment parses as text.
kezenator4f756162016-11-29 19:46:27 +10001222 p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001223 if ( p == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001224 _document->SetError( XML_ERROR_PARSING_COMMENT, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001225 }
1226 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001227}
1228
1229
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001230XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1231{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001232 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001233 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001234 }
1235 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1236 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001237}
1238
1239
1240bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1241{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001242 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001243 const XMLComment* comment = compare->ToComment();
1244 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001245}
1246
1247
Lee Thomason751da522012-02-10 08:50:51 -08001248bool XMLComment::Accept( XMLVisitor* visitor ) const
1249{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001250 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001251 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001252}
Lee Thomason56bdd022012-02-09 18:16:58 -08001253
1254
Lee Thomason50f97b22012-02-11 16:33:40 -08001255// --------- XMLDeclaration ---------- //
1256
1257XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1258{
1259}
1260
1261
1262XMLDeclaration::~XMLDeclaration()
1263{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001264 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001265}
1266
1267
kezenator4f756162016-11-29 19:46:27 +10001268char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001269{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001270 // Declaration parses as text.
kezenator4f756162016-11-29 19:46:27 +10001271 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001272 if ( p == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001273 _document->SetError( XML_ERROR_PARSING_DECLARATION, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001274 }
1275 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001276}
1277
1278
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001279XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1280{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001281 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001282 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001283 }
1284 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1285 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001286}
1287
1288
1289bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1290{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001291 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001292 const XMLDeclaration* declaration = compare->ToDeclaration();
1293 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001294}
1295
1296
1297
Lee Thomason50f97b22012-02-11 16:33:40 -08001298bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1299{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001300 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001301 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001302}
1303
1304// --------- XMLUnknown ---------- //
1305
1306XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1307{
1308}
1309
1310
1311XMLUnknown::~XMLUnknown()
1312{
1313}
1314
1315
kezenator4f756162016-11-29 19:46:27 +10001316char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001317{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001318 // Unknown parses as text.
kezenator4f756162016-11-29 19:46:27 +10001319 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001320 if ( !p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07001321 _document->SetError( XML_ERROR_PARSING_UNKNOWN, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001322 }
1323 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001324}
1325
1326
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001327XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1328{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001329 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001330 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001331 }
1332 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1333 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001334}
1335
1336
1337bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1338{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001339 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001340 const XMLUnknown* unknown = compare->ToUnknown();
1341 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001342}
1343
1344
Lee Thomason50f97b22012-02-11 16:33:40 -08001345bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1346{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001347 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001348 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001349}
1350
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001351// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001352
Gumichan010f1fa6d2018-02-01 14:16:24 +01001353const char* XMLAttribute::Name() const
Michael Daumling21626882013-10-22 17:03:37 +02001354{
1355 return _name.GetStr();
1356}
1357
Gumichan010f1fa6d2018-02-01 14:16:24 +01001358const char* XMLAttribute::Value() const
Michael Daumling21626882013-10-22 17:03:37 +02001359{
1360 return _value.GetStr();
1361}
1362
kezenator4f756162016-11-29 19:46:27 +10001363char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001364{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001365 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001366 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001367 if ( !p || !*p ) {
1368 return 0;
1369 }
Lee Thomason22aead12012-01-23 13:29:35 -08001370
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001371 // Skip white space before =
kezenator4f756162016-11-29 19:46:27 +10001372 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001373 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001374 return 0;
1375 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001376
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001377 ++p; // move up to opening quote
kezenator4f756162016-11-29 19:46:27 +10001378 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001379 if ( *p != '\"' && *p != '\'' ) {
1380 return 0;
1381 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001382
orbitcowboy0e7f2892019-01-15 11:28:49 +01001383 const char endTag[2] = { *p, 0 };
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001384 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001385
kezenator4f756162016-11-29 19:46:27 +10001386 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001387 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001388}
1389
1390
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001391void XMLAttribute::SetName( const char* n )
1392{
Lee Thomason624d43f2012-10-12 10:58:48 -07001393 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001394}
1395
1396
Lee Thomason2fa81722012-11-09 12:37:46 -08001397XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001398{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001399 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001400 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001401 }
1402 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001403}
1404
1405
Lee Thomason2fa81722012-11-09 12:37:46 -08001406XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001407{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001408 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001409 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001410 }
1411 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001412}
1413
1414
Lee Thomason51c12712016-06-04 20:18:49 -07001415XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1416{
1417 if (XMLUtil::ToInt64(Value(), value)) {
1418 return XML_SUCCESS;
1419 }
1420 return XML_WRONG_ATTRIBUTE_TYPE;
1421}
1422
1423
Lee Thomason2fa81722012-11-09 12:37:46 -08001424XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001425{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001426 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001427 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001428 }
1429 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001430}
1431
1432
Lee Thomason2fa81722012-11-09 12:37:46 -08001433XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001434{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001435 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001436 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001437 }
1438 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001439}
1440
1441
Lee Thomason2fa81722012-11-09 12:37:46 -08001442XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001443{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001444 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001445 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001446 }
1447 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001448}
1449
1450
1451void XMLAttribute::SetAttribute( const char* v )
1452{
Lee Thomason624d43f2012-10-12 10:58:48 -07001453 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001454}
1455
1456
Lee Thomason1ff38e02012-02-14 18:18:16 -08001457void XMLAttribute::SetAttribute( int v )
1458{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001459 char buf[BUF_SIZE];
1460 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001461 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001462}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001463
1464
1465void XMLAttribute::SetAttribute( unsigned v )
1466{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001467 char buf[BUF_SIZE];
1468 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001469 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001470}
1471
1472
Lee Thomason51c12712016-06-04 20:18:49 -07001473void XMLAttribute::SetAttribute(int64_t v)
1474{
1475 char buf[BUF_SIZE];
1476 XMLUtil::ToStr(v, buf, BUF_SIZE);
1477 _value.SetStr(buf);
1478}
1479
1480
1481
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001482void XMLAttribute::SetAttribute( bool v )
1483{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001484 char buf[BUF_SIZE];
1485 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001486 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001487}
1488
1489void XMLAttribute::SetAttribute( double v )
1490{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001491 char buf[BUF_SIZE];
1492 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001493 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001494}
1495
1496void XMLAttribute::SetAttribute( float v )
1497{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001498 char buf[BUF_SIZE];
1499 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001500 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001501}
1502
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001503
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001504// --------- XMLElement ---------- //
1505XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Dmitry-Mee5035632017-04-05 18:02:40 +03001506 _closingType( OPEN ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001507 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001508{
1509}
1510
1511
1512XMLElement::~XMLElement()
1513{
Lee Thomason624d43f2012-10-12 10:58:48 -07001514 while( _rootAttribute ) {
1515 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001516 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001517 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001518 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001519}
1520
1521
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001522const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1523{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001524 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001525 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1526 return a;
1527 }
1528 }
1529 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001530}
1531
1532
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001533const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001534{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001535 const XMLAttribute* a = FindAttribute( name );
1536 if ( !a ) {
1537 return 0;
1538 }
1539 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1540 return a->Value();
1541 }
1542 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001543}
1544
Gumichan010f1fa6d2018-02-01 14:16:24 +01001545int XMLElement::IntAttribute(const char* name, int defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001546{
1547 int i = defaultValue;
1548 QueryIntAttribute(name, &i);
1549 return i;
1550}
1551
Gumichan010f1fa6d2018-02-01 14:16:24 +01001552unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001553{
1554 unsigned i = defaultValue;
1555 QueryUnsignedAttribute(name, &i);
1556 return i;
1557}
1558
Gumichan010f1fa6d2018-02-01 14:16:24 +01001559int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001560{
1561 int64_t i = defaultValue;
1562 QueryInt64Attribute(name, &i);
1563 return i;
1564}
1565
Gumichan010f1fa6d2018-02-01 14:16:24 +01001566bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001567{
1568 bool b = defaultValue;
1569 QueryBoolAttribute(name, &b);
1570 return b;
1571}
1572
Gumichan010f1fa6d2018-02-01 14:16:24 +01001573double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001574{
1575 double d = defaultValue;
1576 QueryDoubleAttribute(name, &d);
1577 return d;
1578}
1579
Gumichan010f1fa6d2018-02-01 14:16:24 +01001580float XMLElement::FloatAttribute(const char* name, float defaultValue) const
Josh Wittnercf3dd092016-10-11 18:57:17 -07001581{
1582 float f = defaultValue;
1583 QueryFloatAttribute(name, &f);
1584 return f;
1585}
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001586
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001587const char* XMLElement::GetText() const
1588{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001589 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001590 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001591 }
1592 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001593}
1594
1595
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001596void XMLElement::SetText( const char* inText )
1597{
Uli Kusterer869bb592014-01-21 01:36:16 +01001598 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001599 FirstChild()->SetValue( inText );
1600 else {
1601 XMLText* theText = GetDocument()->NewText( inText );
1602 InsertFirstChild( theText );
1603 }
1604}
1605
Lee Thomason5bb2d802014-01-24 10:42:57 -08001606
Gumichan010f1fa6d2018-02-01 14:16:24 +01001607void XMLElement::SetText( int v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001608{
1609 char buf[BUF_SIZE];
1610 XMLUtil::ToStr( v, buf, BUF_SIZE );
1611 SetText( buf );
1612}
1613
1614
Gumichan010f1fa6d2018-02-01 14:16:24 +01001615void XMLElement::SetText( unsigned v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001616{
1617 char buf[BUF_SIZE];
1618 XMLUtil::ToStr( v, buf, BUF_SIZE );
1619 SetText( buf );
1620}
1621
1622
Lee Thomason51c12712016-06-04 20:18:49 -07001623void XMLElement::SetText(int64_t v)
1624{
1625 char buf[BUF_SIZE];
1626 XMLUtil::ToStr(v, buf, BUF_SIZE);
1627 SetText(buf);
1628}
1629
1630
1631void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001632{
1633 char buf[BUF_SIZE];
1634 XMLUtil::ToStr( v, buf, BUF_SIZE );
1635 SetText( buf );
1636}
1637
1638
Gumichan010f1fa6d2018-02-01 14:16:24 +01001639void XMLElement::SetText( float v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001640{
1641 char buf[BUF_SIZE];
1642 XMLUtil::ToStr( v, buf, BUF_SIZE );
1643 SetText( buf );
1644}
1645
1646
Gumichan010f1fa6d2018-02-01 14:16:24 +01001647void XMLElement::SetText( double v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001648{
1649 char buf[BUF_SIZE];
1650 XMLUtil::ToStr( v, buf, BUF_SIZE );
1651 SetText( buf );
1652}
1653
1654
MortenMacFly4ee49f12013-01-14 20:03:14 +01001655XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001656{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001657 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001658 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001659 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001660 return XML_SUCCESS;
1661 }
1662 return XML_CAN_NOT_CONVERT_TEXT;
1663 }
1664 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001665}
1666
1667
MortenMacFly4ee49f12013-01-14 20:03:14 +01001668XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001669{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001670 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001671 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001672 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001673 return XML_SUCCESS;
1674 }
1675 return XML_CAN_NOT_CONVERT_TEXT;
1676 }
1677 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001678}
1679
1680
Lee Thomason51c12712016-06-04 20:18:49 -07001681XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1682{
1683 if (FirstChild() && FirstChild()->ToText()) {
1684 const char* t = FirstChild()->Value();
1685 if (XMLUtil::ToInt64(t, ival)) {
1686 return XML_SUCCESS;
1687 }
1688 return XML_CAN_NOT_CONVERT_TEXT;
1689 }
1690 return XML_NO_TEXT_NODE;
1691}
1692
1693
MortenMacFly4ee49f12013-01-14 20:03:14 +01001694XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001695{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001696 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001697 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001698 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001699 return XML_SUCCESS;
1700 }
1701 return XML_CAN_NOT_CONVERT_TEXT;
1702 }
1703 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001704}
1705
1706
MortenMacFly4ee49f12013-01-14 20:03:14 +01001707XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001708{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001709 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001710 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001711 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001712 return XML_SUCCESS;
1713 }
1714 return XML_CAN_NOT_CONVERT_TEXT;
1715 }
1716 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001717}
1718
1719
MortenMacFly4ee49f12013-01-14 20:03:14 +01001720XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001721{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001722 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001723 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001724 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001725 return XML_SUCCESS;
1726 }
1727 return XML_CAN_NOT_CONVERT_TEXT;
1728 }
1729 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001730}
1731
Josh Wittnercf3dd092016-10-11 18:57:17 -07001732int XMLElement::IntText(int defaultValue) const
1733{
1734 int i = defaultValue;
1735 QueryIntText(&i);
1736 return i;
1737}
1738
1739unsigned XMLElement::UnsignedText(unsigned defaultValue) const
1740{
1741 unsigned i = defaultValue;
1742 QueryUnsignedText(&i);
1743 return i;
1744}
1745
1746int64_t XMLElement::Int64Text(int64_t defaultValue) const
1747{
1748 int64_t i = defaultValue;
1749 QueryInt64Text(&i);
1750 return i;
1751}
1752
1753bool XMLElement::BoolText(bool defaultValue) const
1754{
1755 bool b = defaultValue;
1756 QueryBoolText(&b);
1757 return b;
1758}
1759
1760double XMLElement::DoubleText(double defaultValue) const
1761{
1762 double d = defaultValue;
1763 QueryDoubleText(&d);
1764 return d;
1765}
1766
1767float XMLElement::FloatText(float defaultValue) const
1768{
1769 float f = defaultValue;
1770 QueryFloatText(&f);
1771 return f;
1772}
Lee Thomason21be8822012-07-15 17:27:22 -07001773
1774
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001775XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1776{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001777 XMLAttribute* last = 0;
1778 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001779 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001780 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001781 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001782 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1783 break;
1784 }
1785 }
1786 if ( !attrib ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001787 attrib = CreateAttribute();
1788 TIXMLASSERT( attrib );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001789 if ( last ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001790 TIXMLASSERT( last->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001791 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001792 }
1793 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001794 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001795 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001796 }
1797 attrib->SetName( name );
1798 }
1799 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001800}
1801
1802
U-Stream\Leeae25a442012-02-17 17:48:16 -08001803void XMLElement::DeleteAttribute( const char* name )
1804{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001805 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001806 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001807 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1808 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001809 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001810 }
1811 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001812 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001813 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001814 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001815 break;
1816 }
1817 prev = a;
1818 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001819}
1820
1821
kezenator4f756162016-11-29 19:46:27 +10001822char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001823{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001824 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001825
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001826 // Read the attributes.
1827 while( p ) {
kezenator4f756162016-11-29 19:46:27 +10001828 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001829 if ( !(*p) ) {
Lee Thomasonf49b9652017-10-11 10:57:49 -07001830 _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, "XMLElement name=%s", Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001831 return 0;
1832 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001833
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001834 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001835 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001836 XMLAttribute* attrib = CreateAttribute();
1837 TIXMLASSERT( attrib );
kezenatorec694152016-11-26 17:21:43 +10001838 attrib->_parseLineNum = _document->_parseCurLineNum;
Lee Thomasond1983222012-02-06 08:41:24 -08001839
orbitcowboy0e7f2892019-01-15 11:28:49 +01001840 const int attrLineNum = attrib->_parseLineNum;
kezenatorec694152016-11-26 17:21:43 +10001841
kezenator4f756162016-11-29 19:46:27 +10001842 p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001843 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001844 DeleteAttribute( attrib );
Lee Thomasonf49b9652017-10-11 10:57:49 -07001845 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, attrLineNum, "XMLElement name=%s", Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001846 return 0;
1847 }
1848 // There is a minor bug here: if the attribute in the source xml
1849 // document is duplicated, it will not be detected and the
1850 // attribute will be doubly added. However, tracking the 'prevAttribute'
1851 // avoids re-scanning the attribute list. Preferring performance for
1852 // now, may reconsider in the future.
1853 if ( prevAttribute ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001854 TIXMLASSERT( prevAttribute->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001855 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001856 }
1857 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001858 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001859 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001860 }
1861 prevAttribute = attrib;
1862 }
1863 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001864 else if ( *p == '>' ) {
1865 ++p;
1866 break;
1867 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001868 // end of the tag
1869 else if ( *p == '/' && *(p+1) == '>' ) {
1870 _closingType = CLOSED;
1871 return p+2; // done; sealed element.
1872 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001873 else {
Lee Thomasonaa188392017-09-19 17:54:31 -07001874 _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001875 return 0;
1876 }
1877 }
1878 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001879}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001880
Dmitry-Mee3225b12014-09-03 11:03:11 +04001881void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1882{
1883 if ( attribute == 0 ) {
1884 return;
1885 }
1886 MemPool* pool = attribute->_memPool;
1887 attribute->~XMLAttribute();
1888 pool->Free( attribute );
1889}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001890
Dmitry-Mea60caa22016-11-22 18:28:08 +03001891XMLAttribute* XMLElement::CreateAttribute()
1892{
1893 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
1894 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
Dmitry-Me7221b492017-03-03 15:45:51 +03001895 TIXMLASSERT( attrib );
Dmitry-Mea60caa22016-11-22 18:28:08 +03001896 attrib->_memPool = &_document->_attributePool;
1897 attrib->_memPool->SetTracked();
1898 return attrib;
1899}
1900
Lee Thomason67d61312012-01-24 16:01:51 -08001901//
1902// <ele></ele>
1903// <ele>foo<b>bar</b></ele>
1904//
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001905char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -08001906{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001907 // Read the element name.
kezenator4f756162016-11-29 19:46:27 +10001908 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomason67d61312012-01-24 16:01:51 -08001909
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001910 // The closing element is the </element> form. It is
1911 // parsed just like a regular element then deleted from
1912 // the DOM.
1913 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001914 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001915 ++p;
1916 }
Lee Thomason67d61312012-01-24 16:01:51 -08001917
Lee Thomason624d43f2012-10-12 10:58:48 -07001918 p = _value.ParseName( p );
1919 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001920 return 0;
1921 }
Lee Thomason67d61312012-01-24 16:01:51 -08001922
kezenator4f756162016-11-29 19:46:27 +10001923 p = ParseAttributes( p, curLineNumPtr );
Dmitry-Mee5035632017-04-05 18:02:40 +03001924 if ( !p || !*p || _closingType != OPEN ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001925 return p;
1926 }
Lee Thomason67d61312012-01-24 16:01:51 -08001927
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001928 p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001929 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001930}
1931
1932
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001933
1934XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1935{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001936 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001937 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001938 }
1939 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1940 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1941 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1942 }
1943 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001944}
1945
1946
1947bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1948{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001949 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001950 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001951 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001952
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001953 const XMLAttribute* a=FirstAttribute();
1954 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001955
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001956 while ( a && b ) {
1957 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1958 return false;
1959 }
1960 a = a->Next();
1961 b = b->Next();
1962 }
1963 if ( a || b ) {
1964 // different count
1965 return false;
1966 }
1967 return true;
1968 }
1969 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001970}
1971
1972
Lee Thomason751da522012-02-10 08:50:51 -08001973bool XMLElement::Accept( XMLVisitor* visitor ) const
1974{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001975 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001976 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001977 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1978 if ( !node->Accept( visitor ) ) {
1979 break;
1980 }
1981 }
1982 }
1983 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001984}
Lee Thomason56bdd022012-02-09 18:16:58 -08001985
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001986
Lee Thomason3f57d272012-01-11 15:30:03 -08001987// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001988
1989// Warning: List must match 'enum XMLError'
1990const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1991 "XML_SUCCESS",
1992 "XML_NO_ATTRIBUTE",
1993 "XML_WRONG_ATTRIBUTE_TYPE",
1994 "XML_ERROR_FILE_NOT_FOUND",
1995 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1996 "XML_ERROR_FILE_READ_ERROR",
Lee Thomason331596e2014-09-11 14:56:43 -07001997 "XML_ERROR_PARSING_ELEMENT",
1998 "XML_ERROR_PARSING_ATTRIBUTE",
Lee Thomason331596e2014-09-11 14:56:43 -07001999 "XML_ERROR_PARSING_TEXT",
2000 "XML_ERROR_PARSING_CDATA",
2001 "XML_ERROR_PARSING_COMMENT",
2002 "XML_ERROR_PARSING_DECLARATION",
2003 "XML_ERROR_PARSING_UNKNOWN",
2004 "XML_ERROR_EMPTY_DOCUMENT",
2005 "XML_ERROR_MISMATCHED_ELEMENT",
2006 "XML_ERROR_PARSING",
2007 "XML_CAN_NOT_CONVERT_TEXT",
Lee Thomasond946dda2018-04-05 09:11:08 -07002008 "XML_NO_TEXT_NODE",
2009 "XML_ELEMENT_DEPTH_EXCEEDED"
Lee Thomason331596e2014-09-11 14:56:43 -07002010};
2011
2012
Dmitry-Meae8a82a2017-03-03 15:40:32 +03002013XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002014 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002015 _writeBOM( false ),
2016 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07002017 _errorID(XML_SUCCESS),
Dmitry-Meae8a82a2017-03-03 15:40:32 +03002018 _whitespaceMode( whitespaceMode ),
Lee Thomason0c0f98b2017-10-11 11:03:49 -07002019 _errorStr(),
Dmitry-Mef89bd3e2017-01-18 18:33:55 +03002020 _errorLineNum( 0 ),
2021 _charBuffer( 0 ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002022 _parseCurLineNum( 0 ),
Lee Thomasond946dda2018-04-05 09:11:08 -07002023 _parsingDepth(0),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002024 _unlinked(),
2025 _elementPool(),
2026 _attributePool(),
2027 _textPool(),
2028 _commentPool()
U-Lama\Lee560bd472011-12-28 19:42:49 -08002029{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03002030 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
2031 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08002032}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002033
2034
Lee Thomason3f57d272012-01-11 15:30:03 -08002035XMLDocument::~XMLDocument()
2036{
Lee Thomasonf07b9522014-10-30 13:25:12 -07002037 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08002038}
2039
2040
Lee Thomason816d3fa2017-06-05 14:35:55 -07002041void XMLDocument::MarkInUse(XMLNode* node)
2042{
Dmitry-Mec2f677b2017-06-15 12:44:27 +03002043 TIXMLASSERT(node);
Lee Thomason816d3fa2017-06-05 14:35:55 -07002044 TIXMLASSERT(node->_parent == 0);
2045
2046 for (int i = 0; i < _unlinked.Size(); ++i) {
2047 if (node == _unlinked[i]) {
2048 _unlinked.SwapRemove(i);
2049 break;
2050 }
2051 }
2052}
2053
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002054void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08002055{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002056 DeleteChildren();
Lee Thomason816d3fa2017-06-05 14:35:55 -07002057 while( _unlinked.Size()) {
2058 DeleteNode(_unlinked[0]); // Will remove from _unlinked as part of delete.
2059 }
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002060
Peter Matula50689912018-01-09 12:52:26 +01002061#ifdef TINYXML2_DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002062 const bool hadError = Error();
2063#endif
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002064 ClearError();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002065
Lee Thomason624d43f2012-10-12 10:58:48 -07002066 delete [] _charBuffer;
2067 _charBuffer = 0;
Lee Thomasond946dda2018-04-05 09:11:08 -07002068 _parsingDepth = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07002069
2070#if 0
2071 _textPool.Trace( "text" );
2072 _elementPool.Trace( "element" );
2073 _commentPool.Trace( "comment" );
2074 _attributePool.Trace( "attribute" );
2075#endif
Gumichan010f1fa6d2018-02-01 14:16:24 +01002076
Peter Matula50689912018-01-09 12:52:26 +01002077#ifdef TINYXML2_DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002078 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002079 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
2080 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
2081 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
2082 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
2083 }
2084#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08002085}
2086
Lee Thomason3f57d272012-01-11 15:30:03 -08002087
Shuichiro Suzuki87cd4e02017-08-24 11:20:26 +09002088void XMLDocument::DeepCopy(XMLDocument* target) const
Lee Thomason7085f002017-06-01 18:09:43 -07002089{
2090 TIXMLASSERT(target);
Lee Thomason1346a172017-06-14 15:14:19 -07002091 if (target == this) {
2092 return; // technically success - a no-op.
2093 }
Lee Thomason7085f002017-06-01 18:09:43 -07002094
2095 target->Clear();
2096 for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {
2097 target->InsertEndChild(node->DeepClone(target));
2098 }
2099}
2100
Lee Thomason2c85a712012-01-31 08:24:24 -08002101XMLElement* XMLDocument::NewElement( const char* name )
2102{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002103 XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002104 ele->SetName( name );
2105 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08002106}
2107
2108
Lee Thomason1ff38e02012-02-14 18:18:16 -08002109XMLComment* XMLDocument::NewComment( const char* str )
2110{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002111 XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002112 comment->SetValue( str );
2113 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002114}
2115
2116
2117XMLText* XMLDocument::NewText( const char* str )
2118{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002119 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002120 text->SetValue( str );
2121 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002122}
2123
2124
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002125XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2126{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002127 XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002128 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2129 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002130}
2131
2132
2133XMLUnknown* XMLDocument::NewUnknown( const char* str )
2134{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002135 XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002136 unk->SetValue( str );
2137 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002138}
2139
Dmitry-Me01578db2014-08-19 10:18:48 +04002140static FILE* callfopen( const char* filepath, const char* mode )
2141{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002142 TIXMLASSERT( filepath );
2143 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002144#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2145 FILE* fp = 0;
orbitcowboy0e7f2892019-01-15 11:28:49 +01002146 const errno_t err = fopen_s( &fp, filepath, mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002147 if ( err ) {
2148 return 0;
2149 }
2150#else
2151 FILE* fp = fopen( filepath, mode );
2152#endif
2153 return fp;
2154}
Gumichan010f1fa6d2018-02-01 14:16:24 +01002155
Lee Thomasoncd011bc2014-12-17 10:41:34 -08002156void XMLDocument::DeleteNode( XMLNode* node ) {
2157 TIXMLASSERT( node );
2158 TIXMLASSERT(node->_document == this );
2159 if (node->_parent) {
2160 node->_parent->DeleteChild( node );
2161 }
2162 else {
2163 // Isn't in the tree.
2164 // Use the parent delete.
2165 // Also, we need to mark it tracked: we 'know'
2166 // it was never used.
2167 node->_memPool->SetTracked();
2168 // Call the static XMLNode version:
2169 XMLNode::DeleteNode(node);
2170 }
2171}
2172
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002173
Lee Thomason2fa81722012-11-09 12:37:46 -08002174XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002175{
Gumichan010f1fa6d2018-02-01 14:16:24 +01002176 if ( !filename ) {
2177 TIXMLASSERT( false );
2178 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" );
2179 return _errorID;
2180 }
2181
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002182 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04002183 FILE* fp = callfopen( filename, "rb" );
2184 if ( !fp ) {
Gumichan010f1fa6d2018-02-01 14:16:24 +01002185 SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename );
Lee Thomason624d43f2012-10-12 10:58:48 -07002186 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002187 }
2188 LoadFile( fp );
2189 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002190 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002191}
2192
Dmitry-Me901fed52015-09-25 10:29:51 +03002193// This is likely overengineered template art to have a check that unsigned long value incremented
2194// by one still fits into size_t. If size_t type is larger than unsigned long type
2195// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
2196// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
2197// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
2198// types sizes relate to each other.
2199template
2200<bool = (sizeof(unsigned long) >= sizeof(size_t))>
2201struct LongFitsIntoSizeTMinusOne {
2202 static bool Fits( unsigned long value )
2203 {
2204 return value < (size_t)-1;
2205 }
2206};
2207
2208template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02002209struct LongFitsIntoSizeTMinusOne<false> {
2210 static bool Fits( unsigned long )
2211 {
2212 return true;
2213 }
2214};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002215
Lee Thomason2fa81722012-11-09 12:37:46 -08002216XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002217{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002218 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002219
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002220 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002221 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002222 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002223 return _errorID;
2224 }
2225
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002226 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002227 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002228 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002229 if ( filelength == -1L ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002230 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002231 return _errorID;
2232 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002233 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002234
Dmitry-Me901fed52015-09-25 10:29:51 +03002235 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002236 // Cannot handle files which won't fit in buffer together with null terminator
Lee Thomasonaa188392017-09-19 17:54:31 -07002237 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002238 return _errorID;
2239 }
2240
Dmitry-Me72801b82015-05-07 09:41:39 +03002241 if ( filelength == 0 ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002242 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002243 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002244 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002245
Dmitry-Me72801b82015-05-07 09:41:39 +03002246 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002247 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002248 _charBuffer = new char[size+1];
orbitcowboy0e7f2892019-01-15 11:28:49 +01002249 const size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002250 if ( read != size ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002251 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002252 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002253 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002254
Lee Thomason624d43f2012-10-12 10:58:48 -07002255 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002256
Dmitry-Me97476b72015-01-01 16:15:57 +03002257 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002258 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002259}
2260
2261
Lee Thomason2fa81722012-11-09 12:37:46 -08002262XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002263{
Gumichan010f1fa6d2018-02-01 14:16:24 +01002264 if ( !filename ) {
2265 TIXMLASSERT( false );
2266 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" );
2267 return _errorID;
2268 }
2269
Dmitry-Me01578db2014-08-19 10:18:48 +04002270 FILE* fp = callfopen( filename, "w" );
2271 if ( !fp ) {
Gumichan010f1fa6d2018-02-01 14:16:24 +01002272 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename );
Lee Thomason624d43f2012-10-12 10:58:48 -07002273 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002274 }
2275 SaveFile(fp, compact);
2276 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002277 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002278}
2279
2280
Lee Thomason2fa81722012-11-09 12:37:46 -08002281XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002282{
Ant Mitchell189198f2015-03-24 16:20:36 +00002283 // Clear any error from the last save, otherwise it will get reported
2284 // for *this* call.
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002285 ClearError();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002286 XMLPrinter stream( fp, compact );
2287 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002288 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002289}
2290
Lee Thomason1ff38e02012-02-14 18:18:16 -08002291
Lee Thomason2fa81722012-11-09 12:37:46 -08002292XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002293{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002294 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002295
Lee Thomason82d32002014-02-21 22:47:18 -08002296 if ( len == 0 || !p || !*p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002297 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002298 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002299 }
2300 if ( len == (size_t)(-1) ) {
2301 len = strlen( p );
2302 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002303 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002304 _charBuffer = new char[ len+1 ];
2305 memcpy( _charBuffer, p, len );
2306 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002307
Dmitry-Me97476b72015-01-01 16:15:57 +03002308 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002309 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002310 // clean up now essentially dangling memory.
2311 // and the parse fail can put objects in the
2312 // pools that are dead and inaccessible.
2313 DeleteChildren();
2314 _elementPool.Clear();
2315 _attributePool.Clear();
2316 _textPool.Clear();
2317 _commentPool.Clear();
2318 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002319 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002320}
2321
2322
PKEuS1c5f99e2013-07-06 11:28:39 +02002323void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002324{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002325 if ( streamer ) {
2326 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002327 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002328 else {
2329 XMLPrinter stdoutStreamer( stdout );
2330 Accept( &stdoutStreamer );
2331 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002332}
2333
2334
Lee Thomasonaa188392017-09-19 17:54:31 -07002335void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... )
Lee Thomason67d61312012-01-24 16:01:51 -08002336{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002337 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002338 _errorID = error;
Lee Thomason714ccfe2017-10-10 17:08:12 -07002339 _errorLineNum = lineNum;
Lee Thomasonaa188392017-09-19 17:54:31 -07002340 _errorStr.Reset();
Lee Thomason584af572016-09-05 14:14:16 -07002341
orbitcowboy0e7f2892019-01-15 11:28:49 +01002342 const size_t BUFFER_SIZE = 1000;
Lee Thomasona36f7ac2017-12-28 13:48:54 -08002343 char* buffer = new char[BUFFER_SIZE];
Lee Thomasonaa188392017-09-19 17:54:31 -07002344
Lee Thomason30d0c3d2018-06-29 15:47:37 -07002345 TIXMLASSERT(sizeof(error) <= sizeof(int));
Lee Thomasona36f7ac2017-12-28 13:48:54 -08002346 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 -07002347
Lee Thomasona36f7ac2017-12-28 13:48:54 -08002348 if (format) {
2349 size_t len = strlen(buffer);
2350 TIXML_SNPRINTF(buffer + len, BUFFER_SIZE - len, ": ");
2351 len = strlen(buffer);
2352
2353 va_list va;
2354 va_start(va, format);
2355 TIXML_VSNPRINTF(buffer + len, BUFFER_SIZE - len, format, va);
2356 va_end(va);
2357 }
2358 _errorStr.SetStr(buffer);
2359 delete[] buffer;
Lee Thomason67d61312012-01-24 16:01:51 -08002360}
2361
Lee Thomasonaa188392017-09-19 17:54:31 -07002362
Lee Thomasone90e9012016-12-24 07:34:39 -08002363/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
Lee Thomason331596e2014-09-11 14:56:43 -07002364{
kezenator5a700712016-11-26 13:54:42 +10002365 TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2366 const char* errorName = _errorNames[errorID];
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002367 TIXMLASSERT( errorName && errorName[0] );
2368 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002369}
Lee Thomason5cae8972012-01-24 18:03:07 -08002370
Gumichan010f1fa6d2018-02-01 14:16:24 +01002371const char* XMLDocument::ErrorStr() const
Lee Thomason8c9e3132017-06-26 16:55:01 -07002372{
Lee Thomasonaa188392017-09-19 17:54:31 -07002373 return _errorStr.Empty() ? "" : _errorStr.GetStr();
Lee Thomason8c9e3132017-06-26 16:55:01 -07002374}
2375
Lee Thomasonf49b9652017-10-11 10:57:49 -07002376
2377void XMLDocument::PrintError() const
2378{
2379 printf("%s\n", ErrorStr());
2380}
2381
kezenator5a700712016-11-26 13:54:42 +10002382const char* XMLDocument::ErrorName() const
2383{
Lee Thomasone90e9012016-12-24 07:34:39 -08002384 return ErrorIDToName(_errorID);
kezenator5a700712016-11-26 13:54:42 +10002385}
2386
Dmitry-Me97476b72015-01-01 16:15:57 +03002387void XMLDocument::Parse()
2388{
2389 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2390 TIXMLASSERT( _charBuffer );
kezenatorec694152016-11-26 17:21:43 +10002391 _parseCurLineNum = 1;
2392 _parseLineNum = 1;
Lee Thomason3cebdc42015-01-05 17:16:28 -08002393 char* p = _charBuffer;
kezenator4f756162016-11-29 19:46:27 +10002394 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mee28be752015-01-09 14:59:30 +03002395 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002396 if ( !*p ) {
Lee Thomasonaa188392017-09-19 17:54:31 -07002397 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002398 return;
2399 }
kezenator4f756162016-11-29 19:46:27 +10002400 ParseDeep(p, 0, &_parseCurLineNum );
Dmitry-Me97476b72015-01-01 16:15:57 +03002401}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002402
Lee Thomasonf928c352018-04-05 09:24:20 -07002403void XMLDocument::PushDepth()
Lee Thomasond946dda2018-04-05 09:11:08 -07002404{
2405 _parsingDepth++;
2406 if (_parsingDepth == TINYXML2_MAX_ELEMENT_DEPTH) {
Lee Thomasonbefc3c32018-04-05 15:53:14 -07002407 SetError(XML_ELEMENT_DEPTH_EXCEEDED, _parseCurLineNum, "Element nesting is too deep." );
Lee Thomasond946dda2018-04-05 09:11:08 -07002408 }
Lee Thomasond946dda2018-04-05 09:11:08 -07002409}
2410
Lee Thomasonf928c352018-04-05 09:24:20 -07002411void XMLDocument::PopDepth()
Lee Thomasond946dda2018-04-05 09:11:08 -07002412{
2413 TIXMLASSERT(_parsingDepth > 0);
2414 --_parsingDepth;
Lee Thomasond946dda2018-04-05 09:11:08 -07002415}
2416
PKEuS1bfb9542013-08-04 13:51:17 +02002417XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002418 _elementJustOpened( false ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002419 _stack(),
Lee Thomason624d43f2012-10-12 10:58:48 -07002420 _firstElement( true ),
2421 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002422 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002423 _textDepth( -1 ),
2424 _processEntities( true ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002425 _compactMode( compact ),
2426 _buffer()
Lee Thomason5cae8972012-01-24 18:03:07 -08002427{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002428 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002429 _entityFlag[i] = false;
2430 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002431 }
2432 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002433 const char entityValue = entities[i].value;
Dmitry-Mea28eb072017-08-25 18:34:18 +03002434 const unsigned char flagIndex = (unsigned char)entityValue;
2435 TIXMLASSERT( flagIndex < ENTITY_RANGE );
2436 _entityFlag[flagIndex] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002437 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002438 _restrictedEntityFlag[(unsigned char)'&'] = true;
2439 _restrictedEntityFlag[(unsigned char)'<'] = true;
2440 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002441 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002442}
2443
2444
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002445void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002446{
2447 va_list va;
2448 va_start( va, format );
2449
Lee Thomason624d43f2012-10-12 10:58:48 -07002450 if ( _fp ) {
2451 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002452 }
2453 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002454 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002455 // Close out and re-start the va-args
2456 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002457 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002458 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002459 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002460 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002461 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002462 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002463 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002464}
2465
2466
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002467void XMLPrinter::Write( const char* data, size_t size )
2468{
2469 if ( _fp ) {
2470 fwrite ( data , sizeof(char), size, _fp);
2471 }
2472 else {
Alex Alabuzhev90e69c92017-11-09 00:32:19 +00002473 char* p = _buffer.PushArr( static_cast<int>(size) ) - 1; // back up over the null terminator.
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002474 memcpy( p, data, size );
2475 p[size] = 0;
2476 }
2477}
2478
2479
2480void XMLPrinter::Putc( char ch )
2481{
2482 if ( _fp ) {
2483 fputc ( ch, _fp);
2484 }
2485 else {
2486 char* p = _buffer.PushArr( sizeof(char) ) - 1; // back up over the null terminator.
2487 p[0] = ch;
2488 p[1] = 0;
2489 }
2490}
2491
2492
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002493void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002494{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002495 for( int i=0; i<depth; ++i ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002496 Write( " " );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002497 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002498}
2499
2500
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002501void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002502{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002503 // Look for runs of bytes between entities to print.
2504 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002505
Lee Thomason624d43f2012-10-12 10:58:48 -07002506 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002507 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002508 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002509 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002510 // Remember, char is sometimes signed. (How many times has that bitten me?)
2511 if ( *q > 0 && *q < ENTITY_RANGE ) {
2512 // Check for entities. If one is found, flush
2513 // the stream up until the entity, write the
2514 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002515 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002516 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002517 const size_t delta = q - p;
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002518 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002519 Write( p, toPrint );
Dmitry-Med95172b2015-03-30 08:11:18 +03002520 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002521 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002522 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002523 for( int i=0; i<NUM_ENTITIES; ++i ) {
2524 if ( entities[i].value == *q ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002525 Putc( '&' );
Brad Anderson85aac022017-10-24 21:48:28 -06002526 Write( entities[i].pattern, entities[i].length );
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002527 Putc( ';' );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002528 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002529 break;
2530 }
2531 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002532 if ( !entityPatternPrinted ) {
2533 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2534 TIXMLASSERT( false );
2535 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002536 ++p;
2537 }
2538 }
2539 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002540 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002541 }
Derek Quambe69ae62018-04-18 13:40:46 -05002542 // Flush the remaining string. This will be the entire
2543 // string if an entity wasn't found.
2544 if ( p < q ) {
2545 const size_t delta = q - p;
2546 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
2547 Write( p, toPrint );
2548 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002549 }
Derek Quambe69ae62018-04-18 13:40:46 -05002550 else {
2551 Write( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002552 }
Lee Thomason857b8682012-01-25 17:50:25 -08002553}
2554
U-Stream\Leeae25a442012-02-17 17:48:16 -08002555
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002556void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002557{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002558 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002559 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 +03002560 Write( reinterpret_cast< const char* >( bom ) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002561 }
2562 if ( writeDec ) {
2563 PushDeclaration( "xml version=\"1.0\"" );
2564 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002565}
2566
2567
Uli Kusterer593a33d2014-02-01 12:48:51 +01002568void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002569{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002570 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002571 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002572
Uli Kusterer593a33d2014-02-01 12:48:51 +01002573 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002574 Putc( '\n' );
PKEuS1bfb9542013-08-04 13:51:17 +02002575 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002576 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002577 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002578 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002579
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002580 Write ( "<" );
2581 Write ( name );
2582
Lee Thomason624d43f2012-10-12 10:58:48 -07002583 _elementJustOpened = true;
2584 _firstElement = false;
2585 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002586}
2587
2588
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002589void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002590{
Lee Thomason624d43f2012-10-12 10:58:48 -07002591 TIXMLASSERT( _elementJustOpened );
Brad Anderson85aac022017-10-24 21:48:28 -06002592 Putc ( ' ' );
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002593 Write( name );
2594 Write( "=\"" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002595 PrintString( value, false );
Brad Anderson85aac022017-10-24 21:48:28 -06002596 Putc ( '\"' );
Lee Thomason5cae8972012-01-24 18:03:07 -08002597}
2598
2599
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002600void XMLPrinter::PushAttribute( const char* name, int v )
2601{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002602 char buf[BUF_SIZE];
2603 XMLUtil::ToStr( v, buf, BUF_SIZE );
2604 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002605}
2606
2607
2608void XMLPrinter::PushAttribute( const char* name, unsigned v )
2609{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002610 char buf[BUF_SIZE];
2611 XMLUtil::ToStr( v, buf, BUF_SIZE );
2612 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002613}
2614
2615
Lee Thomason51c12712016-06-04 20:18:49 -07002616void XMLPrinter::PushAttribute(const char* name, int64_t v)
2617{
2618 char buf[BUF_SIZE];
2619 XMLUtil::ToStr(v, buf, BUF_SIZE);
2620 PushAttribute(name, buf);
2621}
2622
2623
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002624void XMLPrinter::PushAttribute( const char* name, bool v )
2625{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002626 char buf[BUF_SIZE];
2627 XMLUtil::ToStr( v, buf, BUF_SIZE );
2628 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002629}
2630
2631
2632void XMLPrinter::PushAttribute( const char* name, double v )
2633{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002634 char buf[BUF_SIZE];
2635 XMLUtil::ToStr( v, buf, BUF_SIZE );
2636 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002637}
2638
2639
Uli Kustererca412e82014-02-01 13:35:05 +01002640void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002641{
Lee Thomason624d43f2012-10-12 10:58:48 -07002642 --_depth;
2643 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002644
Lee Thomason624d43f2012-10-12 10:58:48 -07002645 if ( _elementJustOpened ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002646 Write( "/>" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002647 }
2648 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002649 if ( _textDepth < 0 && !compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002650 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002651 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002652 }
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002653 Write ( "</" );
2654 Write ( name );
2655 Write ( ">" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002656 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002657
Lee Thomason624d43f2012-10-12 10:58:48 -07002658 if ( _textDepth == _depth ) {
2659 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002660 }
Uli Kustererca412e82014-02-01 13:35:05 +01002661 if ( _depth == 0 && !compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002662 Putc( '\n' );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002663 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002664 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002665}
2666
2667
Dmitry-Mea092bc12014-12-23 17:57:05 +03002668void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002669{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002670 if ( !_elementJustOpened ) {
2671 return;
2672 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002673 _elementJustOpened = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002674 Putc( '>' );
Lee Thomason5cae8972012-01-24 18:03:07 -08002675}
2676
2677
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002678void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002679{
Lee Thomason624d43f2012-10-12 10:58:48 -07002680 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002681
Dmitry-Mea092bc12014-12-23 17:57:05 +03002682 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002683 if ( cdata ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002684 Write( "<![CDATA[" );
2685 Write( text );
2686 Write( "]]>" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002687 }
2688 else {
2689 PrintString( text, true );
2690 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002691}
2692
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002693void XMLPrinter::PushText( int64_t value )
2694{
2695 char buf[BUF_SIZE];
2696 XMLUtil::ToStr( value, buf, BUF_SIZE );
2697 PushText( buf, false );
2698}
2699
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002700void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002701{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002702 char buf[BUF_SIZE];
2703 XMLUtil::ToStr( value, buf, BUF_SIZE );
2704 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002705}
2706
2707
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002708void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002709{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002710 char buf[BUF_SIZE];
2711 XMLUtil::ToStr( value, buf, BUF_SIZE );
2712 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002713}
2714
2715
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002716void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002717{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002718 char buf[BUF_SIZE];
2719 XMLUtil::ToStr( value, buf, BUF_SIZE );
2720 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002721}
2722
2723
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002724void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002725{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002726 char buf[BUF_SIZE];
2727 XMLUtil::ToStr( value, buf, BUF_SIZE );
2728 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002729}
2730
2731
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002732void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002733{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002734 char buf[BUF_SIZE];
2735 XMLUtil::ToStr( value, buf, BUF_SIZE );
2736 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002737}
2738
Lee Thomason5cae8972012-01-24 18:03:07 -08002739
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002740void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002741{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002742 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002743 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002744 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002745 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002746 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002747 _firstElement = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002748
2749 Write( "<!--" );
2750 Write( comment );
2751 Write( "-->" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002752}
Lee Thomason751da522012-02-10 08:50:51 -08002753
2754
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002755void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002756{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002757 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002758 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002759 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002760 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002761 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002762 _firstElement = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002763
2764 Write( "<?" );
2765 Write( value );
2766 Write( "?>" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002767}
2768
2769
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002770void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002771{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002772 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002773 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002774 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002775 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002776 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002777 _firstElement = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002778
2779 Write( "<!" );
2780 Write( value );
Brad Anderson85aac022017-10-24 21:48:28 -06002781 Putc( '>' );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002782}
2783
2784
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002785bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002786{
Lee Thomason624d43f2012-10-12 10:58:48 -07002787 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002788 if ( doc.HasBOM() ) {
2789 PushHeader( true, false );
2790 }
2791 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002792}
2793
2794
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002795bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002796{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002797 const XMLElement* parentElem = 0;
2798 if ( element.Parent() ) {
2799 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002800 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002801 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002802 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002803 while ( attribute ) {
2804 PushAttribute( attribute->Name(), attribute->Value() );
2805 attribute = attribute->Next();
2806 }
2807 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002808}
2809
2810
Uli Kustererca412e82014-02-01 13:35:05 +01002811bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002812{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002813 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002814 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002815}
2816
2817
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002818bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002819{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002820 PushText( text.Value(), text.CData() );
2821 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002822}
2823
2824
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002825bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002826{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002827 PushComment( comment.Value() );
2828 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002829}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002830
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002831bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002832{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002833 PushDeclaration( declaration.Value() );
2834 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002835}
2836
2837
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002838bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002839{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002840 PushUnknown( unknown.Value() );
2841 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002842}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002843
Lee Thomason685b8952012-11-12 13:00:06 -08002844} // namespace tinyxml2