blob: adf7b5fdc9c74297c706c70d1c56f6f02818952a [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
775
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800776void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800777{
Lee Thomason624d43f2012-10-12 10:58:48 -0700778 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300779 TIXMLASSERT( _lastChild );
Dmitry-Me9cb4eca2016-08-18 18:10:59 +0300780 DeleteChild( _firstChild );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700781 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700782 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800783}
784
785
786void XMLNode::Unlink( XMLNode* child )
787{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300788 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300789 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300790 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700791 if ( child == _firstChild ) {
792 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700793 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700794 if ( child == _lastChild ) {
795 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700796 }
Lee Thomasond923c672012-01-23 08:44:25 -0800797
Lee Thomason624d43f2012-10-12 10:58:48 -0700798 if ( child->_prev ) {
799 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700800 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700801 if ( child->_next ) {
802 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700803 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700804 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800805}
806
807
U-Stream\Leeae25a442012-02-17 17:48:16 -0800808void XMLNode::DeleteChild( XMLNode* node )
809{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300810 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300811 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700812 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100813 Unlink( node );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400814 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800815}
816
817
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800818XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
819{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300820 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300821 if ( addThis->_document != _document ) {
822 TIXMLASSERT( false );
823 return 0;
824 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800825 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700826
Lee Thomason624d43f2012-10-12 10:58:48 -0700827 if ( _lastChild ) {
828 TIXMLASSERT( _firstChild );
829 TIXMLASSERT( _lastChild->_next == 0 );
830 _lastChild->_next = addThis;
831 addThis->_prev = _lastChild;
832 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800833
Lee Thomason624d43f2012-10-12 10:58:48 -0700834 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700835 }
836 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700837 TIXMLASSERT( _firstChild == 0 );
838 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800839
Lee Thomason624d43f2012-10-12 10:58:48 -0700840 addThis->_prev = 0;
841 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700842 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700843 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700844 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800845}
846
847
Lee Thomason1ff38e02012-02-14 18:18:16 -0800848XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
849{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300850 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300851 if ( addThis->_document != _document ) {
852 TIXMLASSERT( false );
853 return 0;
854 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800855 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700856
Lee Thomason624d43f2012-10-12 10:58:48 -0700857 if ( _firstChild ) {
858 TIXMLASSERT( _lastChild );
859 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800860
Lee Thomason624d43f2012-10-12 10:58:48 -0700861 _firstChild->_prev = addThis;
862 addThis->_next = _firstChild;
863 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800864
Lee Thomason624d43f2012-10-12 10:58:48 -0700865 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700866 }
867 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700868 TIXMLASSERT( _lastChild == 0 );
869 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800870
Lee Thomason624d43f2012-10-12 10:58:48 -0700871 addThis->_prev = 0;
872 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700873 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700874 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400875 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800876}
877
878
879XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
880{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300881 TIXMLASSERT( addThis );
882 if ( addThis->_document != _document ) {
883 TIXMLASSERT( false );
884 return 0;
885 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700886
Dmitry-Meabb2d042014-12-09 12:59:31 +0300887 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700888
Lee Thomason624d43f2012-10-12 10:58:48 -0700889 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300890 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700891 return 0;
892 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800893
Lee Thomason624d43f2012-10-12 10:58:48 -0700894 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700895 // The last node or the only node.
896 return InsertEndChild( addThis );
897 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800898 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700899 addThis->_prev = afterThis;
900 addThis->_next = afterThis->_next;
901 afterThis->_next->_prev = addThis;
902 afterThis->_next = addThis;
903 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700904 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800905}
906
907
908
909
Dmitry-Me886ad972015-07-22 11:00:51 +0300910const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800911{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300912 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300913 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700914 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300915 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700916 }
917 }
918 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800919}
920
921
Dmitry-Me886ad972015-07-22 11:00:51 +0300922const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800923{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300924 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300925 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700926 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300927 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700928 }
929 }
930 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800931}
932
933
Dmitry-Me886ad972015-07-22 11:00:51 +0300934const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800935{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300936 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300937 const XMLElement* element = node->ToElementWithName( name );
938 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400939 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700940 }
941 }
942 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800943}
944
945
Dmitry-Me886ad972015-07-22 11:00:51 +0300946const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800947{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300948 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300949 const XMLElement* element = node->ToElementWithName( name );
950 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400951 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700952 }
953 }
954 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800955}
956
957
kezenator4f756162016-11-29 19:46:27 +1000958char* XMLNode::ParseDeep( char* p, StrPair* parentEnd, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -0800959{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700960 // This is a recursive method, but thinking about it "at the current level"
961 // it is a pretty simple flat list:
962 // <foo/>
963 // <!-- comment -->
964 //
965 // With a special case:
966 // <foo>
967 // </foo>
968 // <!-- comment -->
969 //
970 // Where the closing element (/foo) *must* be the next thing after the opening
971 // element, and the names must match. BUT the tricky bit is that the closing
972 // element will be read by the child.
973 //
974 // 'endTag' is the end tag for this node, it is returned by a call to a child.
975 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800976
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700977 while( p && *p ) {
978 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800979
Lee Thomason624d43f2012-10-12 10:58:48 -0700980 p = _document->Identify( p, &node );
Dmitry-Me43364312016-11-07 18:48:50 +0300981 TIXMLASSERT( p );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300982 if ( node == 0 ) {
983 break;
984 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800985
kezenatore3531812016-11-29 19:49:07 +1000986 int initialLineNum = node->_parseLineNum;
kezenatorec694152016-11-26 17:21:43 +1000987
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700988 StrPair endTag;
kezenator4f756162016-11-29 19:46:27 +1000989 p = node->ParseDeep( p, &endTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700990 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400991 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700992 if ( !_document->Error() ) {
kezenatore3531812016-11-29 19:49:07 +1000993 _document->SetError( XML_ERROR_PARSING, 0, 0, initialLineNum);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700994 }
995 break;
996 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800997
Sarat Addepalli3df007e2015-05-20 10:43:51 +0530998 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530999 if ( decl ) {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001000 // Declarations are only allowed at document level
1001 bool wellLocated = ( ToDocument() != 0 );
1002 if ( wellLocated ) {
1003 // Multiple declarations are allowed but all declarations
1004 // must occur before anything else
1005 for ( const XMLNode* existingNode = _document->FirstChild(); existingNode; existingNode = existingNode->NextSibling() ) {
1006 if ( !existingNode->ToDeclaration() ) {
1007 wellLocated = false;
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301008 break;
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001009 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301010 }
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001011 }
1012 if ( !wellLocated ) {
kezenatore3531812016-11-29 19:49:07 +10001013 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0, initialLineNum);
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001014 DeleteNode( node );
1015 break;
1016 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301017 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301018
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001019 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001020 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -05001021 // We read the end tag. Return it to the parent.
1022 if ( ele->ClosingType() == XMLElement::CLOSING ) {
1023 if ( parentEnd ) {
1024 ele->_value.TransferTo( parentEnd );
1025 }
1026 node->_memPool->SetTracked(); // created and then immediately deleted.
1027 DeleteNode( node );
1028 return p;
1029 }
1030
1031 // Handle an end tag returned to this level.
1032 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001033 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001034 if ( endTag.Empty() ) {
1035 if ( ele->ClosingType() == XMLElement::OPEN ) {
1036 mismatch = true;
1037 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001038 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001039 else {
1040 if ( ele->ClosingType() != XMLElement::OPEN ) {
1041 mismatch = true;
1042 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001043 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001044 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001045 }
1046 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001047 if ( mismatch ) {
kezenatore3531812016-11-29 19:49:07 +10001048 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0, initialLineNum);
JayXondbfdd8f2014-12-12 20:07:14 -05001049 DeleteNode( node );
1050 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001051 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001052 }
JayXondbfdd8f2014-12-12 20:07:14 -05001053 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001054 }
1055 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001056}
1057
Dmitry-Mee3225b12014-09-03 11:03:11 +04001058void XMLNode::DeleteNode( XMLNode* node )
1059{
1060 if ( node == 0 ) {
1061 return;
1062 }
1063 MemPool* pool = node->_memPool;
1064 node->~XMLNode();
1065 pool->Free( node );
1066}
1067
Lee Thomason3cebdc42015-01-05 17:16:28 -08001068void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001069{
1070 TIXMLASSERT( insertThis );
1071 TIXMLASSERT( insertThis->_document == _document );
1072
1073 if ( insertThis->_parent )
1074 insertThis->_parent->Unlink( insertThis );
1075 else
1076 insertThis->_memPool->SetTracked();
1077}
1078
Dmitry-Meecb9b072016-10-12 16:44:59 +03001079const XMLElement* XMLNode::ToElementWithName( const char* name ) const
1080{
1081 const XMLElement* element = this->ToElement();
1082 if ( element == 0 ) {
1083 return 0;
1084 }
1085 if ( name == 0 ) {
1086 return element;
1087 }
1088 if ( XMLUtil::StringEqual( element->Name(), name ) ) {
1089 return element;
1090 }
1091 return 0;
1092}
1093
Lee Thomason5492a1c2012-01-23 15:32:10 -08001094// --------- XMLText ---------- //
kezenator4f756162016-11-29 19:46:27 +10001095char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001096{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001097 const char* start = p;
1098 if ( this->CData() ) {
kezenator4f756162016-11-29 19:46:27 +10001099 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001100 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001101 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001102 }
1103 return p;
1104 }
1105 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001106 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1107 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001108 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001109 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001110
kezenator4f756162016-11-29 19:46:27 +10001111 p = _value.ParseText( p, "<", flags, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001112 if ( p && *p ) {
1113 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001114 }
1115 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001116 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001117 }
1118 }
1119 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001120}
1121
1122
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001123XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1124{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001125 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001126 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001127 }
1128 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1129 text->SetCData( this->CData() );
1130 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001131}
1132
1133
1134bool XMLText::ShallowEqual( const XMLNode* compare ) const
1135{
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001136 const XMLText* text = compare->ToText();
1137 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001138}
1139
1140
Lee Thomason56bdd022012-02-09 18:16:58 -08001141bool XMLText::Accept( XMLVisitor* visitor ) const
1142{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001143 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001144 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001145}
1146
1147
Lee Thomason3f57d272012-01-11 15:30:03 -08001148// --------- XMLComment ---------- //
1149
Lee Thomasone4422302012-01-20 17:59:50 -08001150XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001151{
1152}
1153
1154
Lee Thomasonce0763e2012-01-11 15:43:54 -08001155XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001156{
Lee Thomason3f57d272012-01-11 15:30:03 -08001157}
1158
1159
kezenator4f756162016-11-29 19:46:27 +10001160char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason3f57d272012-01-11 15:30:03 -08001161{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001162 // Comment parses as text.
1163 const char* start = p;
kezenator4f756162016-11-29 19:46:27 +10001164 p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001165 if ( p == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10001166 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001167 }
1168 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001169}
1170
1171
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001172XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1173{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001174 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001175 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001176 }
1177 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1178 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001179}
1180
1181
1182bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1183{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001184 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001185 const XMLComment* comment = compare->ToComment();
1186 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001187}
1188
1189
Lee Thomason751da522012-02-10 08:50:51 -08001190bool XMLComment::Accept( XMLVisitor* visitor ) const
1191{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001192 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001193 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001194}
Lee Thomason56bdd022012-02-09 18:16:58 -08001195
1196
Lee Thomason50f97b22012-02-11 16:33:40 -08001197// --------- XMLDeclaration ---------- //
1198
1199XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1200{
1201}
1202
1203
1204XMLDeclaration::~XMLDeclaration()
1205{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001206 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001207}
1208
1209
kezenator4f756162016-11-29 19:46:27 +10001210char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001211{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001212 // Declaration parses as text.
1213 const char* start = p;
kezenator4f756162016-11-29 19:46:27 +10001214 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001215 if ( p == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10001216 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001217 }
1218 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001219}
1220
1221
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001222XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1223{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001224 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001225 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001226 }
1227 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1228 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001229}
1230
1231
1232bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1233{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001234 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001235 const XMLDeclaration* declaration = compare->ToDeclaration();
1236 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001237}
1238
1239
1240
Lee Thomason50f97b22012-02-11 16:33:40 -08001241bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1242{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001243 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001244 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001245}
1246
1247// --------- XMLUnknown ---------- //
1248
1249XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1250{
1251}
1252
1253
1254XMLUnknown::~XMLUnknown()
1255{
1256}
1257
1258
kezenator4f756162016-11-29 19:46:27 +10001259char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001260{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001261 // Unknown parses as text.
1262 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001263
kezenator4f756162016-11-29 19:46:27 +10001264 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001265 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001266 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001267 }
1268 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001269}
1270
1271
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001272XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1273{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001274 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001275 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001276 }
1277 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1278 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001279}
1280
1281
1282bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1283{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001284 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001285 const XMLUnknown* unknown = compare->ToUnknown();
1286 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001287}
1288
1289
Lee Thomason50f97b22012-02-11 16:33:40 -08001290bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1291{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001292 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001293 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001294}
1295
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001296// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001297
1298const char* XMLAttribute::Name() const
1299{
1300 return _name.GetStr();
1301}
1302
1303const char* XMLAttribute::Value() const
1304{
1305 return _value.GetStr();
1306}
1307
kezenator4f756162016-11-29 19:46:27 +10001308char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001309{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001310 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001311 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001312 if ( !p || !*p ) {
1313 return 0;
1314 }
Lee Thomason22aead12012-01-23 13:29:35 -08001315
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001316 // Skip white space before =
kezenator4f756162016-11-29 19:46:27 +10001317 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001318 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001319 return 0;
1320 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001321
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001322 ++p; // move up to opening quote
kezenator4f756162016-11-29 19:46:27 +10001323 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001324 if ( *p != '\"' && *p != '\'' ) {
1325 return 0;
1326 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001327
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001328 char endTag[2] = { *p, 0 };
1329 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001330
kezenator4f756162016-11-29 19:46:27 +10001331 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001332 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001333}
1334
1335
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001336void XMLAttribute::SetName( const char* n )
1337{
Lee Thomason624d43f2012-10-12 10:58:48 -07001338 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001339}
1340
1341
Lee Thomason2fa81722012-11-09 12:37:46 -08001342XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001343{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001344 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001345 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001346 }
1347 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001348}
1349
1350
Lee Thomason2fa81722012-11-09 12:37:46 -08001351XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001352{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001353 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001354 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001355 }
1356 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001357}
1358
1359
Lee Thomason51c12712016-06-04 20:18:49 -07001360XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1361{
1362 if (XMLUtil::ToInt64(Value(), value)) {
1363 return XML_SUCCESS;
1364 }
1365 return XML_WRONG_ATTRIBUTE_TYPE;
1366}
1367
1368
Lee Thomason2fa81722012-11-09 12:37:46 -08001369XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001370{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001371 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001372 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001373 }
1374 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001375}
1376
1377
Lee Thomason2fa81722012-11-09 12:37:46 -08001378XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001379{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001380 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001381 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001382 }
1383 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001384}
1385
1386
Lee Thomason2fa81722012-11-09 12:37:46 -08001387XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001388{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001389 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001390 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001391 }
1392 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001393}
1394
1395
1396void XMLAttribute::SetAttribute( const char* v )
1397{
Lee Thomason624d43f2012-10-12 10:58:48 -07001398 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001399}
1400
1401
Lee Thomason1ff38e02012-02-14 18:18:16 -08001402void XMLAttribute::SetAttribute( int v )
1403{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001404 char buf[BUF_SIZE];
1405 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001406 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001407}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001408
1409
1410void XMLAttribute::SetAttribute( unsigned v )
1411{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001412 char buf[BUF_SIZE];
1413 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001414 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001415}
1416
1417
Lee Thomason51c12712016-06-04 20:18:49 -07001418void XMLAttribute::SetAttribute(int64_t v)
1419{
1420 char buf[BUF_SIZE];
1421 XMLUtil::ToStr(v, buf, BUF_SIZE);
1422 _value.SetStr(buf);
1423}
1424
1425
1426
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001427void XMLAttribute::SetAttribute( bool v )
1428{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001429 char buf[BUF_SIZE];
1430 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001431 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001432}
1433
1434void XMLAttribute::SetAttribute( double v )
1435{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001436 char buf[BUF_SIZE];
1437 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001438 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001439}
1440
1441void XMLAttribute::SetAttribute( float v )
1442{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001443 char buf[BUF_SIZE];
1444 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001445 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001446}
1447
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001448
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001449// --------- XMLElement ---------- //
1450XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001451 _closingType( 0 ),
1452 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001453{
1454}
1455
1456
1457XMLElement::~XMLElement()
1458{
Lee Thomason624d43f2012-10-12 10:58:48 -07001459 while( _rootAttribute ) {
1460 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001461 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001462 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001463 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001464}
1465
1466
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001467const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1468{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001469 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001470 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1471 return a;
1472 }
1473 }
1474 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001475}
1476
1477
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001478const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001479{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001480 const XMLAttribute* a = FindAttribute( name );
1481 if ( !a ) {
1482 return 0;
1483 }
1484 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1485 return a->Value();
1486 }
1487 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001488}
1489
Josh Wittnercf3dd092016-10-11 18:57:17 -07001490int XMLElement::IntAttribute(const char* name, int defaultValue) const
1491{
1492 int i = defaultValue;
1493 QueryIntAttribute(name, &i);
1494 return i;
1495}
1496
1497unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
1498{
1499 unsigned i = defaultValue;
1500 QueryUnsignedAttribute(name, &i);
1501 return i;
1502}
1503
1504int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
1505{
1506 int64_t i = defaultValue;
1507 QueryInt64Attribute(name, &i);
1508 return i;
1509}
1510
1511bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
1512{
1513 bool b = defaultValue;
1514 QueryBoolAttribute(name, &b);
1515 return b;
1516}
1517
1518double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
1519{
1520 double d = defaultValue;
1521 QueryDoubleAttribute(name, &d);
1522 return d;
1523}
1524
1525float XMLElement::FloatAttribute(const char* name, float defaultValue) const
1526{
1527 float f = defaultValue;
1528 QueryFloatAttribute(name, &f);
1529 return f;
1530}
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001531
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001532const char* XMLElement::GetText() const
1533{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001534 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001535 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001536 }
1537 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001538}
1539
1540
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001541void XMLElement::SetText( const char* inText )
1542{
Uli Kusterer869bb592014-01-21 01:36:16 +01001543 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001544 FirstChild()->SetValue( inText );
1545 else {
1546 XMLText* theText = GetDocument()->NewText( inText );
1547 InsertFirstChild( theText );
1548 }
1549}
1550
Lee Thomason5bb2d802014-01-24 10:42:57 -08001551
1552void XMLElement::SetText( int v )
1553{
1554 char buf[BUF_SIZE];
1555 XMLUtil::ToStr( v, buf, BUF_SIZE );
1556 SetText( buf );
1557}
1558
1559
1560void XMLElement::SetText( unsigned v )
1561{
1562 char buf[BUF_SIZE];
1563 XMLUtil::ToStr( v, buf, BUF_SIZE );
1564 SetText( buf );
1565}
1566
1567
Lee Thomason51c12712016-06-04 20:18:49 -07001568void XMLElement::SetText(int64_t v)
1569{
1570 char buf[BUF_SIZE];
1571 XMLUtil::ToStr(v, buf, BUF_SIZE);
1572 SetText(buf);
1573}
1574
1575
1576void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001577{
1578 char buf[BUF_SIZE];
1579 XMLUtil::ToStr( v, buf, BUF_SIZE );
1580 SetText( buf );
1581}
1582
1583
1584void XMLElement::SetText( float v )
1585{
1586 char buf[BUF_SIZE];
1587 XMLUtil::ToStr( v, buf, BUF_SIZE );
1588 SetText( buf );
1589}
1590
1591
1592void XMLElement::SetText( double v )
1593{
1594 char buf[BUF_SIZE];
1595 XMLUtil::ToStr( v, buf, BUF_SIZE );
1596 SetText( buf );
1597}
1598
1599
MortenMacFly4ee49f12013-01-14 20:03:14 +01001600XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001601{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001602 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001603 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001604 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001605 return XML_SUCCESS;
1606 }
1607 return XML_CAN_NOT_CONVERT_TEXT;
1608 }
1609 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001610}
1611
1612
MortenMacFly4ee49f12013-01-14 20:03:14 +01001613XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001614{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001615 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001616 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001617 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001618 return XML_SUCCESS;
1619 }
1620 return XML_CAN_NOT_CONVERT_TEXT;
1621 }
1622 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001623}
1624
1625
Lee Thomason51c12712016-06-04 20:18:49 -07001626XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1627{
1628 if (FirstChild() && FirstChild()->ToText()) {
1629 const char* t = FirstChild()->Value();
1630 if (XMLUtil::ToInt64(t, ival)) {
1631 return XML_SUCCESS;
1632 }
1633 return XML_CAN_NOT_CONVERT_TEXT;
1634 }
1635 return XML_NO_TEXT_NODE;
1636}
1637
1638
MortenMacFly4ee49f12013-01-14 20:03:14 +01001639XMLError XMLElement::QueryBoolText( bool* bval ) 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::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001644 return XML_SUCCESS;
1645 }
1646 return XML_CAN_NOT_CONVERT_TEXT;
1647 }
1648 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001649}
1650
1651
MortenMacFly4ee49f12013-01-14 20:03:14 +01001652XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001653{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001654 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001655 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001656 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001657 return XML_SUCCESS;
1658 }
1659 return XML_CAN_NOT_CONVERT_TEXT;
1660 }
1661 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001662}
1663
1664
MortenMacFly4ee49f12013-01-14 20:03:14 +01001665XMLError XMLElement::QueryFloatText( float* fval ) 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::ToFloat( t, fval ) ) {
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
Josh Wittnercf3dd092016-10-11 18:57:17 -07001677int XMLElement::IntText(int defaultValue) const
1678{
1679 int i = defaultValue;
1680 QueryIntText(&i);
1681 return i;
1682}
1683
1684unsigned XMLElement::UnsignedText(unsigned defaultValue) const
1685{
1686 unsigned i = defaultValue;
1687 QueryUnsignedText(&i);
1688 return i;
1689}
1690
1691int64_t XMLElement::Int64Text(int64_t defaultValue) const
1692{
1693 int64_t i = defaultValue;
1694 QueryInt64Text(&i);
1695 return i;
1696}
1697
1698bool XMLElement::BoolText(bool defaultValue) const
1699{
1700 bool b = defaultValue;
1701 QueryBoolText(&b);
1702 return b;
1703}
1704
1705double XMLElement::DoubleText(double defaultValue) const
1706{
1707 double d = defaultValue;
1708 QueryDoubleText(&d);
1709 return d;
1710}
1711
1712float XMLElement::FloatText(float defaultValue) const
1713{
1714 float f = defaultValue;
1715 QueryFloatText(&f);
1716 return f;
1717}
Lee Thomason21be8822012-07-15 17:27:22 -07001718
1719
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001720XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1721{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001722 XMLAttribute* last = 0;
1723 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001724 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001725 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001726 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001727 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1728 break;
1729 }
1730 }
1731 if ( !attrib ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001732 attrib = CreateAttribute();
1733 TIXMLASSERT( attrib );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001734 if ( last ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001735 TIXMLASSERT( last->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001736 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001737 }
1738 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001739 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001740 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001741 }
1742 attrib->SetName( name );
1743 }
1744 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001745}
1746
1747
U-Stream\Leeae25a442012-02-17 17:48:16 -08001748void XMLElement::DeleteAttribute( const char* name )
1749{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001750 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001751 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001752 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1753 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001754 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001755 }
1756 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001757 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001758 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001759 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001760 break;
1761 }
1762 prev = a;
1763 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001764}
1765
1766
kezenator4f756162016-11-29 19:46:27 +10001767char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001768{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001769 const char* start = p;
1770 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001771
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001772 // Read the attributes.
1773 while( p ) {
kezenator4f756162016-11-29 19:46:27 +10001774 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001775 if ( !(*p) ) {
kezenatorec694152016-11-26 17:21:43 +10001776 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name(), _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001777 return 0;
1778 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001779
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001780 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001781 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001782 XMLAttribute* attrib = CreateAttribute();
1783 TIXMLASSERT( attrib );
kezenatorec694152016-11-26 17:21:43 +10001784 attrib->_parseLineNum = _document->_parseCurLineNum;
Lee Thomasond1983222012-02-06 08:41:24 -08001785
kezenatorec694152016-11-26 17:21:43 +10001786 int attrLineNum = attrib->_parseLineNum;
1787
kezenator4f756162016-11-29 19:46:27 +10001788 p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001789 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001790 DeleteAttribute( attrib );
kezenatorec694152016-11-26 17:21:43 +10001791 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p, attrLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001792 return 0;
1793 }
1794 // There is a minor bug here: if the attribute in the source xml
1795 // document is duplicated, it will not be detected and the
1796 // attribute will be doubly added. However, tracking the 'prevAttribute'
1797 // avoids re-scanning the attribute list. Preferring performance for
1798 // now, may reconsider in the future.
1799 if ( prevAttribute ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001800 TIXMLASSERT( prevAttribute->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001801 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001802 }
1803 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001804 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001805 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001806 }
1807 prevAttribute = attrib;
1808 }
1809 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001810 else if ( *p == '>' ) {
1811 ++p;
1812 break;
1813 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001814 // end of the tag
1815 else if ( *p == '/' && *(p+1) == '>' ) {
1816 _closingType = CLOSED;
1817 return p+2; // done; sealed element.
1818 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001819 else {
kezenatorec694152016-11-26 17:21:43 +10001820 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001821 return 0;
1822 }
1823 }
1824 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001825}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001826
Dmitry-Mee3225b12014-09-03 11:03:11 +04001827void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1828{
1829 if ( attribute == 0 ) {
1830 return;
1831 }
1832 MemPool* pool = attribute->_memPool;
1833 attribute->~XMLAttribute();
1834 pool->Free( attribute );
1835}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001836
Dmitry-Mea60caa22016-11-22 18:28:08 +03001837XMLAttribute* XMLElement::CreateAttribute()
1838{
1839 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
1840 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1841 attrib->_memPool = &_document->_attributePool;
1842 attrib->_memPool->SetTracked();
1843 return attrib;
1844}
1845
Lee Thomason67d61312012-01-24 16:01:51 -08001846//
1847// <ele></ele>
1848// <ele>foo<b>bar</b></ele>
1849//
kezenator4f756162016-11-29 19:46:27 +10001850char* XMLElement::ParseDeep( char* p, StrPair* strPair, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -08001851{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001852 // Read the element name.
kezenator4f756162016-11-29 19:46:27 +10001853 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomason67d61312012-01-24 16:01:51 -08001854
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001855 // The closing element is the </element> form. It is
1856 // parsed just like a regular element then deleted from
1857 // the DOM.
1858 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001859 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001860 ++p;
1861 }
Lee Thomason67d61312012-01-24 16:01:51 -08001862
Lee Thomason624d43f2012-10-12 10:58:48 -07001863 p = _value.ParseName( p );
1864 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001865 return 0;
1866 }
Lee Thomason67d61312012-01-24 16:01:51 -08001867
kezenator4f756162016-11-29 19:46:27 +10001868 p = ParseAttributes( p, curLineNumPtr );
Lee Thomason624d43f2012-10-12 10:58:48 -07001869 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001870 return p;
1871 }
Lee Thomason67d61312012-01-24 16:01:51 -08001872
kezenator4f756162016-11-29 19:46:27 +10001873 p = XMLNode::ParseDeep( p, strPair, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001874 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001875}
1876
1877
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001878
1879XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1880{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001881 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001882 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001883 }
1884 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1885 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1886 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1887 }
1888 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001889}
1890
1891
1892bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1893{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001894 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001895 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001896 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001897
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001898 const XMLAttribute* a=FirstAttribute();
1899 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001900
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001901 while ( a && b ) {
1902 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1903 return false;
1904 }
1905 a = a->Next();
1906 b = b->Next();
1907 }
1908 if ( a || b ) {
1909 // different count
1910 return false;
1911 }
1912 return true;
1913 }
1914 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001915}
1916
1917
Lee Thomason751da522012-02-10 08:50:51 -08001918bool XMLElement::Accept( XMLVisitor* visitor ) const
1919{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001920 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001921 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001922 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1923 if ( !node->Accept( visitor ) ) {
1924 break;
1925 }
1926 }
1927 }
1928 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001929}
Lee Thomason56bdd022012-02-09 18:16:58 -08001930
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001931
Lee Thomason3f57d272012-01-11 15:30:03 -08001932// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001933
1934// Warning: List must match 'enum XMLError'
1935const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1936 "XML_SUCCESS",
1937 "XML_NO_ATTRIBUTE",
1938 "XML_WRONG_ATTRIBUTE_TYPE",
1939 "XML_ERROR_FILE_NOT_FOUND",
1940 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1941 "XML_ERROR_FILE_READ_ERROR",
1942 "XML_ERROR_ELEMENT_MISMATCH",
1943 "XML_ERROR_PARSING_ELEMENT",
1944 "XML_ERROR_PARSING_ATTRIBUTE",
1945 "XML_ERROR_IDENTIFYING_TAG",
1946 "XML_ERROR_PARSING_TEXT",
1947 "XML_ERROR_PARSING_CDATA",
1948 "XML_ERROR_PARSING_COMMENT",
1949 "XML_ERROR_PARSING_DECLARATION",
1950 "XML_ERROR_PARSING_UNKNOWN",
1951 "XML_ERROR_EMPTY_DOCUMENT",
1952 "XML_ERROR_MISMATCHED_ELEMENT",
1953 "XML_ERROR_PARSING",
1954 "XML_CAN_NOT_CONVERT_TEXT",
1955 "XML_NO_TEXT_NODE"
1956};
1957
1958
Dmitry-Meae8a82a2017-03-03 15:40:32 +03001959XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001960 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001961 _writeBOM( false ),
1962 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07001963 _errorID(XML_SUCCESS),
Dmitry-Meae8a82a2017-03-03 15:40:32 +03001964 _whitespaceMode( whitespaceMode ),
Dmitry-Mef89bd3e2017-01-18 18:33:55 +03001965 _errorLineNum( 0 ),
1966 _charBuffer( 0 ),
1967 _parseCurLineNum( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001968{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03001969 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
1970 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08001971}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001972
1973
Lee Thomason3f57d272012-01-11 15:30:03 -08001974XMLDocument::~XMLDocument()
1975{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001976 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001977}
1978
1979
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001980void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001981{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001982 DeleteChildren();
1983
Dmitry-Meab37df82014-11-28 12:08:36 +03001984#ifdef DEBUG
1985 const bool hadError = Error();
1986#endif
Dmitry-Me0d2cef02016-11-25 18:39:52 +03001987 ClearError();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001988
Lee Thomason624d43f2012-10-12 10:58:48 -07001989 delete [] _charBuffer;
1990 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001991
1992#if 0
1993 _textPool.Trace( "text" );
1994 _elementPool.Trace( "element" );
1995 _commentPool.Trace( "comment" );
1996 _attributePool.Trace( "attribute" );
1997#endif
1998
1999#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002000 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002001 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
2002 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
2003 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
2004 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
2005 }
2006#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08002007}
2008
Lee Thomason3f57d272012-01-11 15:30:03 -08002009
Lee Thomason2c85a712012-01-31 08:24:24 -08002010XMLElement* XMLDocument::NewElement( const char* name )
2011{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002012 XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002013 ele->SetName( name );
2014 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08002015}
2016
2017
Lee Thomason1ff38e02012-02-14 18:18:16 -08002018XMLComment* XMLDocument::NewComment( const char* str )
2019{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002020 XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002021 comment->SetValue( str );
2022 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002023}
2024
2025
2026XMLText* XMLDocument::NewText( const char* str )
2027{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002028 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002029 text->SetValue( str );
2030 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002031}
2032
2033
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002034XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2035{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002036 XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002037 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2038 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002039}
2040
2041
2042XMLUnknown* XMLDocument::NewUnknown( const char* str )
2043{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002044 XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002045 unk->SetValue( str );
2046 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002047}
2048
Dmitry-Me01578db2014-08-19 10:18:48 +04002049static FILE* callfopen( const char* filepath, const char* mode )
2050{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002051 TIXMLASSERT( filepath );
2052 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002053#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2054 FILE* fp = 0;
2055 errno_t err = fopen_s( &fp, filepath, mode );
2056 if ( err ) {
2057 return 0;
2058 }
2059#else
2060 FILE* fp = fopen( filepath, mode );
2061#endif
2062 return fp;
2063}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08002064
2065void XMLDocument::DeleteNode( XMLNode* node ) {
2066 TIXMLASSERT( node );
2067 TIXMLASSERT(node->_document == this );
2068 if (node->_parent) {
2069 node->_parent->DeleteChild( node );
2070 }
2071 else {
2072 // Isn't in the tree.
2073 // Use the parent delete.
2074 // Also, we need to mark it tracked: we 'know'
2075 // it was never used.
2076 node->_memPool->SetTracked();
2077 // Call the static XMLNode version:
2078 XMLNode::DeleteNode(node);
2079 }
2080}
2081
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002082
Lee Thomason2fa81722012-11-09 12:37:46 -08002083XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002084{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002085 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04002086 FILE* fp = callfopen( filename, "rb" );
2087 if ( !fp ) {
kezenatorec694152016-11-26 17:21:43 +10002088 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002089 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002090 }
2091 LoadFile( fp );
2092 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002093 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002094}
2095
Dmitry-Me901fed52015-09-25 10:29:51 +03002096// This is likely overengineered template art to have a check that unsigned long value incremented
2097// by one still fits into size_t. If size_t type is larger than unsigned long type
2098// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
2099// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
2100// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
2101// types sizes relate to each other.
2102template
2103<bool = (sizeof(unsigned long) >= sizeof(size_t))>
2104struct LongFitsIntoSizeTMinusOne {
2105 static bool Fits( unsigned long value )
2106 {
2107 return value < (size_t)-1;
2108 }
2109};
2110
2111template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02002112struct LongFitsIntoSizeTMinusOne<false> {
2113 static bool Fits( unsigned long )
2114 {
2115 return true;
2116 }
2117};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002118
Lee Thomason2fa81722012-11-09 12:37:46 -08002119XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002120{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002121 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002122
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002123 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002124 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
kezenatorec694152016-11-26 17:21:43 +10002125 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002126 return _errorID;
2127 }
2128
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002129 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002130 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002131 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002132 if ( filelength == -1L ) {
kezenatorec694152016-11-26 17:21:43 +10002133 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002134 return _errorID;
2135 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002136 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002137
Dmitry-Me901fed52015-09-25 10:29:51 +03002138 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002139 // Cannot handle files which won't fit in buffer together with null terminator
kezenatorec694152016-11-26 17:21:43 +10002140 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002141 return _errorID;
2142 }
2143
Dmitry-Me72801b82015-05-07 09:41:39 +03002144 if ( filelength == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10002145 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002146 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002147 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002148
Dmitry-Me72801b82015-05-07 09:41:39 +03002149 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002150 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002151 _charBuffer = new char[size+1];
2152 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002153 if ( read != size ) {
kezenatorec694152016-11-26 17:21:43 +10002154 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002155 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002156 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002157
Lee Thomason624d43f2012-10-12 10:58:48 -07002158 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002159
Dmitry-Me97476b72015-01-01 16:15:57 +03002160 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002161 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002162}
2163
2164
Lee Thomason2fa81722012-11-09 12:37:46 -08002165XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002166{
Dmitry-Me01578db2014-08-19 10:18:48 +04002167 FILE* fp = callfopen( filename, "w" );
2168 if ( !fp ) {
kezenatorec694152016-11-26 17:21:43 +10002169 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002170 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002171 }
2172 SaveFile(fp, compact);
2173 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002174 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002175}
2176
2177
Lee Thomason2fa81722012-11-09 12:37:46 -08002178XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002179{
Ant Mitchell189198f2015-03-24 16:20:36 +00002180 // Clear any error from the last save, otherwise it will get reported
2181 // for *this* call.
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002182 ClearError();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002183 XMLPrinter stream( fp, compact );
2184 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002185 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002186}
2187
Lee Thomason1ff38e02012-02-14 18:18:16 -08002188
Lee Thomason2fa81722012-11-09 12:37:46 -08002189XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002190{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002191 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002192
Lee Thomason82d32002014-02-21 22:47:18 -08002193 if ( len == 0 || !p || !*p ) {
kezenatorec694152016-11-26 17:21:43 +10002194 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002195 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002196 }
2197 if ( len == (size_t)(-1) ) {
2198 len = strlen( p );
2199 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002200 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002201 _charBuffer = new char[ len+1 ];
2202 memcpy( _charBuffer, p, len );
2203 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002204
Dmitry-Me97476b72015-01-01 16:15:57 +03002205 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002206 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002207 // clean up now essentially dangling memory.
2208 // and the parse fail can put objects in the
2209 // pools that are dead and inaccessible.
2210 DeleteChildren();
2211 _elementPool.Clear();
2212 _attributePool.Clear();
2213 _textPool.Clear();
2214 _commentPool.Clear();
2215 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002216 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002217}
2218
2219
PKEuS1c5f99e2013-07-06 11:28:39 +02002220void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002221{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002222 if ( streamer ) {
2223 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002224 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002225 else {
2226 XMLPrinter stdoutStreamer( stdout );
2227 Accept( &stdoutStreamer );
2228 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002229}
2230
2231
kezenatorec694152016-11-26 17:21:43 +10002232void XMLDocument::SetError( XMLError error, const char* str1, const char* str2, int lineNum )
Lee Thomason67d61312012-01-24 16:01:51 -08002233{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002234 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002235 _errorID = error;
Lee Thomason584af572016-09-05 14:14:16 -07002236
2237 _errorStr1.Reset();
2238 _errorStr2.Reset();
kezenatorec694152016-11-26 17:21:43 +10002239 _errorLineNum = lineNum;
Lee Thomason584af572016-09-05 14:14:16 -07002240
2241 if (str1)
2242 _errorStr1.SetStr(str1);
2243 if (str2)
2244 _errorStr2.SetStr(str2);
Lee Thomason67d61312012-01-24 16:01:51 -08002245}
2246
Lee Thomasone90e9012016-12-24 07:34:39 -08002247/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
Lee Thomason331596e2014-09-11 14:56:43 -07002248{
kezenator5a700712016-11-26 13:54:42 +10002249 TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2250 const char* errorName = _errorNames[errorID];
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002251 TIXMLASSERT( errorName && errorName[0] );
2252 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002253}
Lee Thomason5cae8972012-01-24 18:03:07 -08002254
kezenator5a700712016-11-26 13:54:42 +10002255const char* XMLDocument::ErrorName() const
2256{
Lee Thomasone90e9012016-12-24 07:34:39 -08002257 return ErrorIDToName(_errorID);
kezenator5a700712016-11-26 13:54:42 +10002258}
2259
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002260void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002261{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002262 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002263 static const int LEN = 20;
2264 char buf1[LEN] = { 0 };
2265 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002266
Lee Thomason584af572016-09-05 14:14:16 -07002267 if ( !_errorStr1.Empty() ) {
2268 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002269 }
Lee Thomason584af572016-09-05 14:14:16 -07002270 if ( !_errorStr2.Empty() ) {
2271 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002272 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002273
Dmitry-Me2ad43202015-04-16 12:18:58 +03002274 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2275 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2276 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
kezenatorec694152016-11-26 17:21:43 +10002277 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s line=%d\n",
2278 static_cast<int>( _errorID ), ErrorName(), buf1, buf2, _errorLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002279 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002280}
2281
Dmitry-Me97476b72015-01-01 16:15:57 +03002282void XMLDocument::Parse()
2283{
2284 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2285 TIXMLASSERT( _charBuffer );
kezenatorec694152016-11-26 17:21:43 +10002286 _parseCurLineNum = 1;
2287 _parseLineNum = 1;
Lee Thomason3cebdc42015-01-05 17:16:28 -08002288 char* p = _charBuffer;
kezenator4f756162016-11-29 19:46:27 +10002289 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mee28be752015-01-09 14:59:30 +03002290 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002291 if ( !*p ) {
kezenatorec694152016-11-26 17:21:43 +10002292 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002293 return;
2294 }
kezenator4f756162016-11-29 19:46:27 +10002295 ParseDeep(p, 0, &_parseCurLineNum );
Dmitry-Me97476b72015-01-01 16:15:57 +03002296}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002297
PKEuS1bfb9542013-08-04 13:51:17 +02002298XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002299 _elementJustOpened( false ),
2300 _firstElement( true ),
2301 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002302 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002303 _textDepth( -1 ),
2304 _processEntities( true ),
2305 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002306{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002307 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002308 _entityFlag[i] = false;
2309 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002310 }
2311 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002312 const char entityValue = entities[i].value;
Dmitry-Mec5f1e7c2016-10-14 10:33:02 +03002313 TIXMLASSERT( ((unsigned char)entityValue) < ENTITY_RANGE );
Dmitry-Me8b67d742014-12-22 11:35:12 +03002314 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002315 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002316 _restrictedEntityFlag[(unsigned char)'&'] = true;
2317 _restrictedEntityFlag[(unsigned char)'<'] = true;
2318 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002319 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002320}
2321
2322
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002323void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002324{
2325 va_list va;
2326 va_start( va, format );
2327
Lee Thomason624d43f2012-10-12 10:58:48 -07002328 if ( _fp ) {
2329 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002330 }
2331 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002332 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002333 // Close out and re-start the va-args
2334 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002335 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002336 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002337 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002338 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002339 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002340 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002341 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002342}
2343
2344
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002345void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002346{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002347 for( int i=0; i<depth; ++i ) {
2348 Print( " " );
2349 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002350}
2351
2352
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002353void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002354{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002355 // Look for runs of bytes between entities to print.
2356 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002357
Lee Thomason624d43f2012-10-12 10:58:48 -07002358 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002359 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002360 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002361 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002362 // Remember, char is sometimes signed. (How many times has that bitten me?)
2363 if ( *q > 0 && *q < ENTITY_RANGE ) {
2364 // Check for entities. If one is found, flush
2365 // the stream up until the entity, write the
2366 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002367 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002368 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002369 const size_t delta = q - p;
2370 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002371 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002372 Print( "%.*s", toPrint, p );
2373 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002374 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002375 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002376 for( int i=0; i<NUM_ENTITIES; ++i ) {
2377 if ( entities[i].value == *q ) {
2378 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002379 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002380 break;
2381 }
2382 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002383 if ( !entityPatternPrinted ) {
2384 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2385 TIXMLASSERT( false );
2386 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002387 ++p;
2388 }
2389 }
2390 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002391 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002392 }
2393 }
2394 // Flush the remaining string. This will be the entire
2395 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002396 TIXMLASSERT( p <= q );
2397 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002398 Print( "%s", p );
2399 }
Lee Thomason857b8682012-01-25 17:50:25 -08002400}
2401
U-Stream\Leeae25a442012-02-17 17:48:16 -08002402
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002403void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002404{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002405 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002406 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 -07002407 Print( "%s", bom );
2408 }
2409 if ( writeDec ) {
2410 PushDeclaration( "xml version=\"1.0\"" );
2411 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002412}
2413
2414
Uli Kusterer593a33d2014-02-01 12:48:51 +01002415void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002416{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002417 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002418 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002419
Uli Kusterer593a33d2014-02-01 12:48:51 +01002420 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002421 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002422 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002423 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002424 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002425 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002426
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002427 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002428 _elementJustOpened = true;
2429 _firstElement = false;
2430 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002431}
2432
2433
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002434void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002435{
Lee Thomason624d43f2012-10-12 10:58:48 -07002436 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002437 Print( " %s=\"", name );
2438 PrintString( value, false );
2439 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002440}
2441
2442
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002443void XMLPrinter::PushAttribute( const char* name, int v )
2444{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002445 char buf[BUF_SIZE];
2446 XMLUtil::ToStr( v, buf, BUF_SIZE );
2447 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002448}
2449
2450
2451void XMLPrinter::PushAttribute( const char* name, unsigned v )
2452{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002453 char buf[BUF_SIZE];
2454 XMLUtil::ToStr( v, buf, BUF_SIZE );
2455 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002456}
2457
2458
Lee Thomason51c12712016-06-04 20:18:49 -07002459void XMLPrinter::PushAttribute(const char* name, int64_t v)
2460{
2461 char buf[BUF_SIZE];
2462 XMLUtil::ToStr(v, buf, BUF_SIZE);
2463 PushAttribute(name, buf);
2464}
2465
2466
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002467void XMLPrinter::PushAttribute( const char* name, bool v )
2468{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002469 char buf[BUF_SIZE];
2470 XMLUtil::ToStr( v, buf, BUF_SIZE );
2471 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002472}
2473
2474
2475void XMLPrinter::PushAttribute( const char* name, double v )
2476{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002477 char buf[BUF_SIZE];
2478 XMLUtil::ToStr( v, buf, BUF_SIZE );
2479 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002480}
2481
2482
Uli Kustererca412e82014-02-01 13:35:05 +01002483void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002484{
Lee Thomason624d43f2012-10-12 10:58:48 -07002485 --_depth;
2486 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002487
Lee Thomason624d43f2012-10-12 10:58:48 -07002488 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002489 Print( "/>" );
2490 }
2491 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002492 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002493 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002494 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002495 }
2496 Print( "</%s>", name );
2497 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002498
Lee Thomason624d43f2012-10-12 10:58:48 -07002499 if ( _textDepth == _depth ) {
2500 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002501 }
Uli Kustererca412e82014-02-01 13:35:05 +01002502 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002503 Print( "\n" );
2504 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002505 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002506}
2507
2508
Dmitry-Mea092bc12014-12-23 17:57:05 +03002509void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002510{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002511 if ( !_elementJustOpened ) {
2512 return;
2513 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002514 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002515 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002516}
2517
2518
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002519void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002520{
Lee Thomason624d43f2012-10-12 10:58:48 -07002521 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002522
Dmitry-Mea092bc12014-12-23 17:57:05 +03002523 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002524 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002525 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002526 }
2527 else {
2528 PrintString( text, true );
2529 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002530}
2531
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002532void XMLPrinter::PushText( int64_t value )
2533{
2534 char buf[BUF_SIZE];
2535 XMLUtil::ToStr( value, buf, BUF_SIZE );
2536 PushText( buf, false );
2537}
2538
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002539void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002540{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002541 char buf[BUF_SIZE];
2542 XMLUtil::ToStr( value, buf, BUF_SIZE );
2543 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002544}
2545
2546
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002547void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002548{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002549 char buf[BUF_SIZE];
2550 XMLUtil::ToStr( value, buf, BUF_SIZE );
2551 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002552}
2553
2554
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002555void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002556{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002557 char buf[BUF_SIZE];
2558 XMLUtil::ToStr( value, buf, BUF_SIZE );
2559 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002560}
2561
2562
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002563void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002564{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002565 char buf[BUF_SIZE];
2566 XMLUtil::ToStr( value, buf, BUF_SIZE );
2567 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002568}
2569
2570
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002571void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002572{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002573 char buf[BUF_SIZE];
2574 XMLUtil::ToStr( value, buf, BUF_SIZE );
2575 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002576}
2577
Lee Thomason5cae8972012-01-24 18:03:07 -08002578
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002579void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002580{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002581 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002582 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002583 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002584 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002585 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002586 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002587 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002588}
Lee Thomason751da522012-02-10 08:50:51 -08002589
2590
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002591void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002592{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002593 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002594 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002595 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002596 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002597 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002598 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002599 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002600}
2601
2602
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002603void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002604{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002605 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002606 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002607 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002608 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002609 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002610 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002611 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002612}
2613
2614
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002615bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002616{
Lee Thomason624d43f2012-10-12 10:58:48 -07002617 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002618 if ( doc.HasBOM() ) {
2619 PushHeader( true, false );
2620 }
2621 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002622}
2623
2624
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002625bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002626{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002627 const XMLElement* parentElem = 0;
2628 if ( element.Parent() ) {
2629 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002630 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002631 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002632 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002633 while ( attribute ) {
2634 PushAttribute( attribute->Name(), attribute->Value() );
2635 attribute = attribute->Next();
2636 }
2637 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002638}
2639
2640
Uli Kustererca412e82014-02-01 13:35:05 +01002641bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002642{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002643 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002644 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002645}
2646
2647
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002648bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002649{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002650 PushText( text.Value(), text.CData() );
2651 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002652}
2653
2654
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002655bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002656{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002657 PushComment( comment.Value() );
2658 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002659}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002660
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002661bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002662{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002663 PushDeclaration( declaration.Value() );
2664 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002665}
2666
2667
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002668bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002669{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002670 PushUnknown( unknown.Value() );
2671 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002672}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002673
Lee Thomason685b8952012-11-12 13:00:06 -08002674} // namespace tinyxml2
2675