blob: 0168d9b20d57d4ed0e698604b776adebf66723d9 [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);
2055 TIXMLASSERT(target != this);
2056
2057 target->Clear();
2058 for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {
2059 target->InsertEndChild(node->DeepClone(target));
2060 }
2061}
2062
Lee Thomason2c85a712012-01-31 08:24:24 -08002063XMLElement* XMLDocument::NewElement( const char* name )
2064{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002065 XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002066 ele->SetName( name );
2067 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08002068}
2069
2070
Lee Thomason1ff38e02012-02-14 18:18:16 -08002071XMLComment* XMLDocument::NewComment( const char* str )
2072{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002073 XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002074 comment->SetValue( str );
2075 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002076}
2077
2078
2079XMLText* XMLDocument::NewText( const char* str )
2080{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002081 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002082 text->SetValue( str );
2083 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002084}
2085
2086
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002087XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2088{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002089 XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002090 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2091 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002092}
2093
2094
2095XMLUnknown* XMLDocument::NewUnknown( const char* str )
2096{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002097 XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002098 unk->SetValue( str );
2099 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002100}
2101
Dmitry-Me01578db2014-08-19 10:18:48 +04002102static FILE* callfopen( const char* filepath, const char* mode )
2103{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002104 TIXMLASSERT( filepath );
2105 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002106#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2107 FILE* fp = 0;
2108 errno_t err = fopen_s( &fp, filepath, mode );
2109 if ( err ) {
2110 return 0;
2111 }
2112#else
2113 FILE* fp = fopen( filepath, mode );
2114#endif
2115 return fp;
2116}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08002117
2118void XMLDocument::DeleteNode( XMLNode* node ) {
2119 TIXMLASSERT( node );
2120 TIXMLASSERT(node->_document == this );
2121 if (node->_parent) {
2122 node->_parent->DeleteChild( node );
2123 }
2124 else {
2125 // Isn't in the tree.
2126 // Use the parent delete.
2127 // Also, we need to mark it tracked: we 'know'
2128 // it was never used.
2129 node->_memPool->SetTracked();
2130 // Call the static XMLNode version:
2131 XMLNode::DeleteNode(node);
2132 }
2133}
2134
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002135
Lee Thomason2fa81722012-11-09 12:37:46 -08002136XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002137{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002138 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04002139 FILE* fp = callfopen( filename, "rb" );
2140 if ( !fp ) {
kezenatorec694152016-11-26 17:21:43 +10002141 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002142 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002143 }
2144 LoadFile( fp );
2145 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002146 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002147}
2148
Dmitry-Me901fed52015-09-25 10:29:51 +03002149// This is likely overengineered template art to have a check that unsigned long value incremented
2150// by one still fits into size_t. If size_t type is larger than unsigned long type
2151// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
2152// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
2153// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
2154// types sizes relate to each other.
2155template
2156<bool = (sizeof(unsigned long) >= sizeof(size_t))>
2157struct LongFitsIntoSizeTMinusOne {
2158 static bool Fits( unsigned long value )
2159 {
2160 return value < (size_t)-1;
2161 }
2162};
2163
2164template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02002165struct LongFitsIntoSizeTMinusOne<false> {
2166 static bool Fits( unsigned long )
2167 {
2168 return true;
2169 }
2170};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002171
Lee Thomason2fa81722012-11-09 12:37:46 -08002172XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002173{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002174 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002175
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002176 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002177 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
kezenatorec694152016-11-26 17:21:43 +10002178 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002179 return _errorID;
2180 }
2181
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002182 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002183 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002184 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002185 if ( filelength == -1L ) {
kezenatorec694152016-11-26 17:21:43 +10002186 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002187 return _errorID;
2188 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002189 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002190
Dmitry-Me901fed52015-09-25 10:29:51 +03002191 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002192 // Cannot handle files which won't fit in buffer together with null terminator
kezenatorec694152016-11-26 17:21:43 +10002193 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002194 return _errorID;
2195 }
2196
Dmitry-Me72801b82015-05-07 09:41:39 +03002197 if ( filelength == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10002198 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002199 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002200 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002201
Dmitry-Me72801b82015-05-07 09:41:39 +03002202 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002203 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002204 _charBuffer = new char[size+1];
2205 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002206 if ( read != size ) {
kezenatorec694152016-11-26 17:21:43 +10002207 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002208 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002209 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002210
Lee Thomason624d43f2012-10-12 10:58:48 -07002211 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002212
Dmitry-Me97476b72015-01-01 16:15:57 +03002213 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002214 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002215}
2216
2217
Lee Thomason2fa81722012-11-09 12:37:46 -08002218XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002219{
Dmitry-Me01578db2014-08-19 10:18:48 +04002220 FILE* fp = callfopen( filename, "w" );
2221 if ( !fp ) {
kezenatorec694152016-11-26 17:21:43 +10002222 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002223 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002224 }
2225 SaveFile(fp, compact);
2226 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002227 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002228}
2229
2230
Lee Thomason2fa81722012-11-09 12:37:46 -08002231XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002232{
Ant Mitchell189198f2015-03-24 16:20:36 +00002233 // Clear any error from the last save, otherwise it will get reported
2234 // for *this* call.
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002235 ClearError();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002236 XMLPrinter stream( fp, compact );
2237 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002238 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002239}
2240
Lee Thomason1ff38e02012-02-14 18:18:16 -08002241
Lee Thomason2fa81722012-11-09 12:37:46 -08002242XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002243{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002244 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002245
Lee Thomason82d32002014-02-21 22:47:18 -08002246 if ( len == 0 || !p || !*p ) {
kezenatorec694152016-11-26 17:21:43 +10002247 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002248 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002249 }
2250 if ( len == (size_t)(-1) ) {
2251 len = strlen( p );
2252 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002253 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002254 _charBuffer = new char[ len+1 ];
2255 memcpy( _charBuffer, p, len );
2256 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002257
Dmitry-Me97476b72015-01-01 16:15:57 +03002258 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002259 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002260 // clean up now essentially dangling memory.
2261 // and the parse fail can put objects in the
2262 // pools that are dead and inaccessible.
2263 DeleteChildren();
2264 _elementPool.Clear();
2265 _attributePool.Clear();
2266 _textPool.Clear();
2267 _commentPool.Clear();
2268 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002269 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002270}
2271
2272
PKEuS1c5f99e2013-07-06 11:28:39 +02002273void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002274{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002275 if ( streamer ) {
2276 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002277 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002278 else {
2279 XMLPrinter stdoutStreamer( stdout );
2280 Accept( &stdoutStreamer );
2281 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002282}
2283
2284
kezenatorec694152016-11-26 17:21:43 +10002285void XMLDocument::SetError( XMLError error, const char* str1, const char* str2, int lineNum )
Lee Thomason67d61312012-01-24 16:01:51 -08002286{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002287 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002288 _errorID = error;
Lee Thomason584af572016-09-05 14:14:16 -07002289
2290 _errorStr1.Reset();
2291 _errorStr2.Reset();
kezenatorec694152016-11-26 17:21:43 +10002292 _errorLineNum = lineNum;
Lee Thomason584af572016-09-05 14:14:16 -07002293
2294 if (str1)
2295 _errorStr1.SetStr(str1);
2296 if (str2)
2297 _errorStr2.SetStr(str2);
Lee Thomason67d61312012-01-24 16:01:51 -08002298}
2299
Lee Thomasone90e9012016-12-24 07:34:39 -08002300/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
Lee Thomason331596e2014-09-11 14:56:43 -07002301{
kezenator5a700712016-11-26 13:54:42 +10002302 TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2303 const char* errorName = _errorNames[errorID];
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002304 TIXMLASSERT( errorName && errorName[0] );
2305 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002306}
Lee Thomason5cae8972012-01-24 18:03:07 -08002307
kezenator5a700712016-11-26 13:54:42 +10002308const char* XMLDocument::ErrorName() const
2309{
Lee Thomasone90e9012016-12-24 07:34:39 -08002310 return ErrorIDToName(_errorID);
kezenator5a700712016-11-26 13:54:42 +10002311}
2312
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002313void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002314{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002315 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002316 static const int LEN = 20;
2317 char buf1[LEN] = { 0 };
2318 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002319
Lee Thomason584af572016-09-05 14:14:16 -07002320 if ( !_errorStr1.Empty() ) {
2321 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002322 }
Lee Thomason584af572016-09-05 14:14:16 -07002323 if ( !_errorStr2.Empty() ) {
2324 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002325 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002326
Dmitry-Me2ad43202015-04-16 12:18:58 +03002327 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2328 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2329 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
kezenatorec694152016-11-26 17:21:43 +10002330 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s line=%d\n",
2331 static_cast<int>( _errorID ), ErrorName(), buf1, buf2, _errorLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002332 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002333}
2334
Dmitry-Me97476b72015-01-01 16:15:57 +03002335void XMLDocument::Parse()
2336{
2337 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2338 TIXMLASSERT( _charBuffer );
kezenatorec694152016-11-26 17:21:43 +10002339 _parseCurLineNum = 1;
2340 _parseLineNum = 1;
Lee Thomason3cebdc42015-01-05 17:16:28 -08002341 char* p = _charBuffer;
kezenator4f756162016-11-29 19:46:27 +10002342 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mee28be752015-01-09 14:59:30 +03002343 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002344 if ( !*p ) {
kezenatorec694152016-11-26 17:21:43 +10002345 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002346 return;
2347 }
kezenator4f756162016-11-29 19:46:27 +10002348 ParseDeep(p, 0, &_parseCurLineNum );
Dmitry-Me97476b72015-01-01 16:15:57 +03002349}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002350
PKEuS1bfb9542013-08-04 13:51:17 +02002351XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002352 _elementJustOpened( false ),
2353 _firstElement( true ),
2354 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002355 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002356 _textDepth( -1 ),
2357 _processEntities( true ),
2358 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002359{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002360 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002361 _entityFlag[i] = false;
2362 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002363 }
2364 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002365 const char entityValue = entities[i].value;
Dmitry-Mec5f1e7c2016-10-14 10:33:02 +03002366 TIXMLASSERT( ((unsigned char)entityValue) < ENTITY_RANGE );
Dmitry-Me8b67d742014-12-22 11:35:12 +03002367 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002368 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002369 _restrictedEntityFlag[(unsigned char)'&'] = true;
2370 _restrictedEntityFlag[(unsigned char)'<'] = true;
2371 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002372 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002373}
2374
2375
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002376void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002377{
2378 va_list va;
2379 va_start( va, format );
2380
Lee Thomason624d43f2012-10-12 10:58:48 -07002381 if ( _fp ) {
2382 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002383 }
2384 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002385 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002386 // Close out and re-start the va-args
2387 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002388 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002389 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002390 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002391 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002392 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002393 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002394 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002395}
2396
2397
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002398void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002399{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002400 for( int i=0; i<depth; ++i ) {
2401 Print( " " );
2402 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002403}
2404
2405
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002406void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002407{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002408 // Look for runs of bytes between entities to print.
2409 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002410
Lee Thomason624d43f2012-10-12 10:58:48 -07002411 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002412 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002413 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002414 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002415 // Remember, char is sometimes signed. (How many times has that bitten me?)
2416 if ( *q > 0 && *q < ENTITY_RANGE ) {
2417 // Check for entities. If one is found, flush
2418 // the stream up until the entity, write the
2419 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002420 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002421 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002422 const size_t delta = q - p;
2423 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002424 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002425 Print( "%.*s", toPrint, p );
2426 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002427 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002428 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002429 for( int i=0; i<NUM_ENTITIES; ++i ) {
2430 if ( entities[i].value == *q ) {
2431 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002432 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002433 break;
2434 }
2435 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002436 if ( !entityPatternPrinted ) {
2437 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2438 TIXMLASSERT( false );
2439 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002440 ++p;
2441 }
2442 }
2443 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002444 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002445 }
2446 }
2447 // Flush the remaining string. This will be the entire
2448 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002449 TIXMLASSERT( p <= q );
2450 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002451 Print( "%s", p );
2452 }
Lee Thomason857b8682012-01-25 17:50:25 -08002453}
2454
U-Stream\Leeae25a442012-02-17 17:48:16 -08002455
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002456void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002457{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002458 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002459 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 -07002460 Print( "%s", bom );
2461 }
2462 if ( writeDec ) {
2463 PushDeclaration( "xml version=\"1.0\"" );
2464 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002465}
2466
2467
Uli Kusterer593a33d2014-02-01 12:48:51 +01002468void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002469{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002470 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002471 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002472
Uli Kusterer593a33d2014-02-01 12:48:51 +01002473 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002474 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002475 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002476 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002477 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002478 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002479
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002480 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002481 _elementJustOpened = true;
2482 _firstElement = false;
2483 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002484}
2485
2486
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002487void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002488{
Lee Thomason624d43f2012-10-12 10:58:48 -07002489 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002490 Print( " %s=\"", name );
2491 PrintString( value, false );
2492 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002493}
2494
2495
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002496void XMLPrinter::PushAttribute( const char* name, int v )
2497{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002498 char buf[BUF_SIZE];
2499 XMLUtil::ToStr( v, buf, BUF_SIZE );
2500 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002501}
2502
2503
2504void XMLPrinter::PushAttribute( const char* name, unsigned v )
2505{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002506 char buf[BUF_SIZE];
2507 XMLUtil::ToStr( v, buf, BUF_SIZE );
2508 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002509}
2510
2511
Lee Thomason51c12712016-06-04 20:18:49 -07002512void XMLPrinter::PushAttribute(const char* name, int64_t v)
2513{
2514 char buf[BUF_SIZE];
2515 XMLUtil::ToStr(v, buf, BUF_SIZE);
2516 PushAttribute(name, buf);
2517}
2518
2519
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002520void XMLPrinter::PushAttribute( const char* name, bool v )
2521{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002522 char buf[BUF_SIZE];
2523 XMLUtil::ToStr( v, buf, BUF_SIZE );
2524 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002525}
2526
2527
2528void XMLPrinter::PushAttribute( const char* name, double v )
2529{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002530 char buf[BUF_SIZE];
2531 XMLUtil::ToStr( v, buf, BUF_SIZE );
2532 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002533}
2534
2535
Uli Kustererca412e82014-02-01 13:35:05 +01002536void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002537{
Lee Thomason624d43f2012-10-12 10:58:48 -07002538 --_depth;
2539 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002540
Lee Thomason624d43f2012-10-12 10:58:48 -07002541 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002542 Print( "/>" );
2543 }
2544 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002545 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002546 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002547 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002548 }
2549 Print( "</%s>", name );
2550 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002551
Lee Thomason624d43f2012-10-12 10:58:48 -07002552 if ( _textDepth == _depth ) {
2553 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002554 }
Uli Kustererca412e82014-02-01 13:35:05 +01002555 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002556 Print( "\n" );
2557 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002558 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002559}
2560
2561
Dmitry-Mea092bc12014-12-23 17:57:05 +03002562void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002563{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002564 if ( !_elementJustOpened ) {
2565 return;
2566 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002567 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002568 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002569}
2570
2571
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002572void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002573{
Lee Thomason624d43f2012-10-12 10:58:48 -07002574 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002575
Dmitry-Mea092bc12014-12-23 17:57:05 +03002576 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002577 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002578 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002579 }
2580 else {
2581 PrintString( text, true );
2582 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002583}
2584
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002585void XMLPrinter::PushText( int64_t value )
2586{
2587 char buf[BUF_SIZE];
2588 XMLUtil::ToStr( value, buf, BUF_SIZE );
2589 PushText( buf, false );
2590}
2591
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002592void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002593{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002594 char buf[BUF_SIZE];
2595 XMLUtil::ToStr( value, buf, BUF_SIZE );
2596 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002597}
2598
2599
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002600void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002601{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002602 char buf[BUF_SIZE];
2603 XMLUtil::ToStr( value, buf, BUF_SIZE );
2604 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002605}
2606
2607
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002608void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002609{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002610 char buf[BUF_SIZE];
2611 XMLUtil::ToStr( value, buf, BUF_SIZE );
2612 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002613}
2614
2615
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002616void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002617{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002618 char buf[BUF_SIZE];
2619 XMLUtil::ToStr( value, buf, BUF_SIZE );
2620 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002621}
2622
2623
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002624void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002625{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002626 char buf[BUF_SIZE];
2627 XMLUtil::ToStr( value, buf, BUF_SIZE );
2628 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002629}
2630
Lee Thomason5cae8972012-01-24 18:03:07 -08002631
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002632void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002633{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002634 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002635 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002636 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002637 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002638 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002639 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002640 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002641}
Lee Thomason751da522012-02-10 08:50:51 -08002642
2643
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002644void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002645{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002646 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002647 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002648 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002649 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002650 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002651 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002652 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002653}
2654
2655
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002656void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002657{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002658 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002659 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002660 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002661 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002662 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002663 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002664 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002665}
2666
2667
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002668bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002669{
Lee Thomason624d43f2012-10-12 10:58:48 -07002670 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002671 if ( doc.HasBOM() ) {
2672 PushHeader( true, false );
2673 }
2674 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002675}
2676
2677
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002678bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002679{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002680 const XMLElement* parentElem = 0;
2681 if ( element.Parent() ) {
2682 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002683 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002684 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002685 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002686 while ( attribute ) {
2687 PushAttribute( attribute->Name(), attribute->Value() );
2688 attribute = attribute->Next();
2689 }
2690 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002691}
2692
2693
Uli Kustererca412e82014-02-01 13:35:05 +01002694bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002695{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002696 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002697 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002698}
2699
2700
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002701bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002702{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002703 PushText( text.Value(), text.CData() );
2704 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002705}
2706
2707
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002708bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002709{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002710 PushComment( comment.Value() );
2711 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002712}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002713
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002714bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002715{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002716 PushDeclaration( declaration.Value() );
2717 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002718}
2719
2720
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002721bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002722{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002723 PushUnknown( unknown.Value() );
2724 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002725}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002726
Lee Thomason685b8952012-11-12 13:00:06 -08002727} // namespace tinyxml2
2728