blob: 233243b6d5234bd062ec14c6f3a6da8a89490ef9 [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
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300427 // Scary scary fall throughs are annotated with carefully designed comments
428 // to suppress compiler warnings such as -Wimplicit-fallthrough in gcc
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700429 switch (*length) {
430 case 4:
431 --output;
432 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
433 input >>= 6;
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300434 //fall through
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700435 case 3:
436 --output;
437 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
438 input >>= 6;
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300439 //fall through
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700440 case 2:
441 --output;
442 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
443 input >>= 6;
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300444 //fall through
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700445 case 1:
446 --output;
447 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100448 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300449 default:
450 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700451 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800452}
453
454
455const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
456{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700457 // Presume an entity, and pull it out.
458 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800459
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700460 if ( *(p+1) == '#' && *(p+2) ) {
461 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300462 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700463 ptrdiff_t delta = 0;
464 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800465 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800466
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700467 if ( *(p+2) == 'x' ) {
468 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300469 const char* q = p+3;
470 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700471 return 0;
472 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800473
Lee Thomason7e67bc82015-01-12 14:05:12 -0800474 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800475
Dmitry-Me9f56e122015-01-12 10:07:54 +0300476 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700477 return 0;
478 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800479 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800480
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700481 delta = q-p;
482 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800483
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700484 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700485 unsigned int digit = 0;
486
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700487 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300488 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700489 }
490 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300491 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700492 }
493 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300494 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700495 }
496 else {
497 return 0;
498 }
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100499 TIXMLASSERT( digit < 16 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300500 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
501 const unsigned int digitScaled = mult * digit;
502 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
503 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300504 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700505 mult *= 16;
506 --q;
507 }
508 }
509 else {
510 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300511 const char* q = p+2;
512 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700513 return 0;
514 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800515
Lee Thomason7e67bc82015-01-12 14:05:12 -0800516 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800517
Dmitry-Me9f56e122015-01-12 10:07:54 +0300518 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700519 return 0;
520 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800521 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800522
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700523 delta = q-p;
524 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800525
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700526 while ( *q != '#' ) {
527 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300528 const unsigned int digit = *q - '0';
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100529 TIXMLASSERT( digit < 10 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300530 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
531 const unsigned int digitScaled = mult * digit;
532 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
533 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700534 }
535 else {
536 return 0;
537 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300538 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700539 mult *= 10;
540 --q;
541 }
542 }
543 // convert the UCS to UTF-8
544 ConvertUTF32ToUTF8( ucs, value, length );
545 return p + delta + 1;
546 }
547 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800548}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800549
550
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700551void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700552{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700553 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700554}
555
556
557void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
558{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700559 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700560}
561
562
563void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
564{
Lee Thomasonce667c92016-12-26 16:45:30 -0800565 TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? writeBoolTrue : writeBoolFalse);
Lee Thomason21be8822012-07-15 17:27:22 -0700566}
567
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800568/*
569 ToStr() of a number is a very tricky topic.
570 https://github.com/leethomason/tinyxml2/issues/106
571*/
Lee Thomason21be8822012-07-15 17:27:22 -0700572void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
573{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800574 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700575}
576
577
578void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
579{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800580 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700581}
582
583
Lee Thomason51c12712016-06-04 20:18:49 -0700584void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize)
585{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700586 // horrible syntax trick to make the compiler happy about %lld
587 TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v);
Lee Thomason51c12712016-06-04 20:18:49 -0700588}
589
590
Lee Thomason21be8822012-07-15 17:27:22 -0700591bool XMLUtil::ToInt( const char* str, int* value )
592{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700593 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
594 return true;
595 }
596 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700597}
598
599bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
600{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700601 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
602 return true;
603 }
604 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700605}
606
607bool XMLUtil::ToBool( const char* str, bool* value )
608{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700609 int ival = 0;
610 if ( ToInt( str, &ival )) {
611 *value = (ival==0) ? false : true;
612 return true;
613 }
614 if ( StringEqual( str, "true" ) ) {
615 *value = true;
616 return true;
617 }
618 else if ( StringEqual( str, "false" ) ) {
619 *value = false;
620 return true;
621 }
622 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700623}
624
625
626bool XMLUtil::ToFloat( const char* str, float* value )
627{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700628 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
629 return true;
630 }
631 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700632}
633
Lee Thomason51c12712016-06-04 20:18:49 -0700634
Lee Thomason21be8822012-07-15 17:27:22 -0700635bool XMLUtil::ToDouble( const char* str, double* value )
636{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700637 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
638 return true;
639 }
640 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700641}
642
643
Lee Thomason51c12712016-06-04 20:18:49 -0700644bool XMLUtil::ToInt64(const char* str, int64_t* value)
645{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700646 long long v = 0; // horrible syntax trick to make the compiler happy about %lld
647 if (TIXML_SSCANF(str, "%lld", &v) == 1) {
648 *value = (int64_t)v;
Lee Thomason51c12712016-06-04 20:18:49 -0700649 return true;
650 }
651 return false;
652}
653
654
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700655char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800656{
Dmitry-Me02384662015-03-03 16:02:13 +0300657 TIXMLASSERT( node );
658 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400659 char* const start = p;
kezenatorec694152016-11-26 17:21:43 +1000660 int const startLine = _parseCurLineNum;
kezenator4f756162016-11-29 19:46:27 +1000661 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300662 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300663 *node = 0;
664 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700665 return p;
666 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800667
Dmitry-Me962083b2015-05-26 11:38:30 +0300668 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700669 static const char* xmlHeader = { "<?" };
670 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700671 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300672 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700673 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800674
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700675 static const int xmlHeaderLen = 2;
676 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700677 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300678 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700679 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800680
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700681 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
682 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400683 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700684 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300685 returnNode = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000686 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700687 p += xmlHeaderLen;
688 }
689 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300690 returnNode = CreateUnlinkedNode<XMLComment>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000691 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700692 p += commentHeaderLen;
693 }
694 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300695 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700696 returnNode = text;
kezenatorec694152016-11-26 17:21:43 +1000697 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700698 p += cdataHeaderLen;
699 text->SetCData( true );
700 }
701 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300702 returnNode = CreateUnlinkedNode<XMLUnknown>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000703 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700704 p += dtdHeaderLen;
705 }
706 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300707 returnNode = CreateUnlinkedNode<XMLElement>( _elementPool );
kezenatorec694152016-11-26 17:21:43 +1000708 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700709 p += elementHeaderLen;
710 }
711 else {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300712 returnNode = CreateUnlinkedNode<XMLText>( _textPool );
kezenatorec694152016-11-26 17:21:43 +1000713 returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700714 p = start; // Back it up, all the text counts.
kezenatorec694152016-11-26 17:21:43 +1000715 _parseCurLineNum = startLine;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700716 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800717
Dmitry-Me02384662015-03-03 16:02:13 +0300718 TIXMLASSERT( returnNode );
719 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700720 *node = returnNode;
721 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800722}
723
724
Lee Thomason751da522012-02-10 08:50:51 -0800725bool XMLDocument::Accept( XMLVisitor* visitor ) const
726{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300727 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700728 if ( visitor->VisitEnter( *this ) ) {
729 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
730 if ( !node->Accept( visitor ) ) {
731 break;
732 }
733 }
734 }
735 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800736}
Lee Thomason56bdd022012-02-09 18:16:58 -0800737
738
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800739// --------- XMLNode ----------- //
740
741XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700742 _document( doc ),
743 _parent( 0 ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +0200744 _value(),
kezenatorec694152016-11-26 17:21:43 +1000745 _parseLineNum( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -0700746 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200747 _prev( 0 ), _next( 0 ),
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700748 _userData( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200749 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800750{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800751}
752
753
754XMLNode::~XMLNode()
755{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700756 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700757 if ( _parent ) {
758 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700759 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800760}
761
Michael Daumling21626882013-10-22 17:03:37 +0200762const char* XMLNode::Value() const
763{
Dmitry-Mecaa72a62016-08-10 17:34:34 +0300764 // Edge case: XMLDocuments don't have a Value. Return null.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530765 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530766 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200767 return _value.GetStr();
768}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800769
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800770void XMLNode::SetValue( const char* str, bool staticMem )
771{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700772 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700773 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700774 }
775 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700776 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700777 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800778}
779
Dmitry-Me3f63f212017-06-19 18:25:19 +0300780XMLNode* XMLNode::DeepClone(XMLDocument* target) const
Lee Thomason7085f002017-06-01 18:09:43 -0700781{
Dmitry-Me3f63f212017-06-19 18:25:19 +0300782 XMLNode* clone = this->ShallowClone(target);
Lee Thomason7085f002017-06-01 18:09:43 -0700783 if (!clone) return 0;
784
785 for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) {
Dmitry-Me3f63f212017-06-19 18:25:19 +0300786 XMLNode* childClone = child->DeepClone(target);
Lee Thomason7085f002017-06-01 18:09:43 -0700787 TIXMLASSERT(childClone);
788 clone->InsertEndChild(childClone);
789 }
790 return clone;
791}
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800792
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800793void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800794{
Lee Thomason624d43f2012-10-12 10:58:48 -0700795 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300796 TIXMLASSERT( _lastChild );
Dmitry-Me9cb4eca2016-08-18 18:10:59 +0300797 DeleteChild( _firstChild );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700798 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700799 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800800}
801
802
803void XMLNode::Unlink( XMLNode* child )
804{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300805 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300806 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300807 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700808 if ( child == _firstChild ) {
809 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700810 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700811 if ( child == _lastChild ) {
812 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700813 }
Lee Thomasond923c672012-01-23 08:44:25 -0800814
Lee Thomason624d43f2012-10-12 10:58:48 -0700815 if ( child->_prev ) {
816 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700817 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700818 if ( child->_next ) {
819 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700820 }
Lee Thomason8a763612017-06-16 09:30:16 -0700821 child->_next = 0;
822 child->_prev = 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700823 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800824}
825
826
U-Stream\Leeae25a442012-02-17 17:48:16 -0800827void XMLNode::DeleteChild( XMLNode* node )
828{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300829 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300830 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700831 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100832 Unlink( node );
Lee Thomason816d3fa2017-06-05 14:35:55 -0700833 TIXMLASSERT(node->_prev == 0);
834 TIXMLASSERT(node->_next == 0);
835 TIXMLASSERT(node->_parent == 0);
Dmitry-Mee3225b12014-09-03 11:03:11 +0400836 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800837}
838
839
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800840XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
841{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300842 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300843 if ( addThis->_document != _document ) {
844 TIXMLASSERT( false );
845 return 0;
846 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800847 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700848
Lee Thomason624d43f2012-10-12 10:58:48 -0700849 if ( _lastChild ) {
850 TIXMLASSERT( _firstChild );
851 TIXMLASSERT( _lastChild->_next == 0 );
852 _lastChild->_next = addThis;
853 addThis->_prev = _lastChild;
854 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800855
Lee Thomason624d43f2012-10-12 10:58:48 -0700856 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700857 }
858 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700859 TIXMLASSERT( _firstChild == 0 );
860 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800861
Lee Thomason624d43f2012-10-12 10:58:48 -0700862 addThis->_prev = 0;
863 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700864 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700865 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700866 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800867}
868
869
Lee Thomason1ff38e02012-02-14 18:18:16 -0800870XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
871{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300872 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300873 if ( addThis->_document != _document ) {
874 TIXMLASSERT( false );
875 return 0;
876 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800877 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700878
Lee Thomason624d43f2012-10-12 10:58:48 -0700879 if ( _firstChild ) {
880 TIXMLASSERT( _lastChild );
881 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800882
Lee Thomason624d43f2012-10-12 10:58:48 -0700883 _firstChild->_prev = addThis;
884 addThis->_next = _firstChild;
885 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800886
Lee Thomason624d43f2012-10-12 10:58:48 -0700887 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700888 }
889 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700890 TIXMLASSERT( _lastChild == 0 );
891 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800892
Lee Thomason624d43f2012-10-12 10:58:48 -0700893 addThis->_prev = 0;
894 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700895 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700896 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400897 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800898}
899
900
901XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
902{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300903 TIXMLASSERT( addThis );
904 if ( addThis->_document != _document ) {
905 TIXMLASSERT( false );
906 return 0;
907 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700908
Dmitry-Meabb2d042014-12-09 12:59:31 +0300909 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700910
Lee Thomason624d43f2012-10-12 10:58:48 -0700911 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300912 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700913 return 0;
914 }
Dmitry-Mee8f4a8b2017-09-15 19:34:36 +0300915 if ( afterThis == addThis ) {
916 // Current state: BeforeThis -> AddThis -> OneAfterAddThis
917 // Now AddThis must disappear from it's location and then
918 // reappear between BeforeThis and OneAfterAddThis.
919 // So just leave it where it is.
920 return addThis;
921 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800922
Lee Thomason624d43f2012-10-12 10:58:48 -0700923 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700924 // The last node or the only node.
925 return InsertEndChild( addThis );
926 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800927 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700928 addThis->_prev = afterThis;
929 addThis->_next = afterThis->_next;
930 afterThis->_next->_prev = addThis;
931 afterThis->_next = addThis;
932 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700933 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800934}
935
936
937
938
Dmitry-Me886ad972015-07-22 11:00:51 +0300939const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800940{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300941 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300942 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700943 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300944 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700945 }
946 }
947 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800948}
949
950
Dmitry-Me886ad972015-07-22 11:00:51 +0300951const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800952{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300953 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300954 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700955 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300956 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700957 }
958 }
959 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800960}
961
962
Dmitry-Me886ad972015-07-22 11:00:51 +0300963const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800964{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300965 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300966 const XMLElement* element = node->ToElementWithName( name );
967 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400968 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700969 }
970 }
971 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800972}
973
974
Dmitry-Me886ad972015-07-22 11:00:51 +0300975const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800976{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300977 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300978 const XMLElement* element = node->ToElementWithName( name );
979 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400980 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700981 }
982 }
983 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800984}
985
986
Dmitry-Me10b8ecc2017-04-12 17:57:44 +0300987char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -0800988{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700989 // This is a recursive method, but thinking about it "at the current level"
990 // it is a pretty simple flat list:
991 // <foo/>
992 // <!-- comment -->
993 //
994 // With a special case:
995 // <foo>
996 // </foo>
997 // <!-- comment -->
998 //
999 // Where the closing element (/foo) *must* be the next thing after the opening
1000 // element, and the names must match. BUT the tricky bit is that the closing
1001 // element will be read by the child.
1002 //
1003 // 'endTag' is the end tag for this node, it is returned by a call to a child.
1004 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001005
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001006 while( p && *p ) {
1007 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -08001008
Lee Thomason624d43f2012-10-12 10:58:48 -07001009 p = _document->Identify( p, &node );
Dmitry-Me43364312016-11-07 18:48:50 +03001010 TIXMLASSERT( p );
Dmitry-Me9fcb8762015-03-05 17:53:34 +03001011 if ( node == 0 ) {
1012 break;
1013 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001014
kezenatore3531812016-11-29 19:49:07 +10001015 int initialLineNum = node->_parseLineNum;
kezenatorec694152016-11-26 17:21:43 +10001016
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001017 StrPair endTag;
kezenator4f756162016-11-29 19:46:27 +10001018 p = node->ParseDeep( p, &endTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001019 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001020 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -07001021 if ( !_document->Error() ) {
kezenatore3531812016-11-29 19:49:07 +10001022 _document->SetError( XML_ERROR_PARSING, 0, 0, initialLineNum);
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001023 }
1024 break;
1025 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001026
Sarat Addepalli3df007e2015-05-20 10:43:51 +05301027 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301028 if ( decl ) {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001029 // Declarations are only allowed at document level
1030 bool wellLocated = ( ToDocument() != 0 );
1031 if ( wellLocated ) {
1032 // Multiple declarations are allowed but all declarations
1033 // must occur before anything else
1034 for ( const XMLNode* existingNode = _document->FirstChild(); existingNode; existingNode = existingNode->NextSibling() ) {
1035 if ( !existingNode->ToDeclaration() ) {
1036 wellLocated = false;
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301037 break;
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001038 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301039 }
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001040 }
1041 if ( !wellLocated ) {
kezenatore3531812016-11-29 19:49:07 +10001042 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0, initialLineNum);
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001043 DeleteNode( node );
1044 break;
1045 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301046 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301047
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001048 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001049 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -05001050 // We read the end tag. Return it to the parent.
1051 if ( ele->ClosingType() == XMLElement::CLOSING ) {
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001052 if ( parentEndTag ) {
1053 ele->_value.TransferTo( parentEndTag );
JayXone4bf6e32014-12-26 01:00:24 -05001054 }
1055 node->_memPool->SetTracked(); // created and then immediately deleted.
1056 DeleteNode( node );
1057 return p;
1058 }
1059
1060 // Handle an end tag returned to this level.
1061 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001062 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001063 if ( endTag.Empty() ) {
1064 if ( ele->ClosingType() == XMLElement::OPEN ) {
1065 mismatch = true;
1066 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001067 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001068 else {
1069 if ( ele->ClosingType() != XMLElement::OPEN ) {
1070 mismatch = true;
1071 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001072 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001073 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001074 }
1075 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001076 if ( mismatch ) {
kezenatore3531812016-11-29 19:49:07 +10001077 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0, initialLineNum);
JayXondbfdd8f2014-12-12 20:07:14 -05001078 DeleteNode( node );
1079 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001080 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001081 }
JayXondbfdd8f2014-12-12 20:07:14 -05001082 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001083 }
1084 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001085}
1086
Lee Thomason816d3fa2017-06-05 14:35:55 -07001087/*static*/ void XMLNode::DeleteNode( XMLNode* node )
Dmitry-Mee3225b12014-09-03 11:03:11 +04001088{
1089 if ( node == 0 ) {
1090 return;
1091 }
Lee Thomason816d3fa2017-06-05 14:35:55 -07001092 TIXMLASSERT(node->_document);
1093 if (!node->ToDocument()) {
1094 node->_document->MarkInUse(node);
1095 }
1096
Dmitry-Mee3225b12014-09-03 11:03:11 +04001097 MemPool* pool = node->_memPool;
1098 node->~XMLNode();
1099 pool->Free( node );
1100}
1101
Lee Thomason3cebdc42015-01-05 17:16:28 -08001102void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001103{
1104 TIXMLASSERT( insertThis );
1105 TIXMLASSERT( insertThis->_document == _document );
1106
Lee Thomason816d3fa2017-06-05 14:35:55 -07001107 if (insertThis->_parent) {
Dmitry-Me74e39402015-01-01 16:26:17 +03001108 insertThis->_parent->Unlink( insertThis );
Lee Thomason816d3fa2017-06-05 14:35:55 -07001109 }
1110 else {
1111 insertThis->_document->MarkInUse(insertThis);
Dmitry-Me74e39402015-01-01 16:26:17 +03001112 insertThis->_memPool->SetTracked();
Lee Thomason816d3fa2017-06-05 14:35:55 -07001113 }
Dmitry-Me74e39402015-01-01 16:26:17 +03001114}
1115
Dmitry-Meecb9b072016-10-12 16:44:59 +03001116const XMLElement* XMLNode::ToElementWithName( const char* name ) const
1117{
1118 const XMLElement* element = this->ToElement();
1119 if ( element == 0 ) {
1120 return 0;
1121 }
1122 if ( name == 0 ) {
1123 return element;
1124 }
1125 if ( XMLUtil::StringEqual( element->Name(), name ) ) {
1126 return element;
1127 }
1128 return 0;
1129}
1130
Lee Thomason5492a1c2012-01-23 15:32:10 -08001131// --------- XMLText ---------- //
kezenator4f756162016-11-29 19:46:27 +10001132char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001133{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001134 const char* start = p;
1135 if ( this->CData() ) {
kezenator4f756162016-11-29 19:46:27 +10001136 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001137 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001138 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001139 }
1140 return p;
1141 }
1142 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001143 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1144 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001145 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001146 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001147
kezenator4f756162016-11-29 19:46:27 +10001148 p = _value.ParseText( p, "<", flags, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001149 if ( p && *p ) {
1150 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001151 }
1152 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001153 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001154 }
1155 }
1156 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001157}
1158
1159
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001160XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1161{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001162 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001163 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001164 }
1165 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1166 text->SetCData( this->CData() );
1167 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001168}
1169
1170
1171bool XMLText::ShallowEqual( const XMLNode* compare ) const
1172{
Dmitry-Meba68a3a2017-03-21 11:39:48 +03001173 TIXMLASSERT( compare );
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001174 const XMLText* text = compare->ToText();
1175 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001176}
1177
1178
Lee Thomason56bdd022012-02-09 18:16:58 -08001179bool XMLText::Accept( XMLVisitor* visitor ) const
1180{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001181 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001182 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001183}
1184
1185
Lee Thomason3f57d272012-01-11 15:30:03 -08001186// --------- XMLComment ---------- //
1187
Lee Thomasone4422302012-01-20 17:59:50 -08001188XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001189{
1190}
1191
1192
Lee Thomasonce0763e2012-01-11 15:43:54 -08001193XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001194{
Lee Thomason3f57d272012-01-11 15:30:03 -08001195}
1196
1197
kezenator4f756162016-11-29 19:46:27 +10001198char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason3f57d272012-01-11 15:30:03 -08001199{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001200 // Comment parses as text.
1201 const char* start = p;
kezenator4f756162016-11-29 19:46:27 +10001202 p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001203 if ( p == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10001204 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001205 }
1206 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001207}
1208
1209
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001210XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1211{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001212 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001213 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001214 }
1215 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1216 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001217}
1218
1219
1220bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1221{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001222 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001223 const XMLComment* comment = compare->ToComment();
1224 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001225}
1226
1227
Lee Thomason751da522012-02-10 08:50:51 -08001228bool XMLComment::Accept( XMLVisitor* visitor ) const
1229{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001230 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001231 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001232}
Lee Thomason56bdd022012-02-09 18:16:58 -08001233
1234
Lee Thomason50f97b22012-02-11 16:33:40 -08001235// --------- XMLDeclaration ---------- //
1236
1237XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1238{
1239}
1240
1241
1242XMLDeclaration::~XMLDeclaration()
1243{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001244 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001245}
1246
1247
kezenator4f756162016-11-29 19:46:27 +10001248char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001249{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001250 // Declaration parses as text.
1251 const char* start = p;
kezenator4f756162016-11-29 19:46:27 +10001252 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001253 if ( p == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10001254 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001255 }
1256 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001257}
1258
1259
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001260XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1261{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001262 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001263 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001264 }
1265 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1266 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001267}
1268
1269
1270bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1271{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001272 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001273 const XMLDeclaration* declaration = compare->ToDeclaration();
1274 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001275}
1276
1277
1278
Lee Thomason50f97b22012-02-11 16:33:40 -08001279bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1280{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001281 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001282 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001283}
1284
1285// --------- XMLUnknown ---------- //
1286
1287XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1288{
1289}
1290
1291
1292XMLUnknown::~XMLUnknown()
1293{
1294}
1295
1296
kezenator4f756162016-11-29 19:46:27 +10001297char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001298{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001299 // Unknown parses as text.
1300 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001301
kezenator4f756162016-11-29 19:46:27 +10001302 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001303 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001304 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001305 }
1306 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001307}
1308
1309
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001310XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1311{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001312 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001313 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001314 }
1315 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1316 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001317}
1318
1319
1320bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1321{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001322 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001323 const XMLUnknown* unknown = compare->ToUnknown();
1324 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001325}
1326
1327
Lee Thomason50f97b22012-02-11 16:33:40 -08001328bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1329{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001330 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001331 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001332}
1333
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001334// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001335
1336const char* XMLAttribute::Name() const
1337{
1338 return _name.GetStr();
1339}
1340
1341const char* XMLAttribute::Value() const
1342{
1343 return _value.GetStr();
1344}
1345
kezenator4f756162016-11-29 19:46:27 +10001346char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001347{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001348 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001349 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001350 if ( !p || !*p ) {
1351 return 0;
1352 }
Lee Thomason22aead12012-01-23 13:29:35 -08001353
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001354 // Skip white space before =
kezenator4f756162016-11-29 19:46:27 +10001355 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001356 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001357 return 0;
1358 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001359
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001360 ++p; // move up to opening quote
kezenator4f756162016-11-29 19:46:27 +10001361 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001362 if ( *p != '\"' && *p != '\'' ) {
1363 return 0;
1364 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001365
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001366 char endTag[2] = { *p, 0 };
1367 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001368
kezenator4f756162016-11-29 19:46:27 +10001369 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001370 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001371}
1372
1373
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001374void XMLAttribute::SetName( const char* n )
1375{
Lee Thomason624d43f2012-10-12 10:58:48 -07001376 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001377}
1378
1379
Lee Thomason2fa81722012-11-09 12:37:46 -08001380XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001381{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001382 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001383 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001384 }
1385 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001386}
1387
1388
Lee Thomason2fa81722012-11-09 12:37:46 -08001389XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001390{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001391 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001392 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001393 }
1394 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001395}
1396
1397
Lee Thomason51c12712016-06-04 20:18:49 -07001398XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1399{
1400 if (XMLUtil::ToInt64(Value(), value)) {
1401 return XML_SUCCESS;
1402 }
1403 return XML_WRONG_ATTRIBUTE_TYPE;
1404}
1405
1406
Lee Thomason2fa81722012-11-09 12:37:46 -08001407XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001408{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001409 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001410 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001411 }
1412 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001413}
1414
1415
Lee Thomason2fa81722012-11-09 12:37:46 -08001416XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001417{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001418 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001419 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001420 }
1421 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001422}
1423
1424
Lee Thomason2fa81722012-11-09 12:37:46 -08001425XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001426{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001427 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001428 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001429 }
1430 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001431}
1432
1433
1434void XMLAttribute::SetAttribute( const char* v )
1435{
Lee Thomason624d43f2012-10-12 10:58:48 -07001436 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001437}
1438
1439
Lee Thomason1ff38e02012-02-14 18:18:16 -08001440void XMLAttribute::SetAttribute( int v )
1441{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001442 char buf[BUF_SIZE];
1443 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001444 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001445}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001446
1447
1448void XMLAttribute::SetAttribute( unsigned v )
1449{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001450 char buf[BUF_SIZE];
1451 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001452 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001453}
1454
1455
Lee Thomason51c12712016-06-04 20:18:49 -07001456void XMLAttribute::SetAttribute(int64_t v)
1457{
1458 char buf[BUF_SIZE];
1459 XMLUtil::ToStr(v, buf, BUF_SIZE);
1460 _value.SetStr(buf);
1461}
1462
1463
1464
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001465void XMLAttribute::SetAttribute( bool v )
1466{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001467 char buf[BUF_SIZE];
1468 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001469 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001470}
1471
1472void XMLAttribute::SetAttribute( double v )
1473{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001474 char buf[BUF_SIZE];
1475 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001476 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001477}
1478
1479void XMLAttribute::SetAttribute( float v )
1480{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001481 char buf[BUF_SIZE];
1482 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001483 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001484}
1485
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001486
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001487// --------- XMLElement ---------- //
1488XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Dmitry-Mee5035632017-04-05 18:02:40 +03001489 _closingType( OPEN ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001490 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001491{
1492}
1493
1494
1495XMLElement::~XMLElement()
1496{
Lee Thomason624d43f2012-10-12 10:58:48 -07001497 while( _rootAttribute ) {
1498 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001499 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001500 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001501 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001502}
1503
1504
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001505const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1506{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001507 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001508 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1509 return a;
1510 }
1511 }
1512 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001513}
1514
1515
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001516const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001517{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001518 const XMLAttribute* a = FindAttribute( name );
1519 if ( !a ) {
1520 return 0;
1521 }
1522 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1523 return a->Value();
1524 }
1525 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001526}
1527
Josh Wittnercf3dd092016-10-11 18:57:17 -07001528int XMLElement::IntAttribute(const char* name, int defaultValue) const
1529{
1530 int i = defaultValue;
1531 QueryIntAttribute(name, &i);
1532 return i;
1533}
1534
1535unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
1536{
1537 unsigned i = defaultValue;
1538 QueryUnsignedAttribute(name, &i);
1539 return i;
1540}
1541
1542int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
1543{
1544 int64_t i = defaultValue;
1545 QueryInt64Attribute(name, &i);
1546 return i;
1547}
1548
1549bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
1550{
1551 bool b = defaultValue;
1552 QueryBoolAttribute(name, &b);
1553 return b;
1554}
1555
1556double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
1557{
1558 double d = defaultValue;
1559 QueryDoubleAttribute(name, &d);
1560 return d;
1561}
1562
1563float XMLElement::FloatAttribute(const char* name, float defaultValue) const
1564{
1565 float f = defaultValue;
1566 QueryFloatAttribute(name, &f);
1567 return f;
1568}
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001569
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001570const char* XMLElement::GetText() const
1571{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001572 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001573 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001574 }
1575 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001576}
1577
1578
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001579void XMLElement::SetText( const char* inText )
1580{
Uli Kusterer869bb592014-01-21 01:36:16 +01001581 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001582 FirstChild()->SetValue( inText );
1583 else {
1584 XMLText* theText = GetDocument()->NewText( inText );
1585 InsertFirstChild( theText );
1586 }
1587}
1588
Lee Thomason5bb2d802014-01-24 10:42:57 -08001589
1590void XMLElement::SetText( int v )
1591{
1592 char buf[BUF_SIZE];
1593 XMLUtil::ToStr( v, buf, BUF_SIZE );
1594 SetText( buf );
1595}
1596
1597
1598void XMLElement::SetText( unsigned v )
1599{
1600 char buf[BUF_SIZE];
1601 XMLUtil::ToStr( v, buf, BUF_SIZE );
1602 SetText( buf );
1603}
1604
1605
Lee Thomason51c12712016-06-04 20:18:49 -07001606void XMLElement::SetText(int64_t v)
1607{
1608 char buf[BUF_SIZE];
1609 XMLUtil::ToStr(v, buf, BUF_SIZE);
1610 SetText(buf);
1611}
1612
1613
1614void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001615{
1616 char buf[BUF_SIZE];
1617 XMLUtil::ToStr( v, buf, BUF_SIZE );
1618 SetText( buf );
1619}
1620
1621
1622void XMLElement::SetText( float v )
1623{
1624 char buf[BUF_SIZE];
1625 XMLUtil::ToStr( v, buf, BUF_SIZE );
1626 SetText( buf );
1627}
1628
1629
1630void XMLElement::SetText( double v )
1631{
1632 char buf[BUF_SIZE];
1633 XMLUtil::ToStr( v, buf, BUF_SIZE );
1634 SetText( buf );
1635}
1636
1637
MortenMacFly4ee49f12013-01-14 20:03:14 +01001638XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001639{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001640 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001641 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001642 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001643 return XML_SUCCESS;
1644 }
1645 return XML_CAN_NOT_CONVERT_TEXT;
1646 }
1647 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001648}
1649
1650
MortenMacFly4ee49f12013-01-14 20:03:14 +01001651XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001652{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001653 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001654 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001655 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001656 return XML_SUCCESS;
1657 }
1658 return XML_CAN_NOT_CONVERT_TEXT;
1659 }
1660 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001661}
1662
1663
Lee Thomason51c12712016-06-04 20:18:49 -07001664XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1665{
1666 if (FirstChild() && FirstChild()->ToText()) {
1667 const char* t = FirstChild()->Value();
1668 if (XMLUtil::ToInt64(t, ival)) {
1669 return XML_SUCCESS;
1670 }
1671 return XML_CAN_NOT_CONVERT_TEXT;
1672 }
1673 return XML_NO_TEXT_NODE;
1674}
1675
1676
MortenMacFly4ee49f12013-01-14 20:03:14 +01001677XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001678{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001679 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001680 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001681 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001682 return XML_SUCCESS;
1683 }
1684 return XML_CAN_NOT_CONVERT_TEXT;
1685 }
1686 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001687}
1688
1689
MortenMacFly4ee49f12013-01-14 20:03:14 +01001690XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001691{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001692 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001693 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001694 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001695 return XML_SUCCESS;
1696 }
1697 return XML_CAN_NOT_CONVERT_TEXT;
1698 }
1699 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001700}
1701
1702
MortenMacFly4ee49f12013-01-14 20:03:14 +01001703XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001704{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001705 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001706 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001707 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001708 return XML_SUCCESS;
1709 }
1710 return XML_CAN_NOT_CONVERT_TEXT;
1711 }
1712 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001713}
1714
Josh Wittnercf3dd092016-10-11 18:57:17 -07001715int XMLElement::IntText(int defaultValue) const
1716{
1717 int i = defaultValue;
1718 QueryIntText(&i);
1719 return i;
1720}
1721
1722unsigned XMLElement::UnsignedText(unsigned defaultValue) const
1723{
1724 unsigned i = defaultValue;
1725 QueryUnsignedText(&i);
1726 return i;
1727}
1728
1729int64_t XMLElement::Int64Text(int64_t defaultValue) const
1730{
1731 int64_t i = defaultValue;
1732 QueryInt64Text(&i);
1733 return i;
1734}
1735
1736bool XMLElement::BoolText(bool defaultValue) const
1737{
1738 bool b = defaultValue;
1739 QueryBoolText(&b);
1740 return b;
1741}
1742
1743double XMLElement::DoubleText(double defaultValue) const
1744{
1745 double d = defaultValue;
1746 QueryDoubleText(&d);
1747 return d;
1748}
1749
1750float XMLElement::FloatText(float defaultValue) const
1751{
1752 float f = defaultValue;
1753 QueryFloatText(&f);
1754 return f;
1755}
Lee Thomason21be8822012-07-15 17:27:22 -07001756
1757
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001758XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1759{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001760 XMLAttribute* last = 0;
1761 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001762 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001763 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001764 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001765 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1766 break;
1767 }
1768 }
1769 if ( !attrib ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001770 attrib = CreateAttribute();
1771 TIXMLASSERT( attrib );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001772 if ( last ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001773 TIXMLASSERT( last->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001774 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001775 }
1776 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001777 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001778 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001779 }
1780 attrib->SetName( name );
1781 }
1782 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001783}
1784
1785
U-Stream\Leeae25a442012-02-17 17:48:16 -08001786void XMLElement::DeleteAttribute( const char* name )
1787{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001788 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001789 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001790 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1791 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001792 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001793 }
1794 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001795 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001796 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001797 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001798 break;
1799 }
1800 prev = a;
1801 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001802}
1803
1804
kezenator4f756162016-11-29 19:46:27 +10001805char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001806{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001807 const char* start = p;
1808 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001809
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001810 // Read the attributes.
1811 while( p ) {
kezenator4f756162016-11-29 19:46:27 +10001812 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001813 if ( !(*p) ) {
kezenatorec694152016-11-26 17:21:43 +10001814 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name(), _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001815 return 0;
1816 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001817
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001818 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001819 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001820 XMLAttribute* attrib = CreateAttribute();
1821 TIXMLASSERT( attrib );
kezenatorec694152016-11-26 17:21:43 +10001822 attrib->_parseLineNum = _document->_parseCurLineNum;
Lee Thomasond1983222012-02-06 08:41:24 -08001823
kezenatorec694152016-11-26 17:21:43 +10001824 int attrLineNum = attrib->_parseLineNum;
1825
kezenator4f756162016-11-29 19:46:27 +10001826 p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001827 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001828 DeleteAttribute( attrib );
kezenatorec694152016-11-26 17:21:43 +10001829 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p, attrLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001830 return 0;
1831 }
1832 // There is a minor bug here: if the attribute in the source xml
1833 // document is duplicated, it will not be detected and the
1834 // attribute will be doubly added. However, tracking the 'prevAttribute'
1835 // avoids re-scanning the attribute list. Preferring performance for
1836 // now, may reconsider in the future.
1837 if ( prevAttribute ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001838 TIXMLASSERT( prevAttribute->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001839 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001840 }
1841 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001842 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001843 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001844 }
1845 prevAttribute = attrib;
1846 }
1847 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001848 else if ( *p == '>' ) {
1849 ++p;
1850 break;
1851 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001852 // end of the tag
1853 else if ( *p == '/' && *(p+1) == '>' ) {
1854 _closingType = CLOSED;
1855 return p+2; // done; sealed element.
1856 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001857 else {
kezenatorec694152016-11-26 17:21:43 +10001858 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001859 return 0;
1860 }
1861 }
1862 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001863}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001864
Dmitry-Mee3225b12014-09-03 11:03:11 +04001865void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1866{
1867 if ( attribute == 0 ) {
1868 return;
1869 }
1870 MemPool* pool = attribute->_memPool;
1871 attribute->~XMLAttribute();
1872 pool->Free( attribute );
1873}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001874
Dmitry-Mea60caa22016-11-22 18:28:08 +03001875XMLAttribute* XMLElement::CreateAttribute()
1876{
1877 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
1878 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
Dmitry-Me7221b492017-03-03 15:45:51 +03001879 TIXMLASSERT( attrib );
Dmitry-Mea60caa22016-11-22 18:28:08 +03001880 attrib->_memPool = &_document->_attributePool;
1881 attrib->_memPool->SetTracked();
1882 return attrib;
1883}
1884
Lee Thomason67d61312012-01-24 16:01:51 -08001885//
1886// <ele></ele>
1887// <ele>foo<b>bar</b></ele>
1888//
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001889char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -08001890{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001891 // Read the element name.
kezenator4f756162016-11-29 19:46:27 +10001892 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomason67d61312012-01-24 16:01:51 -08001893
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001894 // The closing element is the </element> form. It is
1895 // parsed just like a regular element then deleted from
1896 // the DOM.
1897 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001898 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001899 ++p;
1900 }
Lee Thomason67d61312012-01-24 16:01:51 -08001901
Lee Thomason624d43f2012-10-12 10:58:48 -07001902 p = _value.ParseName( p );
1903 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001904 return 0;
1905 }
Lee Thomason67d61312012-01-24 16:01:51 -08001906
kezenator4f756162016-11-29 19:46:27 +10001907 p = ParseAttributes( p, curLineNumPtr );
Dmitry-Mee5035632017-04-05 18:02:40 +03001908 if ( !p || !*p || _closingType != OPEN ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001909 return p;
1910 }
Lee Thomason67d61312012-01-24 16:01:51 -08001911
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001912 p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001913 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001914}
1915
1916
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001917
1918XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1919{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001920 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001921 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001922 }
1923 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1924 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1925 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1926 }
1927 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001928}
1929
1930
1931bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1932{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001933 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001934 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001935 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001936
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001937 const XMLAttribute* a=FirstAttribute();
1938 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001939
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001940 while ( a && b ) {
1941 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1942 return false;
1943 }
1944 a = a->Next();
1945 b = b->Next();
1946 }
1947 if ( a || b ) {
1948 // different count
1949 return false;
1950 }
1951 return true;
1952 }
1953 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001954}
1955
1956
Lee Thomason751da522012-02-10 08:50:51 -08001957bool XMLElement::Accept( XMLVisitor* visitor ) const
1958{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001959 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001960 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001961 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1962 if ( !node->Accept( visitor ) ) {
1963 break;
1964 }
1965 }
1966 }
1967 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001968}
Lee Thomason56bdd022012-02-09 18:16:58 -08001969
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001970
Lee Thomason3f57d272012-01-11 15:30:03 -08001971// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001972
1973// Warning: List must match 'enum XMLError'
1974const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1975 "XML_SUCCESS",
1976 "XML_NO_ATTRIBUTE",
1977 "XML_WRONG_ATTRIBUTE_TYPE",
1978 "XML_ERROR_FILE_NOT_FOUND",
1979 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1980 "XML_ERROR_FILE_READ_ERROR",
Lee Thomason8bba8b42017-06-20 09:18:41 -07001981 "UNUSED_XML_ERROR_ELEMENT_MISMATCH",
Lee Thomason331596e2014-09-11 14:56:43 -07001982 "XML_ERROR_PARSING_ELEMENT",
1983 "XML_ERROR_PARSING_ATTRIBUTE",
Lee Thomason8bba8b42017-06-20 09:18:41 -07001984 "UNUSED_XML_ERROR_IDENTIFYING_TAG",
Lee Thomason331596e2014-09-11 14:56:43 -07001985 "XML_ERROR_PARSING_TEXT",
1986 "XML_ERROR_PARSING_CDATA",
1987 "XML_ERROR_PARSING_COMMENT",
1988 "XML_ERROR_PARSING_DECLARATION",
1989 "XML_ERROR_PARSING_UNKNOWN",
1990 "XML_ERROR_EMPTY_DOCUMENT",
1991 "XML_ERROR_MISMATCHED_ELEMENT",
1992 "XML_ERROR_PARSING",
1993 "XML_CAN_NOT_CONVERT_TEXT",
1994 "XML_NO_TEXT_NODE"
1995};
1996
1997
Dmitry-Meae8a82a2017-03-03 15:40:32 +03001998XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001999 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002000 _writeBOM( false ),
2001 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07002002 _errorID(XML_SUCCESS),
Dmitry-Meae8a82a2017-03-03 15:40:32 +03002003 _whitespaceMode( whitespaceMode ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002004 _errorStr1(),
2005 _errorStr2(),
Dmitry-Mef89bd3e2017-01-18 18:33:55 +03002006 _errorLineNum( 0 ),
2007 _charBuffer( 0 ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002008 _parseCurLineNum( 0 ),
2009 _unlinked(),
2010 _elementPool(),
2011 _attributePool(),
2012 _textPool(),
2013 _commentPool()
U-Lama\Lee560bd472011-12-28 19:42:49 -08002014{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03002015 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
2016 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08002017}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002018
2019
Lee Thomason3f57d272012-01-11 15:30:03 -08002020XMLDocument::~XMLDocument()
2021{
Lee Thomasonf07b9522014-10-30 13:25:12 -07002022 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08002023}
2024
2025
Lee Thomason816d3fa2017-06-05 14:35:55 -07002026void XMLDocument::MarkInUse(XMLNode* node)
2027{
Dmitry-Mec2f677b2017-06-15 12:44:27 +03002028 TIXMLASSERT(node);
Lee Thomason816d3fa2017-06-05 14:35:55 -07002029 TIXMLASSERT(node->_parent == 0);
2030
2031 for (int i = 0; i < _unlinked.Size(); ++i) {
2032 if (node == _unlinked[i]) {
2033 _unlinked.SwapRemove(i);
2034 break;
2035 }
2036 }
2037}
2038
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002039void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08002040{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002041 DeleteChildren();
Lee Thomason816d3fa2017-06-05 14:35:55 -07002042 while( _unlinked.Size()) {
2043 DeleteNode(_unlinked[0]); // Will remove from _unlinked as part of delete.
2044 }
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002045
Dmitry-Meab37df82014-11-28 12:08:36 +03002046#ifdef DEBUG
2047 const bool hadError = Error();
2048#endif
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002049 ClearError();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002050
Lee Thomason624d43f2012-10-12 10:58:48 -07002051 delete [] _charBuffer;
2052 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07002053
2054#if 0
2055 _textPool.Trace( "text" );
2056 _elementPool.Trace( "element" );
2057 _commentPool.Trace( "comment" );
2058 _attributePool.Trace( "attribute" );
2059#endif
2060
2061#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002062 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002063 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
2064 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
2065 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
2066 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
2067 }
2068#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08002069}
2070
Lee Thomason3f57d272012-01-11 15:30:03 -08002071
Shuichiro Suzuki87cd4e02017-08-24 11:20:26 +09002072void XMLDocument::DeepCopy(XMLDocument* target) const
Lee Thomason7085f002017-06-01 18:09:43 -07002073{
2074 TIXMLASSERT(target);
Lee Thomason1346a172017-06-14 15:14:19 -07002075 if (target == this) {
2076 return; // technically success - a no-op.
2077 }
Lee Thomason7085f002017-06-01 18:09:43 -07002078
2079 target->Clear();
2080 for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {
2081 target->InsertEndChild(node->DeepClone(target));
2082 }
2083}
2084
Lee Thomason2c85a712012-01-31 08:24:24 -08002085XMLElement* XMLDocument::NewElement( const char* name )
2086{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002087 XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002088 ele->SetName( name );
2089 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08002090}
2091
2092
Lee Thomason1ff38e02012-02-14 18:18:16 -08002093XMLComment* XMLDocument::NewComment( const char* str )
2094{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002095 XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002096 comment->SetValue( str );
2097 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002098}
2099
2100
2101XMLText* XMLDocument::NewText( const char* str )
2102{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002103 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002104 text->SetValue( str );
2105 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002106}
2107
2108
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002109XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2110{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002111 XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002112 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2113 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002114}
2115
2116
2117XMLUnknown* XMLDocument::NewUnknown( const char* str )
2118{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002119 XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002120 unk->SetValue( str );
2121 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002122}
2123
Dmitry-Me01578db2014-08-19 10:18:48 +04002124static FILE* callfopen( const char* filepath, const char* mode )
2125{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002126 TIXMLASSERT( filepath );
2127 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002128#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2129 FILE* fp = 0;
2130 errno_t err = fopen_s( &fp, filepath, mode );
2131 if ( err ) {
2132 return 0;
2133 }
2134#else
2135 FILE* fp = fopen( filepath, mode );
2136#endif
2137 return fp;
2138}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08002139
2140void XMLDocument::DeleteNode( XMLNode* node ) {
2141 TIXMLASSERT( node );
2142 TIXMLASSERT(node->_document == this );
2143 if (node->_parent) {
2144 node->_parent->DeleteChild( node );
2145 }
2146 else {
2147 // Isn't in the tree.
2148 // Use the parent delete.
2149 // Also, we need to mark it tracked: we 'know'
2150 // it was never used.
2151 node->_memPool->SetTracked();
2152 // Call the static XMLNode version:
2153 XMLNode::DeleteNode(node);
2154 }
2155}
2156
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002157
Lee Thomason2fa81722012-11-09 12:37:46 -08002158XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002159{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002160 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04002161 FILE* fp = callfopen( filename, "rb" );
2162 if ( !fp ) {
kezenatorec694152016-11-26 17:21:43 +10002163 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002164 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002165 }
2166 LoadFile( fp );
2167 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002168 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002169}
2170
Dmitry-Me901fed52015-09-25 10:29:51 +03002171// This is likely overengineered template art to have a check that unsigned long value incremented
2172// by one still fits into size_t. If size_t type is larger than unsigned long type
2173// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
2174// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
2175// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
2176// types sizes relate to each other.
2177template
2178<bool = (sizeof(unsigned long) >= sizeof(size_t))>
2179struct LongFitsIntoSizeTMinusOne {
2180 static bool Fits( unsigned long value )
2181 {
2182 return value < (size_t)-1;
2183 }
2184};
2185
2186template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02002187struct LongFitsIntoSizeTMinusOne<false> {
2188 static bool Fits( unsigned long )
2189 {
2190 return true;
2191 }
2192};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002193
Lee Thomason2fa81722012-11-09 12:37:46 -08002194XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002195{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002196 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002197
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002198 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002199 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
kezenatorec694152016-11-26 17:21:43 +10002200 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002201 return _errorID;
2202 }
2203
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002204 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002205 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002206 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002207 if ( filelength == -1L ) {
kezenatorec694152016-11-26 17:21:43 +10002208 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002209 return _errorID;
2210 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002211 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002212
Dmitry-Me901fed52015-09-25 10:29:51 +03002213 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002214 // Cannot handle files which won't fit in buffer together with null terminator
kezenatorec694152016-11-26 17:21:43 +10002215 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002216 return _errorID;
2217 }
2218
Dmitry-Me72801b82015-05-07 09:41:39 +03002219 if ( filelength == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10002220 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002221 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002222 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002223
Dmitry-Me72801b82015-05-07 09:41:39 +03002224 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002225 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002226 _charBuffer = new char[size+1];
2227 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002228 if ( read != size ) {
kezenatorec694152016-11-26 17:21:43 +10002229 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002230 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002231 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002232
Lee Thomason624d43f2012-10-12 10:58:48 -07002233 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002234
Dmitry-Me97476b72015-01-01 16:15:57 +03002235 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002236 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002237}
2238
2239
Lee Thomason2fa81722012-11-09 12:37:46 -08002240XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002241{
Dmitry-Me01578db2014-08-19 10:18:48 +04002242 FILE* fp = callfopen( filename, "w" );
2243 if ( !fp ) {
kezenatorec694152016-11-26 17:21:43 +10002244 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002245 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002246 }
2247 SaveFile(fp, compact);
2248 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002249 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002250}
2251
2252
Lee Thomason2fa81722012-11-09 12:37:46 -08002253XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002254{
Ant Mitchell189198f2015-03-24 16:20:36 +00002255 // Clear any error from the last save, otherwise it will get reported
2256 // for *this* call.
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002257 ClearError();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002258 XMLPrinter stream( fp, compact );
2259 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002260 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002261}
2262
Lee Thomason1ff38e02012-02-14 18:18:16 -08002263
Lee Thomason2fa81722012-11-09 12:37:46 -08002264XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002265{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002266 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002267
Lee Thomason82d32002014-02-21 22:47:18 -08002268 if ( len == 0 || !p || !*p ) {
kezenatorec694152016-11-26 17:21:43 +10002269 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002270 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002271 }
2272 if ( len == (size_t)(-1) ) {
2273 len = strlen( p );
2274 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002275 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002276 _charBuffer = new char[ len+1 ];
2277 memcpy( _charBuffer, p, len );
2278 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002279
Dmitry-Me97476b72015-01-01 16:15:57 +03002280 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002281 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002282 // clean up now essentially dangling memory.
2283 // and the parse fail can put objects in the
2284 // pools that are dead and inaccessible.
2285 DeleteChildren();
2286 _elementPool.Clear();
2287 _attributePool.Clear();
2288 _textPool.Clear();
2289 _commentPool.Clear();
2290 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002291 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002292}
2293
2294
PKEuS1c5f99e2013-07-06 11:28:39 +02002295void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002296{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002297 if ( streamer ) {
2298 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002299 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002300 else {
2301 XMLPrinter stdoutStreamer( stdout );
2302 Accept( &stdoutStreamer );
2303 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002304}
2305
2306
kezenatorec694152016-11-26 17:21:43 +10002307void XMLDocument::SetError( XMLError error, const char* str1, const char* str2, int lineNum )
Lee Thomason67d61312012-01-24 16:01:51 -08002308{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002309 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002310 _errorID = error;
Lee Thomason584af572016-09-05 14:14:16 -07002311
2312 _errorStr1.Reset();
2313 _errorStr2.Reset();
kezenatorec694152016-11-26 17:21:43 +10002314 _errorLineNum = lineNum;
Lee Thomason584af572016-09-05 14:14:16 -07002315
2316 if (str1)
2317 _errorStr1.SetStr(str1);
2318 if (str2)
2319 _errorStr2.SetStr(str2);
Lee Thomason67d61312012-01-24 16:01:51 -08002320}
2321
Lee Thomasone90e9012016-12-24 07:34:39 -08002322/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
Lee Thomason331596e2014-09-11 14:56:43 -07002323{
kezenator5a700712016-11-26 13:54:42 +10002324 TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2325 const char* errorName = _errorNames[errorID];
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002326 TIXMLASSERT( errorName && errorName[0] );
2327 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002328}
Lee Thomason5cae8972012-01-24 18:03:07 -08002329
Lee Thomason8c9e3132017-06-26 16:55:01 -07002330const char* XMLDocument::GetErrorStr1() const
2331{
2332 return _errorStr1.GetStr();
2333}
2334
2335const char* XMLDocument::GetErrorStr2() const
2336{
2337 return _errorStr2.GetStr();
2338}
2339
kezenator5a700712016-11-26 13:54:42 +10002340const char* XMLDocument::ErrorName() const
2341{
Lee Thomasone90e9012016-12-24 07:34:39 -08002342 return ErrorIDToName(_errorID);
kezenator5a700712016-11-26 13:54:42 +10002343}
2344
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002345void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002346{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002347 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002348 static const int LEN = 20;
2349 char buf1[LEN] = { 0 };
2350 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002351
Lee Thomason584af572016-09-05 14:14:16 -07002352 if ( !_errorStr1.Empty() ) {
2353 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002354 }
Lee Thomason584af572016-09-05 14:14:16 -07002355 if ( !_errorStr2.Empty() ) {
2356 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002357 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002358
Dmitry-Me2ad43202015-04-16 12:18:58 +03002359 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2360 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2361 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
kezenatorec694152016-11-26 17:21:43 +10002362 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s line=%d\n",
2363 static_cast<int>( _errorID ), ErrorName(), buf1, buf2, _errorLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002364 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002365}
2366
Dmitry-Me97476b72015-01-01 16:15:57 +03002367void XMLDocument::Parse()
2368{
2369 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2370 TIXMLASSERT( _charBuffer );
kezenatorec694152016-11-26 17:21:43 +10002371 _parseCurLineNum = 1;
2372 _parseLineNum = 1;
Lee Thomason3cebdc42015-01-05 17:16:28 -08002373 char* p = _charBuffer;
kezenator4f756162016-11-29 19:46:27 +10002374 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mee28be752015-01-09 14:59:30 +03002375 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002376 if ( !*p ) {
kezenatorec694152016-11-26 17:21:43 +10002377 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002378 return;
2379 }
kezenator4f756162016-11-29 19:46:27 +10002380 ParseDeep(p, 0, &_parseCurLineNum );
Dmitry-Me97476b72015-01-01 16:15:57 +03002381}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002382
PKEuS1bfb9542013-08-04 13:51:17 +02002383XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002384 _elementJustOpened( false ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002385 _stack(),
Lee Thomason624d43f2012-10-12 10:58:48 -07002386 _firstElement( true ),
2387 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002388 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002389 _textDepth( -1 ),
2390 _processEntities( true ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002391 _compactMode( compact ),
2392 _buffer()
Lee Thomason5cae8972012-01-24 18:03:07 -08002393{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002394 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002395 _entityFlag[i] = false;
2396 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002397 }
2398 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002399 const char entityValue = entities[i].value;
Dmitry-Mea28eb072017-08-25 18:34:18 +03002400 const unsigned char flagIndex = (unsigned char)entityValue;
2401 TIXMLASSERT( flagIndex < ENTITY_RANGE );
2402 _entityFlag[flagIndex] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002403 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002404 _restrictedEntityFlag[(unsigned char)'&'] = true;
2405 _restrictedEntityFlag[(unsigned char)'<'] = true;
2406 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002407 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002408}
2409
2410
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002411void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002412{
2413 va_list va;
2414 va_start( va, format );
2415
Lee Thomason624d43f2012-10-12 10:58:48 -07002416 if ( _fp ) {
2417 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002418 }
2419 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002420 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002421 // Close out and re-start the va-args
2422 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002423 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002424 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002425 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002426 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002427 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002428 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002429 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002430}
2431
2432
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002433void XMLPrinter::Write( const char* data, size_t size )
2434{
2435 if ( _fp ) {
2436 fwrite ( data , sizeof(char), size, _fp);
2437 }
2438 else {
2439 char* p = _buffer.PushArr( size ) - 1; // back up over the null terminator.
2440 memcpy( p, data, size );
2441 p[size] = 0;
2442 }
2443}
2444
2445
2446void XMLPrinter::Putc( char ch )
2447{
2448 if ( _fp ) {
2449 fputc ( ch, _fp);
2450 }
2451 else {
2452 char* p = _buffer.PushArr( sizeof(char) ) - 1; // back up over the null terminator.
2453 p[0] = ch;
2454 p[1] = 0;
2455 }
2456}
2457
2458
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002459void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002460{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002461 for( int i=0; i<depth; ++i ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002462 Write( " " );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002463 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002464}
2465
2466
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002467void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002468{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002469 // Look for runs of bytes between entities to print.
2470 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002471
Lee Thomason624d43f2012-10-12 10:58:48 -07002472 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002473 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002474 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002475 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002476 // Remember, char is sometimes signed. (How many times has that bitten me?)
2477 if ( *q > 0 && *q < ENTITY_RANGE ) {
2478 // Check for entities. If one is found, flush
2479 // the stream up until the entity, write the
2480 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002481 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002482 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002483 const size_t delta = q - p;
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002484 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002485 Write( p, toPrint );
Dmitry-Med95172b2015-03-30 08:11:18 +03002486 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002487 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002488 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002489 for( int i=0; i<NUM_ENTITIES; ++i ) {
2490 if ( entities[i].value == *q ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002491 Putc( '&' );
2492 Write( entities[i].pattern );
2493 Putc( ';' );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002494 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002495 break;
2496 }
2497 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002498 if ( !entityPatternPrinted ) {
2499 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2500 TIXMLASSERT( false );
2501 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002502 ++p;
2503 }
2504 }
2505 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002506 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002507 }
2508 }
2509 // Flush the remaining string. This will be the entire
2510 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002511 TIXMLASSERT( p <= q );
2512 if ( !_processEntities || ( p < q ) ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002513 Write( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002514 }
Lee Thomason857b8682012-01-25 17:50:25 -08002515}
2516
U-Stream\Leeae25a442012-02-17 17:48:16 -08002517
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002518void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002519{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002520 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002521 static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002522 Write( reinterpret_cast< const char* >( bom ) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002523 }
2524 if ( writeDec ) {
2525 PushDeclaration( "xml version=\"1.0\"" );
2526 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002527}
2528
2529
Uli Kusterer593a33d2014-02-01 12:48:51 +01002530void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002531{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002532 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002533 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002534
Uli Kusterer593a33d2014-02-01 12:48:51 +01002535 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002536 Putc( '\n' );
PKEuS1bfb9542013-08-04 13:51:17 +02002537 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002538 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002539 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002540 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002541
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002542 Write ( "<" );
2543 Write ( name );
2544
Lee Thomason624d43f2012-10-12 10:58:48 -07002545 _elementJustOpened = true;
2546 _firstElement = false;
2547 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002548}
2549
2550
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002551void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002552{
Lee Thomason624d43f2012-10-12 10:58:48 -07002553 TIXMLASSERT( _elementJustOpened );
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002554 Write( " " );
2555 Write( name );
2556 Write( "=\"" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002557 PrintString( value, false );
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002558 Write( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002559}
2560
2561
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002562void XMLPrinter::PushAttribute( const char* name, int v )
2563{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002564 char buf[BUF_SIZE];
2565 XMLUtil::ToStr( v, buf, BUF_SIZE );
2566 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002567}
2568
2569
2570void XMLPrinter::PushAttribute( const char* name, unsigned v )
2571{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002572 char buf[BUF_SIZE];
2573 XMLUtil::ToStr( v, buf, BUF_SIZE );
2574 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002575}
2576
2577
Lee Thomason51c12712016-06-04 20:18:49 -07002578void XMLPrinter::PushAttribute(const char* name, int64_t v)
2579{
2580 char buf[BUF_SIZE];
2581 XMLUtil::ToStr(v, buf, BUF_SIZE);
2582 PushAttribute(name, buf);
2583}
2584
2585
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002586void XMLPrinter::PushAttribute( const char* name, bool v )
2587{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002588 char buf[BUF_SIZE];
2589 XMLUtil::ToStr( v, buf, BUF_SIZE );
2590 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002591}
2592
2593
2594void XMLPrinter::PushAttribute( const char* name, double v )
2595{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002596 char buf[BUF_SIZE];
2597 XMLUtil::ToStr( v, buf, BUF_SIZE );
2598 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002599}
2600
2601
Uli Kustererca412e82014-02-01 13:35:05 +01002602void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002603{
Lee Thomason624d43f2012-10-12 10:58:48 -07002604 --_depth;
2605 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002606
Lee Thomason624d43f2012-10-12 10:58:48 -07002607 if ( _elementJustOpened ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002608 Write( "/>" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002609 }
2610 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002611 if ( _textDepth < 0 && !compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002612 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002613 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002614 }
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002615 Write ( "</" );
2616 Write ( name );
2617 Write ( ">" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002618 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002619
Lee Thomason624d43f2012-10-12 10:58:48 -07002620 if ( _textDepth == _depth ) {
2621 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002622 }
Uli Kustererca412e82014-02-01 13:35:05 +01002623 if ( _depth == 0 && !compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002624 Putc( '\n' );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002625 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002626 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002627}
2628
2629
Dmitry-Mea092bc12014-12-23 17:57:05 +03002630void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002631{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002632 if ( !_elementJustOpened ) {
2633 return;
2634 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002635 _elementJustOpened = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002636 Putc( '>' );
Lee Thomason5cae8972012-01-24 18:03:07 -08002637}
2638
2639
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002640void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002641{
Lee Thomason624d43f2012-10-12 10:58:48 -07002642 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002643
Dmitry-Mea092bc12014-12-23 17:57:05 +03002644 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002645 if ( cdata ) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002646 Write( "<![CDATA[" );
2647 Write( text );
2648 Write( "]]>" );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002649 }
2650 else {
2651 PrintString( text, true );
2652 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002653}
2654
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002655void XMLPrinter::PushText( int64_t value )
2656{
2657 char buf[BUF_SIZE];
2658 XMLUtil::ToStr( value, buf, BUF_SIZE );
2659 PushText( buf, false );
2660}
2661
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002662void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002663{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002664 char buf[BUF_SIZE];
2665 XMLUtil::ToStr( value, buf, BUF_SIZE );
2666 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002667}
2668
2669
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002670void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002671{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002672 char buf[BUF_SIZE];
2673 XMLUtil::ToStr( value, buf, BUF_SIZE );
2674 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002675}
2676
2677
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002678void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002679{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002680 char buf[BUF_SIZE];
2681 XMLUtil::ToStr( value, buf, BUF_SIZE );
2682 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002683}
2684
2685
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002686void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002687{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002688 char buf[BUF_SIZE];
2689 XMLUtil::ToStr( value, buf, BUF_SIZE );
2690 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002691}
2692
2693
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002694void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002695{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002696 char buf[BUF_SIZE];
2697 XMLUtil::ToStr( value, buf, BUF_SIZE );
2698 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002699}
2700
Lee Thomason5cae8972012-01-24 18:03:07 -08002701
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002702void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002703{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002704 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002705 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002706 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002707 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002708 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002709 _firstElement = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002710
2711 Write( "<!--" );
2712 Write( comment );
2713 Write( "-->" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002714}
Lee Thomason751da522012-02-10 08:50:51 -08002715
2716
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002717void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002718{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002719 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002720 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002721 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002722 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002723 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002724 _firstElement = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002725
2726 Write( "<?" );
2727 Write( value );
2728 Write( "?>" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002729}
2730
2731
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002732void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002733{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002734 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002735 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002736 Putc( '\n' );
Lee Thomason624d43f2012-10-12 10:58:48 -07002737 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002738 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002739 _firstElement = false;
Alexander Golubevb2e08e42016-03-28 19:51:59 +03002740
2741 Write( "<!" );
2742 Write( value );
2743 Write( ">" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002744}
2745
2746
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002747bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002748{
Lee Thomason624d43f2012-10-12 10:58:48 -07002749 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002750 if ( doc.HasBOM() ) {
2751 PushHeader( true, false );
2752 }
2753 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002754}
2755
2756
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002757bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002758{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002759 const XMLElement* parentElem = 0;
2760 if ( element.Parent() ) {
2761 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002762 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002763 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002764 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002765 while ( attribute ) {
2766 PushAttribute( attribute->Name(), attribute->Value() );
2767 attribute = attribute->Next();
2768 }
2769 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002770}
2771
2772
Uli Kustererca412e82014-02-01 13:35:05 +01002773bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002774{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002775 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002776 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002777}
2778
2779
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002780bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002781{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002782 PushText( text.Value(), text.CData() );
2783 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002784}
2785
2786
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002787bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002788{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002789 PushComment( comment.Value() );
2790 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002791}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002792
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002793bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002794{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002795 PushDeclaration( declaration.Value() );
2796 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002797}
2798
2799
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002800bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002801{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002802 PushUnknown( unknown.Value() );
2803 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002804}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002805
Lee Thomason685b8952012-11-12 13:00:06 -08002806} // namespace tinyxml2
2807