blob: 5c459a633c2f9bb94924180845054c634ed0eb35 [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
U-Lama\Lee560bd472011-12-28 19:42:49 -080024#include "tinyxml2.h"
25
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070026#include <new> // yes, this one new style header, is in the Android SDK.
Wilfred van Velzen67abee52016-03-25 14:01:15 +010027#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)
Lee Thomasona9cf3f92012-10-11 16:56:51 -070028# include <stddef.h>
Philipp Kloke358202c2015-07-30 16:02:26 +020029# include <stdarg.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070030#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070031# include <cstddef>
Philipp Kloke358202c2015-07-30 16:02:26 +020032# include <cstdarg>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070033#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080034
Lee Thomason53db4a62015-06-11 22:52:08 -070035#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
Dmitry-Me1ca593c2015-06-22 12:49:32 +030036 // Microsoft Visual Studio, version 2005 and higher. Not WinCE.
Lee Thomason53db4a62015-06-11 22:52:08 -070037 /*int _snprintf_s(
38 char *buffer,
39 size_t sizeOfBuffer,
40 size_t count,
41 const char *format [,
42 argument] ...
43 );*/
PKEuScac75782015-08-15 18:17:27 +020044 static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
Lee Thomason53db4a62015-06-11 22:52:08 -070045 {
46 va_list va;
47 va_start( va, format );
48 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
49 va_end( va );
50 return result;
51 }
52
PKEuScac75782015-08-15 18:17:27 +020053 static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070054 {
55 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
56 return result;
57 }
58
59 #define TIXML_VSCPRINTF _vscprintf
60 #define TIXML_SSCANF sscanf_s
61#elif defined _MSC_VER
62 // Microsoft Visual Studio 2003 and earlier or WinCE
63 #define TIXML_SNPRINTF _snprintf
64 #define TIXML_VSNPRINTF _vsnprintf
65 #define TIXML_SSCANF sscanf
Lee Thomasonaa8566b2015-06-19 16:52:40 -070066 #if (_MSC_VER < 1400 ) && (!defined WINCE)
Lee Thomason53db4a62015-06-11 22:52:08 -070067 // Microsoft Visual Studio 2003 and not WinCE.
68 #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have.
69 #else
70 // Microsoft Visual Studio 2003 and earlier or WinCE.
PKEuScac75782015-08-15 18:17:27 +020071 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070072 {
73 int len = 512;
74 for (;;) {
75 len = len*2;
76 char* str = new char[len]();
77 const int required = _vsnprintf(str, len, format, va);
78 delete[] str;
79 if ( required != -1 ) {
Dmitry-Me1d32e582015-07-27 17:11:51 +030080 TIXMLASSERT( required >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070081 len = required;
82 break;
83 }
84 }
Dmitry-Me1d32e582015-07-27 17:11:51 +030085 TIXMLASSERT( len >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070086 return len;
87 }
88 #endif
89#else
90 // GCC version 3 and higher
91 //#warning( "Using sn* functions." )
92 #define TIXML_SNPRINTF snprintf
93 #define TIXML_VSNPRINTF vsnprintf
PKEuScac75782015-08-15 18:17:27 +020094 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070095 {
96 int len = vsnprintf( 0, 0, format, va );
Dmitry-Me1d32e582015-07-27 17:11:51 +030097 TIXMLASSERT( len >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070098 return len;
99 }
100 #define TIXML_SSCANF sscanf
101#endif
102
103
Lee Thomasone4422302012-01-20 17:59:50 -0800104static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -0800105static const char LF = LINE_FEED;
106static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
107static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -0800108static const char SINGLE_QUOTE = '\'';
109static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -0800110
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800111// Bunch of unicode info at:
112// http://www.unicode.org/faq/utf_bom.html
113// ef bb bf (Microsoft "lead bytes") - designates UTF-8
114
115static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
116static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
117static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800118
Kevin Wojniak04c22d22012-11-08 11:02:22 -0800119namespace tinyxml2
120{
121
Lee Thomason8ee79892012-01-25 17:44:30 -0800122struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700123 const char* pattern;
124 int length;
125 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -0800126};
127
128static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700129static const Entity entities[NUM_ENTITIES] = {
130 { "quot", 4, DOUBLE_QUOTE },
131 { "amp", 3, '&' },
132 { "apos", 4, SINGLE_QUOTE },
133 { "lt", 2, '<' },
134 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -0800135};
136
Lee Thomasonfde6a752012-01-14 18:08:12 -0800137
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800138StrPair::~StrPair()
139{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700140 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800141}
142
143
Lee Thomason29658802014-11-27 22:31:11 -0800144void StrPair::TransferTo( StrPair* other )
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300145{
Lee Thomason29658802014-11-27 22:31:11 -0800146 if ( this == other ) {
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300147 return;
148 }
149 // This in effect implements the assignment operator by "moving"
150 // ownership (as in auto_ptr).
151
Dmitry-Medb02b212016-08-04 17:16:05 +0300152 TIXMLASSERT( other != 0 );
Lee Thomason29658802014-11-27 22:31:11 -0800153 TIXMLASSERT( other->_flags == 0 );
154 TIXMLASSERT( other->_start == 0 );
155 TIXMLASSERT( other->_end == 0 );
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300156
Lee Thomason29658802014-11-27 22:31:11 -0800157 other->Reset();
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300158
Lee Thomason29658802014-11-27 22:31:11 -0800159 other->_flags = _flags;
160 other->_start = _start;
161 other->_end = _end;
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300162
163 _flags = 0;
164 _start = 0;
165 _end = 0;
166}
167
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800168void StrPair::Reset()
169{
Lee Thomason120b3a62012-10-12 10:06:59 -0700170 if ( _flags & NEEDS_DELETE ) {
171 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700172 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700173 _flags = 0;
174 _start = 0;
175 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800176}
177
178
179void StrPair::SetStr( const char* str, int flags )
180{
Dmitry-Me0515fa92015-12-09 11:54:06 +0300181 TIXMLASSERT( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700182 Reset();
183 size_t len = strlen( str );
Dmitry-Me96f38cc2015-08-10 16:45:12 +0300184 TIXMLASSERT( _start == 0 );
Lee Thomason120b3a62012-10-12 10:06:59 -0700185 _start = new char[ len+1 ];
186 memcpy( _start, str, len+1 );
187 _end = _start + len;
188 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800189}
190
191
kezenator4f756162016-11-29 19:46:27 +1000192char* StrPair::ParseText( char* p, const char* endTag, int strFlags, int* curLineNumPtr )
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800193{
Dmitry-Mef9f3c3e2016-08-30 15:51:55 +0300194 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700195 TIXMLASSERT( endTag && *endTag );
Lee Thomasone90e9012016-12-24 07:34:39 -0800196 TIXMLASSERT(curLineNumPtr);
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800197
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400198 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700199 char endChar = *endTag;
200 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800201
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700202 // Inner loop of text parsing.
203 while ( *p ) {
204 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
205 Set( start, p, strFlags );
206 return p + length;
kezenatorec694152016-11-26 17:21:43 +1000207 } else if (*p == '\n') {
kezenator4f756162016-11-29 19:46:27 +1000208 ++(*curLineNumPtr);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700209 }
210 ++p;
Dmitry-Mef9f3c3e2016-08-30 15:51:55 +0300211 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700212 }
213 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800214}
215
216
217char* StrPair::ParseName( char* p )
218{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400219 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700220 return 0;
221 }
JayXonee525db2014-12-24 04:01:42 -0500222 if ( !XMLUtil::IsNameStartChar( *p ) ) {
223 return 0;
224 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800225
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400226 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500227 ++p;
228 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700229 ++p;
230 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800231
JayXonee525db2014-12-24 04:01:42 -0500232 Set( start, p, 0 );
233 return p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800234}
235
236
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700237void StrPair::CollapseWhitespace()
238{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400239 // Adjusting _start would cause undefined behavior on delete[]
240 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700241 // Trim leading space.
Lee Thomasone90e9012016-12-24 07:34:39 -0800242 _start = XMLUtil::SkipWhiteSpace( _start, 0 );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700243
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300244 if ( *_start ) {
Dmitry-Me24495822016-09-02 16:53:32 +0300245 const char* p = _start; // the read pointer
Lee Thomason120b3a62012-10-12 10:06:59 -0700246 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700247
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700248 while( *p ) {
249 if ( XMLUtil::IsWhiteSpace( *p )) {
Lee Thomasone90e9012016-12-24 07:34:39 -0800250 p = XMLUtil::SkipWhiteSpace( p, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700251 if ( *p == 0 ) {
252 break; // don't write to q; this trims the trailing space.
253 }
254 *q = ' ';
255 ++q;
256 }
257 *q = *p;
258 ++q;
259 ++p;
260 }
261 *q = 0;
262 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700263}
264
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800265
Lee Thomasone4422302012-01-20 17:59:50 -0800266const char* StrPair::GetStr()
267{
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300268 TIXMLASSERT( _start );
269 TIXMLASSERT( _end );
Lee Thomason120b3a62012-10-12 10:06:59 -0700270 if ( _flags & NEEDS_FLUSH ) {
271 *_end = 0;
272 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800273
Lee Thomason120b3a62012-10-12 10:06:59 -0700274 if ( _flags ) {
Dmitry-Me24495822016-09-02 16:53:32 +0300275 const char* p = _start; // the read pointer
Lee Thomason120b3a62012-10-12 10:06:59 -0700276 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800277
Lee Thomason120b3a62012-10-12 10:06:59 -0700278 while( p < _end ) {
279 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700280 // CR-LF pair becomes LF
281 // CR alone becomes LF
282 // LF-CR becomes LF
283 if ( *(p+1) == LF ) {
284 p += 2;
285 }
286 else {
287 ++p;
288 }
Dmitry-Mefed51122016-09-06 18:08:55 +0300289 *q = LF;
290 ++q;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700291 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700292 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700293 if ( *(p+1) == CR ) {
294 p += 2;
295 }
296 else {
297 ++p;
298 }
Dmitry-Mefed51122016-09-06 18:08:55 +0300299 *q = LF;
300 ++q;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700301 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700302 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700303 // Entities handled by tinyXML2:
304 // - special entities in the entity table [in/out]
305 // - numeric character reference [in]
306 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800307
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700308 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400309 const int buflen = 10;
310 char buf[buflen] = { 0 };
311 int len = 0;
Dmitry-Me6f51c802015-03-14 13:25:03 +0300312 char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
313 if ( adjusted == 0 ) {
314 *q = *p;
315 ++p;
316 ++q;
317 }
318 else {
319 TIXMLASSERT( 0 <= len && len <= buflen );
320 TIXMLASSERT( q + len <= adjusted );
321 p = adjusted;
322 memcpy( q, buf, len );
323 q += len;
324 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700325 }
326 else {
Dmitry-Me764545e2015-05-20 10:29:24 +0300327 bool entityFound = false;
328 for( int i = 0; i < NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400329 const Entity& entity = entities[i];
330 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
331 && *( p + entity.length + 1 ) == ';' ) {
332 // Found an entity - convert.
333 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700334 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400335 p += entity.length + 2;
Dmitry-Me764545e2015-05-20 10:29:24 +0300336 entityFound = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700337 break;
338 }
339 }
Dmitry-Me764545e2015-05-20 10:29:24 +0300340 if ( !entityFound ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700341 // fixme: treat as error?
342 ++p;
343 ++q;
344 }
345 }
346 }
347 else {
348 *q = *p;
349 ++p;
350 ++q;
351 }
352 }
353 *q = 0;
354 }
355 // The loop below has plenty going on, and this
356 // is a less useful mode. Break it out.
Dmitry-Me5420e542015-05-20 10:51:26 +0300357 if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700358 CollapseWhitespace();
359 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700360 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700361 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300362 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700363 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800364}
365
Lee Thomason2c85a712012-01-31 08:24:24 -0800366
Lee Thomasone4422302012-01-20 17:59:50 -0800367
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800368
Lee Thomason56bdd022012-02-09 18:16:58 -0800369// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800370
Lee Thomasonf458d262016-12-26 22:47:25 -0800371const char* XMLUtil::writeBoolTrue = "true";
372const char* XMLUtil::writeBoolFalse = "false";
Lee Thomasonce667c92016-12-26 16:45:30 -0800373
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800374void XMLUtil::SetBoolSerialization(const char* writeTrue, const char* writeFalse)
Lee Thomasonce667c92016-12-26 16:45:30 -0800375{
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800376 static const char* defTrue = "true";
Lee Thomasonce667c92016-12-26 16:45:30 -0800377 static const char* defFalse = "false";
Lee Thomasonce667c92016-12-26 16:45:30 -0800378
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800379 writeBoolTrue = (writeTrue) ? writeTrue : defTrue;
380 writeBoolFalse = (writeFalse) ? writeFalse : defFalse;
Lee Thomasonce667c92016-12-26 16:45:30 -0800381}
382
383
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800384const char* XMLUtil::ReadBOM( const char* p, bool* bom )
385{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300386 TIXMLASSERT( p );
387 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700388 *bom = false;
389 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
390 // Check for BOM:
391 if ( *(pu+0) == TIXML_UTF_LEAD_0
392 && *(pu+1) == TIXML_UTF_LEAD_1
393 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
394 *bom = true;
395 p += 3;
396 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300397 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700398 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800399}
400
401
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800402void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
403{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700404 const unsigned long BYTE_MASK = 0xBF;
405 const unsigned long BYTE_MARK = 0x80;
406 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800407
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700408 if (input < 0x80) {
409 *length = 1;
410 }
411 else if ( input < 0x800 ) {
412 *length = 2;
413 }
414 else if ( input < 0x10000 ) {
415 *length = 3;
416 }
417 else if ( input < 0x200000 ) {
418 *length = 4;
419 }
420 else {
Dmitry-Me2f465c42015-03-16 11:08:23 +0300421 *length = 0; // This code won't convert this correctly anyway.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700422 return;
423 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800424
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700425 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800426
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700427 // Scary scary fall throughs.
428 switch (*length) {
429 case 4:
430 --output;
431 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
432 input >>= 6;
433 case 3:
434 --output;
435 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
436 input >>= 6;
437 case 2:
438 --output;
439 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
440 input >>= 6;
441 case 1:
442 --output;
443 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100444 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300445 default:
446 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700447 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800448}
449
450
451const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
452{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700453 // Presume an entity, and pull it out.
454 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800455
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700456 if ( *(p+1) == '#' && *(p+2) ) {
457 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300458 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700459 ptrdiff_t delta = 0;
460 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800461 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800462
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700463 if ( *(p+2) == 'x' ) {
464 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300465 const char* q = p+3;
466 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700467 return 0;
468 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800469
Lee Thomason7e67bc82015-01-12 14:05:12 -0800470 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800471
Dmitry-Me9f56e122015-01-12 10:07:54 +0300472 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700473 return 0;
474 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800475 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800476
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700477 delta = q-p;
478 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800479
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700480 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700481 unsigned int digit = 0;
482
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700483 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300484 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700485 }
486 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300487 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700488 }
489 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300490 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700491 }
492 else {
493 return 0;
494 }
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100495 TIXMLASSERT( digit < 16 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300496 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
497 const unsigned int digitScaled = mult * digit;
498 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
499 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300500 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700501 mult *= 16;
502 --q;
503 }
504 }
505 else {
506 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300507 const char* q = p+2;
508 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700509 return 0;
510 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800511
Lee Thomason7e67bc82015-01-12 14:05:12 -0800512 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800513
Dmitry-Me9f56e122015-01-12 10:07:54 +0300514 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700515 return 0;
516 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800517 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800518
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700519 delta = q-p;
520 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800521
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700522 while ( *q != '#' ) {
523 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300524 const unsigned int digit = *q - '0';
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100525 TIXMLASSERT( digit < 10 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300526 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
527 const unsigned int digitScaled = mult * digit;
528 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
529 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700530 }
531 else {
532 return 0;
533 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300534 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700535 mult *= 10;
536 --q;
537 }
538 }
539 // convert the UCS to UTF-8
540 ConvertUTF32ToUTF8( ucs, value, length );
541 return p + delta + 1;
542 }
543 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800544}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800545
546
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700547void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700548{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700549 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700550}
551
552
553void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
554{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700555 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700556}
557
558
559void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
560{
Lee Thomasonce667c92016-12-26 16:45:30 -0800561 TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? writeBoolTrue : writeBoolFalse);
Lee Thomason21be8822012-07-15 17:27:22 -0700562}
563
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800564/*
565 ToStr() of a number is a very tricky topic.
566 https://github.com/leethomason/tinyxml2/issues/106
567*/
Lee Thomason21be8822012-07-15 17:27:22 -0700568void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
569{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800570 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700571}
572
573
574void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
575{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800576 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700577}
578
579
Lee Thomason51c12712016-06-04 20:18:49 -0700580void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize)
581{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700582 // horrible syntax trick to make the compiler happy about %lld
583 TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v);
Lee Thomason51c12712016-06-04 20:18:49 -0700584}
585
586
Lee Thomason21be8822012-07-15 17:27:22 -0700587bool XMLUtil::ToInt( const char* str, int* value )
588{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700589 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
590 return true;
591 }
592 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700593}
594
595bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
596{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700597 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
598 return true;
599 }
600 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700601}
602
603bool XMLUtil::ToBool( const char* str, bool* value )
604{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700605 int ival = 0;
606 if ( ToInt( str, &ival )) {
607 *value = (ival==0) ? false : true;
608 return true;
609 }
610 if ( StringEqual( str, "true" ) ) {
611 *value = true;
612 return true;
613 }
614 else if ( StringEqual( str, "false" ) ) {
615 *value = false;
616 return true;
617 }
618 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700619}
620
621
622bool XMLUtil::ToFloat( const char* str, float* value )
623{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700624 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
625 return true;
626 }
627 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700628}
629
Lee Thomason51c12712016-06-04 20:18:49 -0700630
Lee Thomason21be8822012-07-15 17:27:22 -0700631bool XMLUtil::ToDouble( const char* str, double* value )
632{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700633 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
634 return true;
635 }
636 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700637}
638
639
Lee Thomason51c12712016-06-04 20:18:49 -0700640bool XMLUtil::ToInt64(const char* str, int64_t* value)
641{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700642 long long v = 0; // horrible syntax trick to make the compiler happy about %lld
643 if (TIXML_SSCANF(str, "%lld", &v) == 1) {
644 *value = (int64_t)v;
Lee Thomason51c12712016-06-04 20:18:49 -0700645 return true;
646 }
647 return false;
648}
649
650
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700651char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800652{
Dmitry-Me02384662015-03-03 16:02:13 +0300653 TIXMLASSERT( node );
654 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400655 char* const start = p;
kezenatorec694152016-11-26 17:21:43 +1000656 int const startLine = _parseCurLineNum;
kezenator4f756162016-11-29 19:46:27 +1000657 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300658 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300659 *node = 0;
660 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700661 return p;
662 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800663
Dmitry-Me962083b2015-05-26 11:38:30 +0300664 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700665 static const char* xmlHeader = { "<?" };
666 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700667 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300668 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700669 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800670
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700671 static const int xmlHeaderLen = 2;
672 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700673 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300674 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700675 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800676
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700677 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
678 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400679 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700680 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300681 returnNode = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000682 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700683 p += xmlHeaderLen;
684 }
685 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300686 returnNode = CreateUnlinkedNode<XMLComment>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000687 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700688 p += commentHeaderLen;
689 }
690 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300691 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700692 returnNode = text;
kezenatorec694152016-11-26 17:21:43 +1000693 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700694 p += cdataHeaderLen;
695 text->SetCData( true );
696 }
697 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300698 returnNode = CreateUnlinkedNode<XMLUnknown>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000699 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700700 p += dtdHeaderLen;
701 }
702 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300703 returnNode = CreateUnlinkedNode<XMLElement>( _elementPool );
kezenatorec694152016-11-26 17:21:43 +1000704 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700705 p += elementHeaderLen;
706 }
707 else {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300708 returnNode = CreateUnlinkedNode<XMLText>( _textPool );
kezenatorec694152016-11-26 17:21:43 +1000709 returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700710 p = start; // Back it up, all the text counts.
kezenatorec694152016-11-26 17:21:43 +1000711 _parseCurLineNum = startLine;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700712 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800713
Dmitry-Me02384662015-03-03 16:02:13 +0300714 TIXMLASSERT( returnNode );
715 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700716 *node = returnNode;
717 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800718}
719
720
Lee Thomason751da522012-02-10 08:50:51 -0800721bool XMLDocument::Accept( XMLVisitor* visitor ) const
722{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300723 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700724 if ( visitor->VisitEnter( *this ) ) {
725 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
726 if ( !node->Accept( visitor ) ) {
727 break;
728 }
729 }
730 }
731 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800732}
Lee Thomason56bdd022012-02-09 18:16:58 -0800733
734
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800735// --------- XMLNode ----------- //
736
737XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700738 _document( doc ),
739 _parent( 0 ),
kezenatorec694152016-11-26 17:21:43 +1000740 _parseLineNum( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -0700741 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200742 _prev( 0 ), _next( 0 ),
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700743 _userData( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200744 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800745{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800746}
747
748
749XMLNode::~XMLNode()
750{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700751 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700752 if ( _parent ) {
753 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700754 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800755}
756
Michael Daumling21626882013-10-22 17:03:37 +0200757const char* XMLNode::Value() const
758{
Dmitry-Mecaa72a62016-08-10 17:34:34 +0300759 // Edge case: XMLDocuments don't have a Value. Return null.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530760 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530761 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200762 return _value.GetStr();
763}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800764
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800765void XMLNode::SetValue( const char* str, bool staticMem )
766{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700767 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700768 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700769 }
770 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700771 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700772 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800773}
774
Lee Thomason7085f002017-06-01 18:09:43 -0700775XMLNode* XMLNode::DeepClone(XMLDocument* document) const
776{
777 XMLNode* clone = this->ShallowClone(document);
778 if (!clone) return 0;
779
780 for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) {
781 XMLNode* childClone = child->DeepClone(document);
782 TIXMLASSERT(childClone);
783 clone->InsertEndChild(childClone);
784 }
785 return clone;
786}
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800787
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800788void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800789{
Lee Thomason624d43f2012-10-12 10:58:48 -0700790 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300791 TIXMLASSERT( _lastChild );
Dmitry-Me9cb4eca2016-08-18 18:10:59 +0300792 DeleteChild( _firstChild );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700793 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700794 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800795}
796
797
798void XMLNode::Unlink( XMLNode* child )
799{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300800 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300801 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300802 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700803 if ( child == _firstChild ) {
804 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700805 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700806 if ( child == _lastChild ) {
807 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700808 }
Lee Thomasond923c672012-01-23 08:44:25 -0800809
Lee Thomason624d43f2012-10-12 10:58:48 -0700810 if ( child->_prev ) {
811 child->_prev->_next = child->_next;
Lee Thomasonb754ddf2017-06-14 15:02:38 -0700812 child->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700813 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700814 if ( child->_next ) {
815 child->_next->_prev = child->_prev;
Lee Thomasonb754ddf2017-06-14 15:02:38 -0700816 child->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700817 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700818 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800819}
820
821
U-Stream\Leeae25a442012-02-17 17:48:16 -0800822void XMLNode::DeleteChild( XMLNode* node )
823{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300824 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300825 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700826 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100827 Unlink( node );
Lee Thomason816d3fa2017-06-05 14:35:55 -0700828 TIXMLASSERT(node->_prev == 0);
829 TIXMLASSERT(node->_next == 0);
830 TIXMLASSERT(node->_parent == 0);
Dmitry-Mee3225b12014-09-03 11:03:11 +0400831 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800832}
833
834
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800835XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
836{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300837 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300838 if ( addThis->_document != _document ) {
839 TIXMLASSERT( false );
840 return 0;
841 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800842 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700843
Lee Thomason624d43f2012-10-12 10:58:48 -0700844 if ( _lastChild ) {
845 TIXMLASSERT( _firstChild );
846 TIXMLASSERT( _lastChild->_next == 0 );
847 _lastChild->_next = addThis;
848 addThis->_prev = _lastChild;
849 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800850
Lee Thomason624d43f2012-10-12 10:58:48 -0700851 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700852 }
853 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700854 TIXMLASSERT( _firstChild == 0 );
855 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800856
Lee Thomason624d43f2012-10-12 10:58:48 -0700857 addThis->_prev = 0;
858 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700859 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700860 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700861 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800862}
863
864
Lee Thomason1ff38e02012-02-14 18:18:16 -0800865XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
866{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300867 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300868 if ( addThis->_document != _document ) {
869 TIXMLASSERT( false );
870 return 0;
871 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800872 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700873
Lee Thomason624d43f2012-10-12 10:58:48 -0700874 if ( _firstChild ) {
875 TIXMLASSERT( _lastChild );
876 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800877
Lee Thomason624d43f2012-10-12 10:58:48 -0700878 _firstChild->_prev = addThis;
879 addThis->_next = _firstChild;
880 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800881
Lee Thomason624d43f2012-10-12 10:58:48 -0700882 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700883 }
884 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700885 TIXMLASSERT( _lastChild == 0 );
886 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800887
Lee Thomason624d43f2012-10-12 10:58:48 -0700888 addThis->_prev = 0;
889 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700890 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700891 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400892 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800893}
894
895
896XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
897{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300898 TIXMLASSERT( addThis );
899 if ( addThis->_document != _document ) {
900 TIXMLASSERT( false );
901 return 0;
902 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700903
Dmitry-Meabb2d042014-12-09 12:59:31 +0300904 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700905
Lee Thomason624d43f2012-10-12 10:58:48 -0700906 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300907 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700908 return 0;
909 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800910
Lee Thomason624d43f2012-10-12 10:58:48 -0700911 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700912 // The last node or the only node.
913 return InsertEndChild( addThis );
914 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800915 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700916 addThis->_prev = afterThis;
917 addThis->_next = afterThis->_next;
918 afterThis->_next->_prev = addThis;
919 afterThis->_next = addThis;
920 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700921 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800922}
923
924
925
926
Dmitry-Me886ad972015-07-22 11:00:51 +0300927const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800928{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300929 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300930 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700931 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300932 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700933 }
934 }
935 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800936}
937
938
Dmitry-Me886ad972015-07-22 11:00:51 +0300939const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800940{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300941 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300942 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700943 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300944 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700945 }
946 }
947 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800948}
949
950
Dmitry-Me886ad972015-07-22 11:00:51 +0300951const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800952{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300953 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300954 const XMLElement* element = node->ToElementWithName( name );
955 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400956 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700957 }
958 }
959 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800960}
961
962
Dmitry-Me886ad972015-07-22 11:00:51 +0300963const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800964{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300965 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300966 const XMLElement* element = node->ToElementWithName( name );
967 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400968 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700969 }
970 }
971 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800972}
973
974
Dmitry-Me10b8ecc2017-04-12 17:57:44 +0300975char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -0800976{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700977 // This is a recursive method, but thinking about it "at the current level"
978 // it is a pretty simple flat list:
979 // <foo/>
980 // <!-- comment -->
981 //
982 // With a special case:
983 // <foo>
984 // </foo>
985 // <!-- comment -->
986 //
987 // Where the closing element (/foo) *must* be the next thing after the opening
988 // element, and the names must match. BUT the tricky bit is that the closing
989 // element will be read by the child.
990 //
991 // 'endTag' is the end tag for this node, it is returned by a call to a child.
992 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800993
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700994 while( p && *p ) {
995 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800996
Lee Thomason624d43f2012-10-12 10:58:48 -0700997 p = _document->Identify( p, &node );
Dmitry-Me43364312016-11-07 18:48:50 +0300998 TIXMLASSERT( p );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300999 if ( node == 0 ) {
1000 break;
1001 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001002
kezenatore3531812016-11-29 19:49:07 +10001003 int initialLineNum = node->_parseLineNum;
kezenatorec694152016-11-26 17:21:43 +10001004
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001005 StrPair endTag;
kezenator4f756162016-11-29 19:46:27 +10001006 p = node->ParseDeep( p, &endTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001007 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001008 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -07001009 if ( !_document->Error() ) {
kezenatore3531812016-11-29 19:49:07 +10001010 _document->SetError( XML_ERROR_PARSING, 0, 0, initialLineNum);
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001011 }
1012 break;
1013 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001014
Sarat Addepalli3df007e2015-05-20 10:43:51 +05301015 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301016 if ( decl ) {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001017 // Declarations are only allowed at document level
1018 bool wellLocated = ( ToDocument() != 0 );
1019 if ( wellLocated ) {
1020 // Multiple declarations are allowed but all declarations
1021 // must occur before anything else
1022 for ( const XMLNode* existingNode = _document->FirstChild(); existingNode; existingNode = existingNode->NextSibling() ) {
1023 if ( !existingNode->ToDeclaration() ) {
1024 wellLocated = false;
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301025 break;
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001026 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301027 }
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001028 }
1029 if ( !wellLocated ) {
kezenatore3531812016-11-29 19:49:07 +10001030 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0, initialLineNum);
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001031 DeleteNode( node );
1032 break;
1033 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301034 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301035
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001036 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001037 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -05001038 // We read the end tag. Return it to the parent.
1039 if ( ele->ClosingType() == XMLElement::CLOSING ) {
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001040 if ( parentEndTag ) {
1041 ele->_value.TransferTo( parentEndTag );
JayXone4bf6e32014-12-26 01:00:24 -05001042 }
1043 node->_memPool->SetTracked(); // created and then immediately deleted.
1044 DeleteNode( node );
1045 return p;
1046 }
1047
1048 // Handle an end tag returned to this level.
1049 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001050 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001051 if ( endTag.Empty() ) {
1052 if ( ele->ClosingType() == XMLElement::OPEN ) {
1053 mismatch = true;
1054 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001055 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001056 else {
1057 if ( ele->ClosingType() != XMLElement::OPEN ) {
1058 mismatch = true;
1059 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001060 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001061 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001062 }
1063 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001064 if ( mismatch ) {
kezenatore3531812016-11-29 19:49:07 +10001065 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0, initialLineNum);
JayXondbfdd8f2014-12-12 20:07:14 -05001066 DeleteNode( node );
1067 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001068 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001069 }
JayXondbfdd8f2014-12-12 20:07:14 -05001070 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001071 }
1072 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001073}
1074
Lee Thomason816d3fa2017-06-05 14:35:55 -07001075/*static*/ void XMLNode::DeleteNode( XMLNode* node )
Dmitry-Mee3225b12014-09-03 11:03:11 +04001076{
1077 if ( node == 0 ) {
1078 return;
1079 }
Lee Thomason816d3fa2017-06-05 14:35:55 -07001080 TIXMLASSERT(node->_document);
1081 if (!node->ToDocument()) {
1082 node->_document->MarkInUse(node);
1083 }
1084
Dmitry-Mee3225b12014-09-03 11:03:11 +04001085 MemPool* pool = node->_memPool;
1086 node->~XMLNode();
1087 pool->Free( node );
1088}
1089
Lee Thomason3cebdc42015-01-05 17:16:28 -08001090void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001091{
1092 TIXMLASSERT( insertThis );
1093 TIXMLASSERT( insertThis->_document == _document );
1094
Lee Thomason816d3fa2017-06-05 14:35:55 -07001095 if (insertThis->_parent) {
Dmitry-Me74e39402015-01-01 16:26:17 +03001096 insertThis->_parent->Unlink( insertThis );
Lee Thomason816d3fa2017-06-05 14:35:55 -07001097 }
1098 else {
1099 insertThis->_document->MarkInUse(insertThis);
Dmitry-Me74e39402015-01-01 16:26:17 +03001100 insertThis->_memPool->SetTracked();
Lee Thomason816d3fa2017-06-05 14:35:55 -07001101 }
Dmitry-Me74e39402015-01-01 16:26:17 +03001102}
1103
Dmitry-Meecb9b072016-10-12 16:44:59 +03001104const XMLElement* XMLNode::ToElementWithName( const char* name ) const
1105{
1106 const XMLElement* element = this->ToElement();
1107 if ( element == 0 ) {
1108 return 0;
1109 }
1110 if ( name == 0 ) {
1111 return element;
1112 }
1113 if ( XMLUtil::StringEqual( element->Name(), name ) ) {
1114 return element;
1115 }
1116 return 0;
1117}
1118
Lee Thomason5492a1c2012-01-23 15:32:10 -08001119// --------- XMLText ---------- //
kezenator4f756162016-11-29 19:46:27 +10001120char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001121{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001122 const char* start = p;
1123 if ( this->CData() ) {
kezenator4f756162016-11-29 19:46:27 +10001124 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001125 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001126 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001127 }
1128 return p;
1129 }
1130 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001131 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1132 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001133 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001134 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001135
kezenator4f756162016-11-29 19:46:27 +10001136 p = _value.ParseText( p, "<", flags, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001137 if ( p && *p ) {
1138 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001139 }
1140 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001141 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001142 }
1143 }
1144 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001145}
1146
1147
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001148XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1149{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001150 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001151 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001152 }
1153 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1154 text->SetCData( this->CData() );
1155 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001156}
1157
1158
1159bool XMLText::ShallowEqual( const XMLNode* compare ) const
1160{
Dmitry-Meba68a3a2017-03-21 11:39:48 +03001161 TIXMLASSERT( compare );
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001162 const XMLText* text = compare->ToText();
1163 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001164}
1165
1166
Lee Thomason56bdd022012-02-09 18:16:58 -08001167bool XMLText::Accept( XMLVisitor* visitor ) const
1168{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001169 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001170 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001171}
1172
1173
Lee Thomason3f57d272012-01-11 15:30:03 -08001174// --------- XMLComment ---------- //
1175
Lee Thomasone4422302012-01-20 17:59:50 -08001176XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001177{
1178}
1179
1180
Lee Thomasonce0763e2012-01-11 15:43:54 -08001181XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001182{
Lee Thomason3f57d272012-01-11 15:30:03 -08001183}
1184
1185
kezenator4f756162016-11-29 19:46:27 +10001186char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason3f57d272012-01-11 15:30:03 -08001187{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001188 // Comment parses as text.
1189 const char* start = p;
kezenator4f756162016-11-29 19:46:27 +10001190 p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001191 if ( p == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10001192 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001193 }
1194 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001195}
1196
1197
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001198XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1199{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001200 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001201 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001202 }
1203 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1204 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001205}
1206
1207
1208bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1209{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001210 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001211 const XMLComment* comment = compare->ToComment();
1212 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001213}
1214
1215
Lee Thomason751da522012-02-10 08:50:51 -08001216bool XMLComment::Accept( XMLVisitor* visitor ) const
1217{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001218 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001219 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001220}
Lee Thomason56bdd022012-02-09 18:16:58 -08001221
1222
Lee Thomason50f97b22012-02-11 16:33:40 -08001223// --------- XMLDeclaration ---------- //
1224
1225XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1226{
1227}
1228
1229
1230XMLDeclaration::~XMLDeclaration()
1231{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001232 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001233}
1234
1235
kezenator4f756162016-11-29 19:46:27 +10001236char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001237{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001238 // Declaration parses as text.
1239 const char* start = p;
kezenator4f756162016-11-29 19:46:27 +10001240 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001241 if ( p == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10001242 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001243 }
1244 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001245}
1246
1247
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001248XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1249{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001250 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001251 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001252 }
1253 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1254 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001255}
1256
1257
1258bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1259{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001260 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001261 const XMLDeclaration* declaration = compare->ToDeclaration();
1262 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001263}
1264
1265
1266
Lee Thomason50f97b22012-02-11 16:33:40 -08001267bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1268{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001269 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001270 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001271}
1272
1273// --------- XMLUnknown ---------- //
1274
1275XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1276{
1277}
1278
1279
1280XMLUnknown::~XMLUnknown()
1281{
1282}
1283
1284
kezenator4f756162016-11-29 19:46:27 +10001285char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001286{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001287 // Unknown parses as text.
1288 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001289
kezenator4f756162016-11-29 19:46:27 +10001290 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001291 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001292 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001293 }
1294 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001295}
1296
1297
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001298XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1299{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001300 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001301 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001302 }
1303 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1304 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001305}
1306
1307
1308bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1309{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001310 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001311 const XMLUnknown* unknown = compare->ToUnknown();
1312 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001313}
1314
1315
Lee Thomason50f97b22012-02-11 16:33:40 -08001316bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1317{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001318 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001319 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001320}
1321
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001322// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001323
1324const char* XMLAttribute::Name() const
1325{
1326 return _name.GetStr();
1327}
1328
1329const char* XMLAttribute::Value() const
1330{
1331 return _value.GetStr();
1332}
1333
kezenator4f756162016-11-29 19:46:27 +10001334char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001335{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001336 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001337 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001338 if ( !p || !*p ) {
1339 return 0;
1340 }
Lee Thomason22aead12012-01-23 13:29:35 -08001341
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001342 // Skip white space before =
kezenator4f756162016-11-29 19:46:27 +10001343 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001344 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001345 return 0;
1346 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001347
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001348 ++p; // move up to opening quote
kezenator4f756162016-11-29 19:46:27 +10001349 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001350 if ( *p != '\"' && *p != '\'' ) {
1351 return 0;
1352 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001353
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001354 char endTag[2] = { *p, 0 };
1355 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001356
kezenator4f756162016-11-29 19:46:27 +10001357 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001358 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001359}
1360
1361
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001362void XMLAttribute::SetName( const char* n )
1363{
Lee Thomason624d43f2012-10-12 10:58:48 -07001364 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001365}
1366
1367
Lee Thomason2fa81722012-11-09 12:37:46 -08001368XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001369{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001370 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001371 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001372 }
1373 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001374}
1375
1376
Lee Thomason2fa81722012-11-09 12:37:46 -08001377XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001378{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001379 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001380 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001381 }
1382 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001383}
1384
1385
Lee Thomason51c12712016-06-04 20:18:49 -07001386XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1387{
1388 if (XMLUtil::ToInt64(Value(), value)) {
1389 return XML_SUCCESS;
1390 }
1391 return XML_WRONG_ATTRIBUTE_TYPE;
1392}
1393
1394
Lee Thomason2fa81722012-11-09 12:37:46 -08001395XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001396{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001397 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001398 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001399 }
1400 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001401}
1402
1403
Lee Thomason2fa81722012-11-09 12:37:46 -08001404XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001405{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001406 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001407 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001408 }
1409 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001410}
1411
1412
Lee Thomason2fa81722012-11-09 12:37:46 -08001413XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001414{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001415 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001416 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001417 }
1418 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001419}
1420
1421
1422void XMLAttribute::SetAttribute( const char* v )
1423{
Lee Thomason624d43f2012-10-12 10:58:48 -07001424 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001425}
1426
1427
Lee Thomason1ff38e02012-02-14 18:18:16 -08001428void XMLAttribute::SetAttribute( int v )
1429{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001430 char buf[BUF_SIZE];
1431 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001432 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001433}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001434
1435
1436void XMLAttribute::SetAttribute( unsigned v )
1437{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001438 char buf[BUF_SIZE];
1439 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001440 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001441}
1442
1443
Lee Thomason51c12712016-06-04 20:18:49 -07001444void XMLAttribute::SetAttribute(int64_t v)
1445{
1446 char buf[BUF_SIZE];
1447 XMLUtil::ToStr(v, buf, BUF_SIZE);
1448 _value.SetStr(buf);
1449}
1450
1451
1452
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001453void XMLAttribute::SetAttribute( bool v )
1454{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001455 char buf[BUF_SIZE];
1456 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001457 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001458}
1459
1460void XMLAttribute::SetAttribute( double v )
1461{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001462 char buf[BUF_SIZE];
1463 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001464 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001465}
1466
1467void XMLAttribute::SetAttribute( float v )
1468{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001469 char buf[BUF_SIZE];
1470 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001471 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001472}
1473
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001474
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001475// --------- XMLElement ---------- //
1476XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Dmitry-Mee5035632017-04-05 18:02:40 +03001477 _closingType( OPEN ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001478 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001479{
1480}
1481
1482
1483XMLElement::~XMLElement()
1484{
Lee Thomason624d43f2012-10-12 10:58:48 -07001485 while( _rootAttribute ) {
1486 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001487 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001488 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001489 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001490}
1491
1492
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001493const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1494{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001495 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001496 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1497 return a;
1498 }
1499 }
1500 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001501}
1502
1503
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001504const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001505{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001506 const XMLAttribute* a = FindAttribute( name );
1507 if ( !a ) {
1508 return 0;
1509 }
1510 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1511 return a->Value();
1512 }
1513 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001514}
1515
Josh Wittnercf3dd092016-10-11 18:57:17 -07001516int XMLElement::IntAttribute(const char* name, int defaultValue) const
1517{
1518 int i = defaultValue;
1519 QueryIntAttribute(name, &i);
1520 return i;
1521}
1522
1523unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
1524{
1525 unsigned i = defaultValue;
1526 QueryUnsignedAttribute(name, &i);
1527 return i;
1528}
1529
1530int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
1531{
1532 int64_t i = defaultValue;
1533 QueryInt64Attribute(name, &i);
1534 return i;
1535}
1536
1537bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
1538{
1539 bool b = defaultValue;
1540 QueryBoolAttribute(name, &b);
1541 return b;
1542}
1543
1544double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
1545{
1546 double d = defaultValue;
1547 QueryDoubleAttribute(name, &d);
1548 return d;
1549}
1550
1551float XMLElement::FloatAttribute(const char* name, float defaultValue) const
1552{
1553 float f = defaultValue;
1554 QueryFloatAttribute(name, &f);
1555 return f;
1556}
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001557
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001558const char* XMLElement::GetText() const
1559{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001560 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001561 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001562 }
1563 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001564}
1565
1566
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001567void XMLElement::SetText( const char* inText )
1568{
Uli Kusterer869bb592014-01-21 01:36:16 +01001569 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001570 FirstChild()->SetValue( inText );
1571 else {
1572 XMLText* theText = GetDocument()->NewText( inText );
1573 InsertFirstChild( theText );
1574 }
1575}
1576
Lee Thomason5bb2d802014-01-24 10:42:57 -08001577
1578void XMLElement::SetText( int v )
1579{
1580 char buf[BUF_SIZE];
1581 XMLUtil::ToStr( v, buf, BUF_SIZE );
1582 SetText( buf );
1583}
1584
1585
1586void XMLElement::SetText( unsigned v )
1587{
1588 char buf[BUF_SIZE];
1589 XMLUtil::ToStr( v, buf, BUF_SIZE );
1590 SetText( buf );
1591}
1592
1593
Lee Thomason51c12712016-06-04 20:18:49 -07001594void XMLElement::SetText(int64_t v)
1595{
1596 char buf[BUF_SIZE];
1597 XMLUtil::ToStr(v, buf, BUF_SIZE);
1598 SetText(buf);
1599}
1600
1601
1602void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001603{
1604 char buf[BUF_SIZE];
1605 XMLUtil::ToStr( v, buf, BUF_SIZE );
1606 SetText( buf );
1607}
1608
1609
1610void XMLElement::SetText( float v )
1611{
1612 char buf[BUF_SIZE];
1613 XMLUtil::ToStr( v, buf, BUF_SIZE );
1614 SetText( buf );
1615}
1616
1617
1618void XMLElement::SetText( double v )
1619{
1620 char buf[BUF_SIZE];
1621 XMLUtil::ToStr( v, buf, BUF_SIZE );
1622 SetText( buf );
1623}
1624
1625
MortenMacFly4ee49f12013-01-14 20:03:14 +01001626XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001627{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001628 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001629 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001630 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001631 return XML_SUCCESS;
1632 }
1633 return XML_CAN_NOT_CONVERT_TEXT;
1634 }
1635 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001636}
1637
1638
MortenMacFly4ee49f12013-01-14 20:03:14 +01001639XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001640{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001641 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001642 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001643 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001644 return XML_SUCCESS;
1645 }
1646 return XML_CAN_NOT_CONVERT_TEXT;
1647 }
1648 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001649}
1650
1651
Lee Thomason51c12712016-06-04 20:18:49 -07001652XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1653{
1654 if (FirstChild() && FirstChild()->ToText()) {
1655 const char* t = FirstChild()->Value();
1656 if (XMLUtil::ToInt64(t, ival)) {
1657 return XML_SUCCESS;
1658 }
1659 return XML_CAN_NOT_CONVERT_TEXT;
1660 }
1661 return XML_NO_TEXT_NODE;
1662}
1663
1664
MortenMacFly4ee49f12013-01-14 20:03:14 +01001665XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001666{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001667 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001668 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001669 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001670 return XML_SUCCESS;
1671 }
1672 return XML_CAN_NOT_CONVERT_TEXT;
1673 }
1674 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001675}
1676
1677
MortenMacFly4ee49f12013-01-14 20:03:14 +01001678XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001679{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001680 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001681 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001682 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001683 return XML_SUCCESS;
1684 }
1685 return XML_CAN_NOT_CONVERT_TEXT;
1686 }
1687 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001688}
1689
1690
MortenMacFly4ee49f12013-01-14 20:03:14 +01001691XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001692{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001693 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001694 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001695 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001696 return XML_SUCCESS;
1697 }
1698 return XML_CAN_NOT_CONVERT_TEXT;
1699 }
1700 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001701}
1702
Josh Wittnercf3dd092016-10-11 18:57:17 -07001703int XMLElement::IntText(int defaultValue) const
1704{
1705 int i = defaultValue;
1706 QueryIntText(&i);
1707 return i;
1708}
1709
1710unsigned XMLElement::UnsignedText(unsigned defaultValue) const
1711{
1712 unsigned i = defaultValue;
1713 QueryUnsignedText(&i);
1714 return i;
1715}
1716
1717int64_t XMLElement::Int64Text(int64_t defaultValue) const
1718{
1719 int64_t i = defaultValue;
1720 QueryInt64Text(&i);
1721 return i;
1722}
1723
1724bool XMLElement::BoolText(bool defaultValue) const
1725{
1726 bool b = defaultValue;
1727 QueryBoolText(&b);
1728 return b;
1729}
1730
1731double XMLElement::DoubleText(double defaultValue) const
1732{
1733 double d = defaultValue;
1734 QueryDoubleText(&d);
1735 return d;
1736}
1737
1738float XMLElement::FloatText(float defaultValue) const
1739{
1740 float f = defaultValue;
1741 QueryFloatText(&f);
1742 return f;
1743}
Lee Thomason21be8822012-07-15 17:27:22 -07001744
1745
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001746XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1747{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001748 XMLAttribute* last = 0;
1749 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001750 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001751 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001752 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001753 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1754 break;
1755 }
1756 }
1757 if ( !attrib ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001758 attrib = CreateAttribute();
1759 TIXMLASSERT( attrib );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001760 if ( last ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001761 TIXMLASSERT( last->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001762 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001763 }
1764 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001765 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001766 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001767 }
1768 attrib->SetName( name );
1769 }
1770 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001771}
1772
1773
U-Stream\Leeae25a442012-02-17 17:48:16 -08001774void XMLElement::DeleteAttribute( const char* name )
1775{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001776 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001777 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001778 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1779 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001780 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001781 }
1782 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001783 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001784 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001785 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001786 break;
1787 }
1788 prev = a;
1789 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001790}
1791
1792
kezenator4f756162016-11-29 19:46:27 +10001793char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001794{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001795 const char* start = p;
1796 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001797
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001798 // Read the attributes.
1799 while( p ) {
kezenator4f756162016-11-29 19:46:27 +10001800 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001801 if ( !(*p) ) {
kezenatorec694152016-11-26 17:21:43 +10001802 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name(), _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001803 return 0;
1804 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001805
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001806 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001807 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001808 XMLAttribute* attrib = CreateAttribute();
1809 TIXMLASSERT( attrib );
kezenatorec694152016-11-26 17:21:43 +10001810 attrib->_parseLineNum = _document->_parseCurLineNum;
Lee Thomasond1983222012-02-06 08:41:24 -08001811
kezenatorec694152016-11-26 17:21:43 +10001812 int attrLineNum = attrib->_parseLineNum;
1813
kezenator4f756162016-11-29 19:46:27 +10001814 p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001815 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001816 DeleteAttribute( attrib );
kezenatorec694152016-11-26 17:21:43 +10001817 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p, attrLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001818 return 0;
1819 }
1820 // There is a minor bug here: if the attribute in the source xml
1821 // document is duplicated, it will not be detected and the
1822 // attribute will be doubly added. However, tracking the 'prevAttribute'
1823 // avoids re-scanning the attribute list. Preferring performance for
1824 // now, may reconsider in the future.
1825 if ( prevAttribute ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001826 TIXMLASSERT( prevAttribute->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001827 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001828 }
1829 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001830 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001831 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001832 }
1833 prevAttribute = attrib;
1834 }
1835 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001836 else if ( *p == '>' ) {
1837 ++p;
1838 break;
1839 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001840 // end of the tag
1841 else if ( *p == '/' && *(p+1) == '>' ) {
1842 _closingType = CLOSED;
1843 return p+2; // done; sealed element.
1844 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001845 else {
kezenatorec694152016-11-26 17:21:43 +10001846 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001847 return 0;
1848 }
1849 }
1850 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001851}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001852
Dmitry-Mee3225b12014-09-03 11:03:11 +04001853void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1854{
1855 if ( attribute == 0 ) {
1856 return;
1857 }
1858 MemPool* pool = attribute->_memPool;
1859 attribute->~XMLAttribute();
1860 pool->Free( attribute );
1861}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001862
Dmitry-Mea60caa22016-11-22 18:28:08 +03001863XMLAttribute* XMLElement::CreateAttribute()
1864{
1865 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
1866 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
Dmitry-Me7221b492017-03-03 15:45:51 +03001867 TIXMLASSERT( attrib );
Dmitry-Mea60caa22016-11-22 18:28:08 +03001868 attrib->_memPool = &_document->_attributePool;
1869 attrib->_memPool->SetTracked();
1870 return attrib;
1871}
1872
Lee Thomason67d61312012-01-24 16:01:51 -08001873//
1874// <ele></ele>
1875// <ele>foo<b>bar</b></ele>
1876//
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001877char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -08001878{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001879 // Read the element name.
kezenator4f756162016-11-29 19:46:27 +10001880 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomason67d61312012-01-24 16:01:51 -08001881
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001882 // The closing element is the </element> form. It is
1883 // parsed just like a regular element then deleted from
1884 // the DOM.
1885 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001886 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001887 ++p;
1888 }
Lee Thomason67d61312012-01-24 16:01:51 -08001889
Lee Thomason624d43f2012-10-12 10:58:48 -07001890 p = _value.ParseName( p );
1891 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001892 return 0;
1893 }
Lee Thomason67d61312012-01-24 16:01:51 -08001894
kezenator4f756162016-11-29 19:46:27 +10001895 p = ParseAttributes( p, curLineNumPtr );
Dmitry-Mee5035632017-04-05 18:02:40 +03001896 if ( !p || !*p || _closingType != OPEN ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001897 return p;
1898 }
Lee Thomason67d61312012-01-24 16:01:51 -08001899
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001900 p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001901 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001902}
1903
1904
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001905
1906XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1907{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001908 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001909 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001910 }
1911 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1912 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1913 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1914 }
1915 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001916}
1917
1918
1919bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1920{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001921 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001922 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001923 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001924
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001925 const XMLAttribute* a=FirstAttribute();
1926 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001927
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001928 while ( a && b ) {
1929 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1930 return false;
1931 }
1932 a = a->Next();
1933 b = b->Next();
1934 }
1935 if ( a || b ) {
1936 // different count
1937 return false;
1938 }
1939 return true;
1940 }
1941 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001942}
1943
1944
Lee Thomason751da522012-02-10 08:50:51 -08001945bool XMLElement::Accept( XMLVisitor* visitor ) const
1946{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001947 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001948 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001949 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1950 if ( !node->Accept( visitor ) ) {
1951 break;
1952 }
1953 }
1954 }
1955 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001956}
Lee Thomason56bdd022012-02-09 18:16:58 -08001957
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001958
Lee Thomason3f57d272012-01-11 15:30:03 -08001959// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001960
1961// Warning: List must match 'enum XMLError'
1962const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1963 "XML_SUCCESS",
1964 "XML_NO_ATTRIBUTE",
1965 "XML_WRONG_ATTRIBUTE_TYPE",
1966 "XML_ERROR_FILE_NOT_FOUND",
1967 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1968 "XML_ERROR_FILE_READ_ERROR",
1969 "XML_ERROR_ELEMENT_MISMATCH",
1970 "XML_ERROR_PARSING_ELEMENT",
1971 "XML_ERROR_PARSING_ATTRIBUTE",
1972 "XML_ERROR_IDENTIFYING_TAG",
1973 "XML_ERROR_PARSING_TEXT",
1974 "XML_ERROR_PARSING_CDATA",
1975 "XML_ERROR_PARSING_COMMENT",
1976 "XML_ERROR_PARSING_DECLARATION",
1977 "XML_ERROR_PARSING_UNKNOWN",
1978 "XML_ERROR_EMPTY_DOCUMENT",
1979 "XML_ERROR_MISMATCHED_ELEMENT",
1980 "XML_ERROR_PARSING",
1981 "XML_CAN_NOT_CONVERT_TEXT",
1982 "XML_NO_TEXT_NODE"
1983};
1984
1985
Dmitry-Meae8a82a2017-03-03 15:40:32 +03001986XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001987 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001988 _writeBOM( false ),
1989 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07001990 _errorID(XML_SUCCESS),
Dmitry-Meae8a82a2017-03-03 15:40:32 +03001991 _whitespaceMode( whitespaceMode ),
Dmitry-Mef89bd3e2017-01-18 18:33:55 +03001992 _errorLineNum( 0 ),
1993 _charBuffer( 0 ),
1994 _parseCurLineNum( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001995{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03001996 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
1997 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08001998}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001999
2000
Lee Thomason3f57d272012-01-11 15:30:03 -08002001XMLDocument::~XMLDocument()
2002{
Lee Thomasonf07b9522014-10-30 13:25:12 -07002003 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08002004}
2005
2006
Lee Thomason816d3fa2017-06-05 14:35:55 -07002007void XMLDocument::MarkInUse(XMLNode* node)
2008{
2009 TIXMLASSERT(node->_parent == 0);
2010
2011 for (int i = 0; i < _unlinked.Size(); ++i) {
2012 if (node == _unlinked[i]) {
2013 _unlinked.SwapRemove(i);
2014 break;
2015 }
2016 }
2017}
2018
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002019void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08002020{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002021 DeleteChildren();
Lee Thomason816d3fa2017-06-05 14:35:55 -07002022 while( _unlinked.Size()) {
2023 DeleteNode(_unlinked[0]); // Will remove from _unlinked as part of delete.
2024 }
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002025
Dmitry-Meab37df82014-11-28 12:08:36 +03002026#ifdef DEBUG
2027 const bool hadError = Error();
2028#endif
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002029 ClearError();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002030
Lee Thomason624d43f2012-10-12 10:58:48 -07002031 delete [] _charBuffer;
2032 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07002033
2034#if 0
2035 _textPool.Trace( "text" );
2036 _elementPool.Trace( "element" );
2037 _commentPool.Trace( "comment" );
2038 _attributePool.Trace( "attribute" );
2039#endif
2040
2041#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002042 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002043 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
2044 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
2045 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
2046 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
2047 }
2048#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08002049}
2050
Lee Thomason3f57d272012-01-11 15:30:03 -08002051
Lee Thomason7085f002017-06-01 18:09:43 -07002052void XMLDocument::DeepCopy(XMLDocument* target)
2053{
2054 TIXMLASSERT(target);
Lee Thomason1346a172017-06-14 15:14:19 -07002055 if (target == this) {
2056 return; // technically success - a no-op.
2057 }
Lee Thomason7085f002017-06-01 18:09:43 -07002058
2059 target->Clear();
2060 for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {
2061 target->InsertEndChild(node->DeepClone(target));
2062 }
2063}
2064
Lee Thomason2c85a712012-01-31 08:24:24 -08002065XMLElement* XMLDocument::NewElement( const char* name )
2066{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002067 XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002068 ele->SetName( name );
2069 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08002070}
2071
2072
Lee Thomason1ff38e02012-02-14 18:18:16 -08002073XMLComment* XMLDocument::NewComment( const char* str )
2074{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002075 XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002076 comment->SetValue( str );
2077 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002078}
2079
2080
2081XMLText* XMLDocument::NewText( const char* str )
2082{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002083 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002084 text->SetValue( str );
2085 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002086}
2087
2088
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002089XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2090{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002091 XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002092 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2093 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002094}
2095
2096
2097XMLUnknown* XMLDocument::NewUnknown( const char* str )
2098{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002099 XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002100 unk->SetValue( str );
2101 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002102}
2103
Dmitry-Me01578db2014-08-19 10:18:48 +04002104static FILE* callfopen( const char* filepath, const char* mode )
2105{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002106 TIXMLASSERT( filepath );
2107 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002108#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2109 FILE* fp = 0;
2110 errno_t err = fopen_s( &fp, filepath, mode );
2111 if ( err ) {
2112 return 0;
2113 }
2114#else
2115 FILE* fp = fopen( filepath, mode );
2116#endif
2117 return fp;
2118}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08002119
2120void XMLDocument::DeleteNode( XMLNode* node ) {
2121 TIXMLASSERT( node );
2122 TIXMLASSERT(node->_document == this );
2123 if (node->_parent) {
2124 node->_parent->DeleteChild( node );
2125 }
2126 else {
2127 // Isn't in the tree.
2128 // Use the parent delete.
2129 // Also, we need to mark it tracked: we 'know'
2130 // it was never used.
2131 node->_memPool->SetTracked();
2132 // Call the static XMLNode version:
2133 XMLNode::DeleteNode(node);
2134 }
2135}
2136
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002137
Lee Thomason2fa81722012-11-09 12:37:46 -08002138XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002139{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002140 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04002141 FILE* fp = callfopen( filename, "rb" );
2142 if ( !fp ) {
kezenatorec694152016-11-26 17:21:43 +10002143 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002144 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002145 }
2146 LoadFile( fp );
2147 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002148 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002149}
2150
Dmitry-Me901fed52015-09-25 10:29:51 +03002151// This is likely overengineered template art to have a check that unsigned long value incremented
2152// by one still fits into size_t. If size_t type is larger than unsigned long type
2153// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
2154// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
2155// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
2156// types sizes relate to each other.
2157template
2158<bool = (sizeof(unsigned long) >= sizeof(size_t))>
2159struct LongFitsIntoSizeTMinusOne {
2160 static bool Fits( unsigned long value )
2161 {
2162 return value < (size_t)-1;
2163 }
2164};
2165
2166template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02002167struct LongFitsIntoSizeTMinusOne<false> {
2168 static bool Fits( unsigned long )
2169 {
2170 return true;
2171 }
2172};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002173
Lee Thomason2fa81722012-11-09 12:37:46 -08002174XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002175{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002176 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002177
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002178 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002179 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
kezenatorec694152016-11-26 17:21:43 +10002180 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002181 return _errorID;
2182 }
2183
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002184 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002185 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002186 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002187 if ( filelength == -1L ) {
kezenatorec694152016-11-26 17:21:43 +10002188 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002189 return _errorID;
2190 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002191 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002192
Dmitry-Me901fed52015-09-25 10:29:51 +03002193 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002194 // Cannot handle files which won't fit in buffer together with null terminator
kezenatorec694152016-11-26 17:21:43 +10002195 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002196 return _errorID;
2197 }
2198
Dmitry-Me72801b82015-05-07 09:41:39 +03002199 if ( filelength == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10002200 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002201 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002202 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002203
Dmitry-Me72801b82015-05-07 09:41:39 +03002204 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002205 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002206 _charBuffer = new char[size+1];
2207 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002208 if ( read != size ) {
kezenatorec694152016-11-26 17:21:43 +10002209 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002210 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002211 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002212
Lee Thomason624d43f2012-10-12 10:58:48 -07002213 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002214
Dmitry-Me97476b72015-01-01 16:15:57 +03002215 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002216 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002217}
2218
2219
Lee Thomason2fa81722012-11-09 12:37:46 -08002220XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002221{
Dmitry-Me01578db2014-08-19 10:18:48 +04002222 FILE* fp = callfopen( filename, "w" );
2223 if ( !fp ) {
kezenatorec694152016-11-26 17:21:43 +10002224 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002225 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002226 }
2227 SaveFile(fp, compact);
2228 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002229 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002230}
2231
2232
Lee Thomason2fa81722012-11-09 12:37:46 -08002233XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002234{
Ant Mitchell189198f2015-03-24 16:20:36 +00002235 // Clear any error from the last save, otherwise it will get reported
2236 // for *this* call.
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002237 ClearError();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002238 XMLPrinter stream( fp, compact );
2239 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002240 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002241}
2242
Lee Thomason1ff38e02012-02-14 18:18:16 -08002243
Lee Thomason2fa81722012-11-09 12:37:46 -08002244XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002245{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002246 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002247
Lee Thomason82d32002014-02-21 22:47:18 -08002248 if ( len == 0 || !p || !*p ) {
kezenatorec694152016-11-26 17:21:43 +10002249 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002250 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002251 }
2252 if ( len == (size_t)(-1) ) {
2253 len = strlen( p );
2254 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002255 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002256 _charBuffer = new char[ len+1 ];
2257 memcpy( _charBuffer, p, len );
2258 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002259
Dmitry-Me97476b72015-01-01 16:15:57 +03002260 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002261 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002262 // clean up now essentially dangling memory.
2263 // and the parse fail can put objects in the
2264 // pools that are dead and inaccessible.
2265 DeleteChildren();
2266 _elementPool.Clear();
2267 _attributePool.Clear();
2268 _textPool.Clear();
2269 _commentPool.Clear();
2270 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002271 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002272}
2273
2274
PKEuS1c5f99e2013-07-06 11:28:39 +02002275void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002276{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002277 if ( streamer ) {
2278 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002279 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002280 else {
2281 XMLPrinter stdoutStreamer( stdout );
2282 Accept( &stdoutStreamer );
2283 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002284}
2285
2286
kezenatorec694152016-11-26 17:21:43 +10002287void XMLDocument::SetError( XMLError error, const char* str1, const char* str2, int lineNum )
Lee Thomason67d61312012-01-24 16:01:51 -08002288{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002289 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002290 _errorID = error;
Lee Thomason584af572016-09-05 14:14:16 -07002291
2292 _errorStr1.Reset();
2293 _errorStr2.Reset();
kezenatorec694152016-11-26 17:21:43 +10002294 _errorLineNum = lineNum;
Lee Thomason584af572016-09-05 14:14:16 -07002295
2296 if (str1)
2297 _errorStr1.SetStr(str1);
2298 if (str2)
2299 _errorStr2.SetStr(str2);
Lee Thomason67d61312012-01-24 16:01:51 -08002300}
2301
Lee Thomasone90e9012016-12-24 07:34:39 -08002302/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
Lee Thomason331596e2014-09-11 14:56:43 -07002303{
kezenator5a700712016-11-26 13:54:42 +10002304 TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2305 const char* errorName = _errorNames[errorID];
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002306 TIXMLASSERT( errorName && errorName[0] );
2307 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002308}
Lee Thomason5cae8972012-01-24 18:03:07 -08002309
kezenator5a700712016-11-26 13:54:42 +10002310const char* XMLDocument::ErrorName() const
2311{
Lee Thomasone90e9012016-12-24 07:34:39 -08002312 return ErrorIDToName(_errorID);
kezenator5a700712016-11-26 13:54:42 +10002313}
2314
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002315void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002316{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002317 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002318 static const int LEN = 20;
2319 char buf1[LEN] = { 0 };
2320 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002321
Lee Thomason584af572016-09-05 14:14:16 -07002322 if ( !_errorStr1.Empty() ) {
2323 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002324 }
Lee Thomason584af572016-09-05 14:14:16 -07002325 if ( !_errorStr2.Empty() ) {
2326 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002327 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002328
Dmitry-Me2ad43202015-04-16 12:18:58 +03002329 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2330 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2331 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
kezenatorec694152016-11-26 17:21:43 +10002332 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s line=%d\n",
2333 static_cast<int>( _errorID ), ErrorName(), buf1, buf2, _errorLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002334 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002335}
2336
Dmitry-Me97476b72015-01-01 16:15:57 +03002337void XMLDocument::Parse()
2338{
2339 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2340 TIXMLASSERT( _charBuffer );
kezenatorec694152016-11-26 17:21:43 +10002341 _parseCurLineNum = 1;
2342 _parseLineNum = 1;
Lee Thomason3cebdc42015-01-05 17:16:28 -08002343 char* p = _charBuffer;
kezenator4f756162016-11-29 19:46:27 +10002344 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mee28be752015-01-09 14:59:30 +03002345 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002346 if ( !*p ) {
kezenatorec694152016-11-26 17:21:43 +10002347 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002348 return;
2349 }
kezenator4f756162016-11-29 19:46:27 +10002350 ParseDeep(p, 0, &_parseCurLineNum );
Dmitry-Me97476b72015-01-01 16:15:57 +03002351}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002352
PKEuS1bfb9542013-08-04 13:51:17 +02002353XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002354 _elementJustOpened( false ),
2355 _firstElement( true ),
2356 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002357 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002358 _textDepth( -1 ),
2359 _processEntities( true ),
2360 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002361{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002362 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002363 _entityFlag[i] = false;
2364 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002365 }
2366 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002367 const char entityValue = entities[i].value;
Dmitry-Mec5f1e7c2016-10-14 10:33:02 +03002368 TIXMLASSERT( ((unsigned char)entityValue) < ENTITY_RANGE );
Dmitry-Me8b67d742014-12-22 11:35:12 +03002369 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002370 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002371 _restrictedEntityFlag[(unsigned char)'&'] = true;
2372 _restrictedEntityFlag[(unsigned char)'<'] = true;
2373 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002374 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002375}
2376
2377
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002378void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002379{
2380 va_list va;
2381 va_start( va, format );
2382
Lee Thomason624d43f2012-10-12 10:58:48 -07002383 if ( _fp ) {
2384 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002385 }
2386 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002387 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002388 // Close out and re-start the va-args
2389 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002390 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002391 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002392 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002393 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002394 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002395 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002396 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002397}
2398
2399
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002400void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002401{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002402 for( int i=0; i<depth; ++i ) {
2403 Print( " " );
2404 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002405}
2406
2407
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002408void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002409{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002410 // Look for runs of bytes between entities to print.
2411 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002412
Lee Thomason624d43f2012-10-12 10:58:48 -07002413 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002414 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002415 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002416 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002417 // Remember, char is sometimes signed. (How many times has that bitten me?)
2418 if ( *q > 0 && *q < ENTITY_RANGE ) {
2419 // Check for entities. If one is found, flush
2420 // the stream up until the entity, write the
2421 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002422 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002423 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002424 const size_t delta = q - p;
2425 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002426 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002427 Print( "%.*s", toPrint, p );
2428 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002429 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002430 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002431 for( int i=0; i<NUM_ENTITIES; ++i ) {
2432 if ( entities[i].value == *q ) {
2433 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002434 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002435 break;
2436 }
2437 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002438 if ( !entityPatternPrinted ) {
2439 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2440 TIXMLASSERT( false );
2441 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002442 ++p;
2443 }
2444 }
2445 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002446 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002447 }
2448 }
2449 // Flush the remaining string. This will be the entire
2450 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002451 TIXMLASSERT( p <= q );
2452 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002453 Print( "%s", p );
2454 }
Lee Thomason857b8682012-01-25 17:50:25 -08002455}
2456
U-Stream\Leeae25a442012-02-17 17:48:16 -08002457
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002458void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002459{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002460 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002461 static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002462 Print( "%s", bom );
2463 }
2464 if ( writeDec ) {
2465 PushDeclaration( "xml version=\"1.0\"" );
2466 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002467}
2468
2469
Uli Kusterer593a33d2014-02-01 12:48:51 +01002470void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002471{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002472 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002473 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002474
Uli Kusterer593a33d2014-02-01 12:48:51 +01002475 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002476 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002477 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002478 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002479 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002480 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002481
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002482 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002483 _elementJustOpened = true;
2484 _firstElement = false;
2485 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002486}
2487
2488
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002489void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002490{
Lee Thomason624d43f2012-10-12 10:58:48 -07002491 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002492 Print( " %s=\"", name );
2493 PrintString( value, false );
2494 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002495}
2496
2497
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002498void XMLPrinter::PushAttribute( const char* name, int v )
2499{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002500 char buf[BUF_SIZE];
2501 XMLUtil::ToStr( v, buf, BUF_SIZE );
2502 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002503}
2504
2505
2506void XMLPrinter::PushAttribute( const char* name, unsigned v )
2507{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002508 char buf[BUF_SIZE];
2509 XMLUtil::ToStr( v, buf, BUF_SIZE );
2510 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002511}
2512
2513
Lee Thomason51c12712016-06-04 20:18:49 -07002514void XMLPrinter::PushAttribute(const char* name, int64_t v)
2515{
2516 char buf[BUF_SIZE];
2517 XMLUtil::ToStr(v, buf, BUF_SIZE);
2518 PushAttribute(name, buf);
2519}
2520
2521
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002522void XMLPrinter::PushAttribute( const char* name, bool v )
2523{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002524 char buf[BUF_SIZE];
2525 XMLUtil::ToStr( v, buf, BUF_SIZE );
2526 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002527}
2528
2529
2530void XMLPrinter::PushAttribute( const char* name, double v )
2531{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002532 char buf[BUF_SIZE];
2533 XMLUtil::ToStr( v, buf, BUF_SIZE );
2534 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002535}
2536
2537
Uli Kustererca412e82014-02-01 13:35:05 +01002538void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002539{
Lee Thomason624d43f2012-10-12 10:58:48 -07002540 --_depth;
2541 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002542
Lee Thomason624d43f2012-10-12 10:58:48 -07002543 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002544 Print( "/>" );
2545 }
2546 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002547 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002548 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002549 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002550 }
2551 Print( "</%s>", name );
2552 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002553
Lee Thomason624d43f2012-10-12 10:58:48 -07002554 if ( _textDepth == _depth ) {
2555 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002556 }
Uli Kustererca412e82014-02-01 13:35:05 +01002557 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002558 Print( "\n" );
2559 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002560 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002561}
2562
2563
Dmitry-Mea092bc12014-12-23 17:57:05 +03002564void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002565{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002566 if ( !_elementJustOpened ) {
2567 return;
2568 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002569 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002570 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002571}
2572
2573
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002574void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002575{
Lee Thomason624d43f2012-10-12 10:58:48 -07002576 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002577
Dmitry-Mea092bc12014-12-23 17:57:05 +03002578 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002579 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002580 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002581 }
2582 else {
2583 PrintString( text, true );
2584 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002585}
2586
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002587void XMLPrinter::PushText( int64_t value )
2588{
2589 char buf[BUF_SIZE];
2590 XMLUtil::ToStr( value, buf, BUF_SIZE );
2591 PushText( buf, false );
2592}
2593
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002594void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002595{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002596 char buf[BUF_SIZE];
2597 XMLUtil::ToStr( value, buf, BUF_SIZE );
2598 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002599}
2600
2601
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002602void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002603{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002604 char buf[BUF_SIZE];
2605 XMLUtil::ToStr( value, buf, BUF_SIZE );
2606 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002607}
2608
2609
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002610void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002611{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002612 char buf[BUF_SIZE];
2613 XMLUtil::ToStr( value, buf, BUF_SIZE );
2614 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002615}
2616
2617
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002618void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002619{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002620 char buf[BUF_SIZE];
2621 XMLUtil::ToStr( value, buf, BUF_SIZE );
2622 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002623}
2624
2625
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002626void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002627{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002628 char buf[BUF_SIZE];
2629 XMLUtil::ToStr( value, buf, BUF_SIZE );
2630 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002631}
2632
Lee Thomason5cae8972012-01-24 18:03:07 -08002633
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002634void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002635{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002636 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002637 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002638 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002639 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002640 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002641 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002642 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002643}
Lee Thomason751da522012-02-10 08:50:51 -08002644
2645
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002646void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002647{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002648 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002649 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002650 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002651 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002652 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002653 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002654 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002655}
2656
2657
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002658void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002659{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002660 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002661 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002662 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002663 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002664 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002665 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002666 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002667}
2668
2669
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002670bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002671{
Lee Thomason624d43f2012-10-12 10:58:48 -07002672 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002673 if ( doc.HasBOM() ) {
2674 PushHeader( true, false );
2675 }
2676 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002677}
2678
2679
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002680bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002681{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002682 const XMLElement* parentElem = 0;
2683 if ( element.Parent() ) {
2684 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002685 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002686 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002687 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002688 while ( attribute ) {
2689 PushAttribute( attribute->Name(), attribute->Value() );
2690 attribute = attribute->Next();
2691 }
2692 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002693}
2694
2695
Uli Kustererca412e82014-02-01 13:35:05 +01002696bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002697{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002698 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002699 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002700}
2701
2702
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002703bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002704{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002705 PushText( text.Value(), text.CData() );
2706 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002707}
2708
2709
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002710bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002711{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002712 PushComment( comment.Value() );
2713 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002714}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002715
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002716bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002717{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002718 PushDeclaration( declaration.Value() );
2719 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002720}
2721
2722
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002723bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002724{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002725 PushUnknown( unknown.Value() );
2726 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002727}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002728
Lee Thomason685b8952012-11-12 13:00:06 -08002729} // namespace tinyxml2
2730