blob: dcf2a43bf28a823f3d31fb756056014cad5aef1c [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 ),
kezenatorec694152016-11-26 17:21:43 +1000744 _parseLineNum( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -0700745 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200746 _prev( 0 ), _next( 0 ),
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700747 _userData( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200748 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800749{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800750}
751
752
753XMLNode::~XMLNode()
754{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700755 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700756 if ( _parent ) {
757 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700758 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800759}
760
Michael Daumling21626882013-10-22 17:03:37 +0200761const char* XMLNode::Value() const
762{
Dmitry-Mecaa72a62016-08-10 17:34:34 +0300763 // Edge case: XMLDocuments don't have a Value. Return null.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530764 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530765 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200766 return _value.GetStr();
767}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800768
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800769void XMLNode::SetValue( const char* str, bool staticMem )
770{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700771 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700772 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700773 }
774 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700775 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700776 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800777}
778
Dmitry-Me3f63f212017-06-19 18:25:19 +0300779XMLNode* XMLNode::DeepClone(XMLDocument* target) const
Lee Thomason7085f002017-06-01 18:09:43 -0700780{
Dmitry-Me3f63f212017-06-19 18:25:19 +0300781 XMLNode* clone = this->ShallowClone(target);
Lee Thomason7085f002017-06-01 18:09:43 -0700782 if (!clone) return 0;
783
784 for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) {
Dmitry-Me3f63f212017-06-19 18:25:19 +0300785 XMLNode* childClone = child->DeepClone(target);
Lee Thomason7085f002017-06-01 18:09:43 -0700786 TIXMLASSERT(childClone);
787 clone->InsertEndChild(childClone);
788 }
789 return clone;
790}
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800791
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800792void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800793{
Lee Thomason624d43f2012-10-12 10:58:48 -0700794 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300795 TIXMLASSERT( _lastChild );
Dmitry-Me9cb4eca2016-08-18 18:10:59 +0300796 DeleteChild( _firstChild );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700797 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700798 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800799}
800
801
802void XMLNode::Unlink( XMLNode* child )
803{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300804 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300805 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300806 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700807 if ( child == _firstChild ) {
808 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700809 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700810 if ( child == _lastChild ) {
811 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700812 }
Lee Thomasond923c672012-01-23 08:44:25 -0800813
Lee Thomason624d43f2012-10-12 10:58:48 -0700814 if ( child->_prev ) {
815 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700816 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700817 if ( child->_next ) {
818 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700819 }
Lee Thomason8a763612017-06-16 09:30:16 -0700820 child->_next = 0;
821 child->_prev = 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700822 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800823}
824
825
U-Stream\Leeae25a442012-02-17 17:48:16 -0800826void XMLNode::DeleteChild( XMLNode* node )
827{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300828 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300829 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700830 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100831 Unlink( node );
Lee Thomason816d3fa2017-06-05 14:35:55 -0700832 TIXMLASSERT(node->_prev == 0);
833 TIXMLASSERT(node->_next == 0);
834 TIXMLASSERT(node->_parent == 0);
Dmitry-Mee3225b12014-09-03 11:03:11 +0400835 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800836}
837
838
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800839XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
840{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300841 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300842 if ( addThis->_document != _document ) {
843 TIXMLASSERT( false );
844 return 0;
845 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800846 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700847
Lee Thomason624d43f2012-10-12 10:58:48 -0700848 if ( _lastChild ) {
849 TIXMLASSERT( _firstChild );
850 TIXMLASSERT( _lastChild->_next == 0 );
851 _lastChild->_next = addThis;
852 addThis->_prev = _lastChild;
853 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800854
Lee Thomason624d43f2012-10-12 10:58:48 -0700855 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700856 }
857 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700858 TIXMLASSERT( _firstChild == 0 );
859 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800860
Lee Thomason624d43f2012-10-12 10:58:48 -0700861 addThis->_prev = 0;
862 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700863 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700864 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700865 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800866}
867
868
Lee Thomason1ff38e02012-02-14 18:18:16 -0800869XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
870{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300871 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300872 if ( addThis->_document != _document ) {
873 TIXMLASSERT( false );
874 return 0;
875 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800876 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700877
Lee Thomason624d43f2012-10-12 10:58:48 -0700878 if ( _firstChild ) {
879 TIXMLASSERT( _lastChild );
880 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800881
Lee Thomason624d43f2012-10-12 10:58:48 -0700882 _firstChild->_prev = addThis;
883 addThis->_next = _firstChild;
884 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800885
Lee Thomason624d43f2012-10-12 10:58:48 -0700886 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700887 }
888 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700889 TIXMLASSERT( _lastChild == 0 );
890 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800891
Lee Thomason624d43f2012-10-12 10:58:48 -0700892 addThis->_prev = 0;
893 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700894 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700895 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400896 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800897}
898
899
900XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
901{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300902 TIXMLASSERT( addThis );
903 if ( addThis->_document != _document ) {
904 TIXMLASSERT( false );
905 return 0;
906 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700907
Dmitry-Meabb2d042014-12-09 12:59:31 +0300908 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700909
Lee Thomason624d43f2012-10-12 10:58:48 -0700910 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300911 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700912 return 0;
913 }
Dmitry-Mee8f4a8b2017-09-15 19:34:36 +0300914 if ( afterThis == addThis ) {
915 // Current state: BeforeThis -> AddThis -> OneAfterAddThis
916 // Now AddThis must disappear from it's location and then
917 // reappear between BeforeThis and OneAfterAddThis.
918 // So just leave it where it is.
919 return addThis;
920 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800921
Lee Thomason624d43f2012-10-12 10:58:48 -0700922 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700923 // The last node or the only node.
924 return InsertEndChild( addThis );
925 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800926 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700927 addThis->_prev = afterThis;
928 addThis->_next = afterThis->_next;
929 afterThis->_next->_prev = addThis;
930 afterThis->_next = addThis;
931 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700932 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800933}
934
935
936
937
Dmitry-Me886ad972015-07-22 11:00:51 +0300938const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800939{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300940 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300941 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700942 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300943 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700944 }
945 }
946 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800947}
948
949
Dmitry-Me886ad972015-07-22 11:00:51 +0300950const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800951{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300952 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300953 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700954 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300955 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700956 }
957 }
958 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800959}
960
961
Dmitry-Me886ad972015-07-22 11:00:51 +0300962const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800963{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300964 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300965 const XMLElement* element = node->ToElementWithName( name );
966 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400967 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700968 }
969 }
970 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800971}
972
973
Dmitry-Me886ad972015-07-22 11:00:51 +0300974const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800975{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300976 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300977 const XMLElement* element = node->ToElementWithName( name );
978 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400979 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700980 }
981 }
982 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800983}
984
985
Dmitry-Me10b8ecc2017-04-12 17:57:44 +0300986char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -0800987{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700988 // This is a recursive method, but thinking about it "at the current level"
989 // it is a pretty simple flat list:
990 // <foo/>
991 // <!-- comment -->
992 //
993 // With a special case:
994 // <foo>
995 // </foo>
996 // <!-- comment -->
997 //
998 // Where the closing element (/foo) *must* be the next thing after the opening
999 // element, and the names must match. BUT the tricky bit is that the closing
1000 // element will be read by the child.
1001 //
1002 // 'endTag' is the end tag for this node, it is returned by a call to a child.
1003 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001004
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001005 while( p && *p ) {
1006 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -08001007
Lee Thomason624d43f2012-10-12 10:58:48 -07001008 p = _document->Identify( p, &node );
Dmitry-Me43364312016-11-07 18:48:50 +03001009 TIXMLASSERT( p );
Dmitry-Me9fcb8762015-03-05 17:53:34 +03001010 if ( node == 0 ) {
1011 break;
1012 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001013
kezenatore3531812016-11-29 19:49:07 +10001014 int initialLineNum = node->_parseLineNum;
kezenatorec694152016-11-26 17:21:43 +10001015
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001016 StrPair endTag;
kezenator4f756162016-11-29 19:46:27 +10001017 p = node->ParseDeep( p, &endTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001018 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001019 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -07001020 if ( !_document->Error() ) {
kezenatore3531812016-11-29 19:49:07 +10001021 _document->SetError( XML_ERROR_PARSING, 0, 0, initialLineNum);
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001022 }
1023 break;
1024 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001025
Sarat Addepalli3df007e2015-05-20 10:43:51 +05301026 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301027 if ( decl ) {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001028 // Declarations are only allowed at document level
1029 bool wellLocated = ( ToDocument() != 0 );
1030 if ( wellLocated ) {
1031 // Multiple declarations are allowed but all declarations
1032 // must occur before anything else
1033 for ( const XMLNode* existingNode = _document->FirstChild(); existingNode; existingNode = existingNode->NextSibling() ) {
1034 if ( !existingNode->ToDeclaration() ) {
1035 wellLocated = false;
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301036 break;
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001037 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301038 }
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001039 }
1040 if ( !wellLocated ) {
kezenatore3531812016-11-29 19:49:07 +10001041 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0, initialLineNum);
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001042 DeleteNode( node );
1043 break;
1044 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301045 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301046
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001047 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001048 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -05001049 // We read the end tag. Return it to the parent.
1050 if ( ele->ClosingType() == XMLElement::CLOSING ) {
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001051 if ( parentEndTag ) {
1052 ele->_value.TransferTo( parentEndTag );
JayXone4bf6e32014-12-26 01:00:24 -05001053 }
1054 node->_memPool->SetTracked(); // created and then immediately deleted.
1055 DeleteNode( node );
1056 return p;
1057 }
1058
1059 // Handle an end tag returned to this level.
1060 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001061 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001062 if ( endTag.Empty() ) {
1063 if ( ele->ClosingType() == XMLElement::OPEN ) {
1064 mismatch = true;
1065 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001066 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001067 else {
1068 if ( ele->ClosingType() != XMLElement::OPEN ) {
1069 mismatch = true;
1070 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001071 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001072 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001073 }
1074 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001075 if ( mismatch ) {
kezenatore3531812016-11-29 19:49:07 +10001076 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0, initialLineNum);
JayXondbfdd8f2014-12-12 20:07:14 -05001077 DeleteNode( node );
1078 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001079 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001080 }
JayXondbfdd8f2014-12-12 20:07:14 -05001081 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001082 }
1083 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001084}
1085
Lee Thomason816d3fa2017-06-05 14:35:55 -07001086/*static*/ void XMLNode::DeleteNode( XMLNode* node )
Dmitry-Mee3225b12014-09-03 11:03:11 +04001087{
1088 if ( node == 0 ) {
1089 return;
1090 }
Lee Thomason816d3fa2017-06-05 14:35:55 -07001091 TIXMLASSERT(node->_document);
1092 if (!node->ToDocument()) {
1093 node->_document->MarkInUse(node);
1094 }
1095
Dmitry-Mee3225b12014-09-03 11:03:11 +04001096 MemPool* pool = node->_memPool;
1097 node->~XMLNode();
1098 pool->Free( node );
1099}
1100
Lee Thomason3cebdc42015-01-05 17:16:28 -08001101void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001102{
1103 TIXMLASSERT( insertThis );
1104 TIXMLASSERT( insertThis->_document == _document );
1105
Lee Thomason816d3fa2017-06-05 14:35:55 -07001106 if (insertThis->_parent) {
Dmitry-Me74e39402015-01-01 16:26:17 +03001107 insertThis->_parent->Unlink( insertThis );
Lee Thomason816d3fa2017-06-05 14:35:55 -07001108 }
1109 else {
1110 insertThis->_document->MarkInUse(insertThis);
Dmitry-Me74e39402015-01-01 16:26:17 +03001111 insertThis->_memPool->SetTracked();
Lee Thomason816d3fa2017-06-05 14:35:55 -07001112 }
Dmitry-Me74e39402015-01-01 16:26:17 +03001113}
1114
Dmitry-Meecb9b072016-10-12 16:44:59 +03001115const XMLElement* XMLNode::ToElementWithName( const char* name ) const
1116{
1117 const XMLElement* element = this->ToElement();
1118 if ( element == 0 ) {
1119 return 0;
1120 }
1121 if ( name == 0 ) {
1122 return element;
1123 }
1124 if ( XMLUtil::StringEqual( element->Name(), name ) ) {
1125 return element;
1126 }
1127 return 0;
1128}
1129
Lee Thomason5492a1c2012-01-23 15:32:10 -08001130// --------- XMLText ---------- //
kezenator4f756162016-11-29 19:46:27 +10001131char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001132{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001133 const char* start = p;
1134 if ( this->CData() ) {
kezenator4f756162016-11-29 19:46:27 +10001135 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001136 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001137 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001138 }
1139 return p;
1140 }
1141 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001142 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1143 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001144 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001145 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001146
kezenator4f756162016-11-29 19:46:27 +10001147 p = _value.ParseText( p, "<", flags, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001148 if ( p && *p ) {
1149 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001150 }
1151 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001152 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001153 }
1154 }
1155 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001156}
1157
1158
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001159XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1160{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001161 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001162 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001163 }
1164 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1165 text->SetCData( this->CData() );
1166 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001167}
1168
1169
1170bool XMLText::ShallowEqual( const XMLNode* compare ) const
1171{
Dmitry-Meba68a3a2017-03-21 11:39:48 +03001172 TIXMLASSERT( compare );
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001173 const XMLText* text = compare->ToText();
1174 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001175}
1176
1177
Lee Thomason56bdd022012-02-09 18:16:58 -08001178bool XMLText::Accept( XMLVisitor* visitor ) const
1179{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001180 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001181 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001182}
1183
1184
Lee Thomason3f57d272012-01-11 15:30:03 -08001185// --------- XMLComment ---------- //
1186
Lee Thomasone4422302012-01-20 17:59:50 -08001187XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001188{
1189}
1190
1191
Lee Thomasonce0763e2012-01-11 15:43:54 -08001192XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001193{
Lee Thomason3f57d272012-01-11 15:30:03 -08001194}
1195
1196
kezenator4f756162016-11-29 19:46:27 +10001197char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason3f57d272012-01-11 15:30:03 -08001198{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001199 // Comment parses as text.
1200 const char* start = p;
kezenator4f756162016-11-29 19:46:27 +10001201 p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001202 if ( p == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10001203 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001204 }
1205 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001206}
1207
1208
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001209XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1210{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001211 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001212 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001213 }
1214 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1215 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001216}
1217
1218
1219bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1220{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001221 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001222 const XMLComment* comment = compare->ToComment();
1223 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001224}
1225
1226
Lee Thomason751da522012-02-10 08:50:51 -08001227bool XMLComment::Accept( XMLVisitor* visitor ) const
1228{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001229 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001230 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001231}
Lee Thomason56bdd022012-02-09 18:16:58 -08001232
1233
Lee Thomason50f97b22012-02-11 16:33:40 -08001234// --------- XMLDeclaration ---------- //
1235
1236XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1237{
1238}
1239
1240
1241XMLDeclaration::~XMLDeclaration()
1242{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001243 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001244}
1245
1246
kezenator4f756162016-11-29 19:46:27 +10001247char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001248{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001249 // Declaration parses as text.
1250 const char* start = p;
kezenator4f756162016-11-29 19:46:27 +10001251 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001252 if ( p == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10001253 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001254 }
1255 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001256}
1257
1258
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001259XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1260{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001261 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001262 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001263 }
1264 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1265 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001266}
1267
1268
1269bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1270{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001271 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001272 const XMLDeclaration* declaration = compare->ToDeclaration();
1273 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001274}
1275
1276
1277
Lee Thomason50f97b22012-02-11 16:33:40 -08001278bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1279{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001280 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001281 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001282}
1283
1284// --------- XMLUnknown ---------- //
1285
1286XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1287{
1288}
1289
1290
1291XMLUnknown::~XMLUnknown()
1292{
1293}
1294
1295
kezenator4f756162016-11-29 19:46:27 +10001296char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001297{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001298 // Unknown parses as text.
1299 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001300
kezenator4f756162016-11-29 19:46:27 +10001301 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001302 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001303 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001304 }
1305 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001306}
1307
1308
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001309XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1310{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001311 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001312 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001313 }
1314 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1315 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001316}
1317
1318
1319bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1320{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001321 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001322 const XMLUnknown* unknown = compare->ToUnknown();
1323 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001324}
1325
1326
Lee Thomason50f97b22012-02-11 16:33:40 -08001327bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1328{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001329 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001330 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001331}
1332
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001333// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001334
1335const char* XMLAttribute::Name() const
1336{
1337 return _name.GetStr();
1338}
1339
1340const char* XMLAttribute::Value() const
1341{
1342 return _value.GetStr();
1343}
1344
kezenator4f756162016-11-29 19:46:27 +10001345char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001346{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001347 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001348 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001349 if ( !p || !*p ) {
1350 return 0;
1351 }
Lee Thomason22aead12012-01-23 13:29:35 -08001352
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001353 // Skip white space before =
kezenator4f756162016-11-29 19:46:27 +10001354 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001355 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001356 return 0;
1357 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001358
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001359 ++p; // move up to opening quote
kezenator4f756162016-11-29 19:46:27 +10001360 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001361 if ( *p != '\"' && *p != '\'' ) {
1362 return 0;
1363 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001364
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001365 char endTag[2] = { *p, 0 };
1366 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001367
kezenator4f756162016-11-29 19:46:27 +10001368 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001369 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001370}
1371
1372
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001373void XMLAttribute::SetName( const char* n )
1374{
Lee Thomason624d43f2012-10-12 10:58:48 -07001375 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001376}
1377
1378
Lee Thomason2fa81722012-11-09 12:37:46 -08001379XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001380{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001381 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001382 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001383 }
1384 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001385}
1386
1387
Lee Thomason2fa81722012-11-09 12:37:46 -08001388XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001389{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001390 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001391 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001392 }
1393 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001394}
1395
1396
Lee Thomason51c12712016-06-04 20:18:49 -07001397XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1398{
1399 if (XMLUtil::ToInt64(Value(), value)) {
1400 return XML_SUCCESS;
1401 }
1402 return XML_WRONG_ATTRIBUTE_TYPE;
1403}
1404
1405
Lee Thomason2fa81722012-11-09 12:37:46 -08001406XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001407{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001408 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001409 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001410 }
1411 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001412}
1413
1414
Lee Thomason2fa81722012-11-09 12:37:46 -08001415XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001416{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001417 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001418 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001419 }
1420 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001421}
1422
1423
Lee Thomason2fa81722012-11-09 12:37:46 -08001424XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001425{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001426 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001427 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001428 }
1429 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001430}
1431
1432
1433void XMLAttribute::SetAttribute( const char* v )
1434{
Lee Thomason624d43f2012-10-12 10:58:48 -07001435 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001436}
1437
1438
Lee Thomason1ff38e02012-02-14 18:18:16 -08001439void XMLAttribute::SetAttribute( int v )
1440{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001441 char buf[BUF_SIZE];
1442 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001443 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001444}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001445
1446
1447void XMLAttribute::SetAttribute( unsigned v )
1448{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001449 char buf[BUF_SIZE];
1450 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001451 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001452}
1453
1454
Lee Thomason51c12712016-06-04 20:18:49 -07001455void XMLAttribute::SetAttribute(int64_t v)
1456{
1457 char buf[BUF_SIZE];
1458 XMLUtil::ToStr(v, buf, BUF_SIZE);
1459 _value.SetStr(buf);
1460}
1461
1462
1463
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001464void XMLAttribute::SetAttribute( bool v )
1465{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001466 char buf[BUF_SIZE];
1467 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001468 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001469}
1470
1471void XMLAttribute::SetAttribute( double v )
1472{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001473 char buf[BUF_SIZE];
1474 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001475 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001476}
1477
1478void XMLAttribute::SetAttribute( float v )
1479{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001480 char buf[BUF_SIZE];
1481 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001482 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001483}
1484
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001485
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001486// --------- XMLElement ---------- //
1487XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Dmitry-Mee5035632017-04-05 18:02:40 +03001488 _closingType( OPEN ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001489 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001490{
1491}
1492
1493
1494XMLElement::~XMLElement()
1495{
Lee Thomason624d43f2012-10-12 10:58:48 -07001496 while( _rootAttribute ) {
1497 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001498 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001499 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001500 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001501}
1502
1503
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001504const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1505{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001506 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001507 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1508 return a;
1509 }
1510 }
1511 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001512}
1513
1514
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001515const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001516{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001517 const XMLAttribute* a = FindAttribute( name );
1518 if ( !a ) {
1519 return 0;
1520 }
1521 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1522 return a->Value();
1523 }
1524 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001525}
1526
Josh Wittnercf3dd092016-10-11 18:57:17 -07001527int XMLElement::IntAttribute(const char* name, int defaultValue) const
1528{
1529 int i = defaultValue;
1530 QueryIntAttribute(name, &i);
1531 return i;
1532}
1533
1534unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
1535{
1536 unsigned i = defaultValue;
1537 QueryUnsignedAttribute(name, &i);
1538 return i;
1539}
1540
1541int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
1542{
1543 int64_t i = defaultValue;
1544 QueryInt64Attribute(name, &i);
1545 return i;
1546}
1547
1548bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
1549{
1550 bool b = defaultValue;
1551 QueryBoolAttribute(name, &b);
1552 return b;
1553}
1554
1555double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
1556{
1557 double d = defaultValue;
1558 QueryDoubleAttribute(name, &d);
1559 return d;
1560}
1561
1562float XMLElement::FloatAttribute(const char* name, float defaultValue) const
1563{
1564 float f = defaultValue;
1565 QueryFloatAttribute(name, &f);
1566 return f;
1567}
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001568
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001569const char* XMLElement::GetText() const
1570{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001571 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001572 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001573 }
1574 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001575}
1576
1577
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001578void XMLElement::SetText( const char* inText )
1579{
Uli Kusterer869bb592014-01-21 01:36:16 +01001580 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001581 FirstChild()->SetValue( inText );
1582 else {
1583 XMLText* theText = GetDocument()->NewText( inText );
1584 InsertFirstChild( theText );
1585 }
1586}
1587
Lee Thomason5bb2d802014-01-24 10:42:57 -08001588
1589void XMLElement::SetText( int v )
1590{
1591 char buf[BUF_SIZE];
1592 XMLUtil::ToStr( v, buf, BUF_SIZE );
1593 SetText( buf );
1594}
1595
1596
1597void XMLElement::SetText( unsigned v )
1598{
1599 char buf[BUF_SIZE];
1600 XMLUtil::ToStr( v, buf, BUF_SIZE );
1601 SetText( buf );
1602}
1603
1604
Lee Thomason51c12712016-06-04 20:18:49 -07001605void XMLElement::SetText(int64_t v)
1606{
1607 char buf[BUF_SIZE];
1608 XMLUtil::ToStr(v, buf, BUF_SIZE);
1609 SetText(buf);
1610}
1611
1612
1613void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001614{
1615 char buf[BUF_SIZE];
1616 XMLUtil::ToStr( v, buf, BUF_SIZE );
1617 SetText( buf );
1618}
1619
1620
1621void XMLElement::SetText( float v )
1622{
1623 char buf[BUF_SIZE];
1624 XMLUtil::ToStr( v, buf, BUF_SIZE );
1625 SetText( buf );
1626}
1627
1628
1629void XMLElement::SetText( double v )
1630{
1631 char buf[BUF_SIZE];
1632 XMLUtil::ToStr( v, buf, BUF_SIZE );
1633 SetText( buf );
1634}
1635
1636
MortenMacFly4ee49f12013-01-14 20:03:14 +01001637XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001638{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001639 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001640 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001641 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001642 return XML_SUCCESS;
1643 }
1644 return XML_CAN_NOT_CONVERT_TEXT;
1645 }
1646 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001647}
1648
1649
MortenMacFly4ee49f12013-01-14 20:03:14 +01001650XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001651{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001652 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001653 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001654 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001655 return XML_SUCCESS;
1656 }
1657 return XML_CAN_NOT_CONVERT_TEXT;
1658 }
1659 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001660}
1661
1662
Lee Thomason51c12712016-06-04 20:18:49 -07001663XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1664{
1665 if (FirstChild() && FirstChild()->ToText()) {
1666 const char* t = FirstChild()->Value();
1667 if (XMLUtil::ToInt64(t, ival)) {
1668 return XML_SUCCESS;
1669 }
1670 return XML_CAN_NOT_CONVERT_TEXT;
1671 }
1672 return XML_NO_TEXT_NODE;
1673}
1674
1675
MortenMacFly4ee49f12013-01-14 20:03:14 +01001676XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001677{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001678 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001679 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001680 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001681 return XML_SUCCESS;
1682 }
1683 return XML_CAN_NOT_CONVERT_TEXT;
1684 }
1685 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001686}
1687
1688
MortenMacFly4ee49f12013-01-14 20:03:14 +01001689XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001690{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001691 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001692 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001693 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001694 return XML_SUCCESS;
1695 }
1696 return XML_CAN_NOT_CONVERT_TEXT;
1697 }
1698 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001699}
1700
1701
MortenMacFly4ee49f12013-01-14 20:03:14 +01001702XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001703{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001704 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001705 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001706 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001707 return XML_SUCCESS;
1708 }
1709 return XML_CAN_NOT_CONVERT_TEXT;
1710 }
1711 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001712}
1713
Josh Wittnercf3dd092016-10-11 18:57:17 -07001714int XMLElement::IntText(int defaultValue) const
1715{
1716 int i = defaultValue;
1717 QueryIntText(&i);
1718 return i;
1719}
1720
1721unsigned XMLElement::UnsignedText(unsigned defaultValue) const
1722{
1723 unsigned i = defaultValue;
1724 QueryUnsignedText(&i);
1725 return i;
1726}
1727
1728int64_t XMLElement::Int64Text(int64_t defaultValue) const
1729{
1730 int64_t i = defaultValue;
1731 QueryInt64Text(&i);
1732 return i;
1733}
1734
1735bool XMLElement::BoolText(bool defaultValue) const
1736{
1737 bool b = defaultValue;
1738 QueryBoolText(&b);
1739 return b;
1740}
1741
1742double XMLElement::DoubleText(double defaultValue) const
1743{
1744 double d = defaultValue;
1745 QueryDoubleText(&d);
1746 return d;
1747}
1748
1749float XMLElement::FloatText(float defaultValue) const
1750{
1751 float f = defaultValue;
1752 QueryFloatText(&f);
1753 return f;
1754}
Lee Thomason21be8822012-07-15 17:27:22 -07001755
1756
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001757XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1758{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001759 XMLAttribute* last = 0;
1760 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001761 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001762 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001763 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001764 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1765 break;
1766 }
1767 }
1768 if ( !attrib ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001769 attrib = CreateAttribute();
1770 TIXMLASSERT( attrib );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001771 if ( last ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001772 TIXMLASSERT( last->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001773 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001774 }
1775 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001776 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001777 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001778 }
1779 attrib->SetName( name );
1780 }
1781 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001782}
1783
1784
U-Stream\Leeae25a442012-02-17 17:48:16 -08001785void XMLElement::DeleteAttribute( const char* name )
1786{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001787 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001788 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001789 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1790 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001791 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001792 }
1793 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001794 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001795 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001796 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001797 break;
1798 }
1799 prev = a;
1800 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001801}
1802
1803
kezenator4f756162016-11-29 19:46:27 +10001804char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001805{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001806 const char* start = p;
1807 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001808
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001809 // Read the attributes.
1810 while( p ) {
kezenator4f756162016-11-29 19:46:27 +10001811 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001812 if ( !(*p) ) {
kezenatorec694152016-11-26 17:21:43 +10001813 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name(), _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001814 return 0;
1815 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001816
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001817 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001818 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001819 XMLAttribute* attrib = CreateAttribute();
1820 TIXMLASSERT( attrib );
kezenatorec694152016-11-26 17:21:43 +10001821 attrib->_parseLineNum = _document->_parseCurLineNum;
Lee Thomasond1983222012-02-06 08:41:24 -08001822
kezenatorec694152016-11-26 17:21:43 +10001823 int attrLineNum = attrib->_parseLineNum;
1824
kezenator4f756162016-11-29 19:46:27 +10001825 p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001826 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001827 DeleteAttribute( attrib );
kezenatorec694152016-11-26 17:21:43 +10001828 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p, attrLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001829 return 0;
1830 }
1831 // There is a minor bug here: if the attribute in the source xml
1832 // document is duplicated, it will not be detected and the
1833 // attribute will be doubly added. However, tracking the 'prevAttribute'
1834 // avoids re-scanning the attribute list. Preferring performance for
1835 // now, may reconsider in the future.
1836 if ( prevAttribute ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001837 TIXMLASSERT( prevAttribute->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001838 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001839 }
1840 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001841 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001842 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001843 }
1844 prevAttribute = attrib;
1845 }
1846 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001847 else if ( *p == '>' ) {
1848 ++p;
1849 break;
1850 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001851 // end of the tag
1852 else if ( *p == '/' && *(p+1) == '>' ) {
1853 _closingType = CLOSED;
1854 return p+2; // done; sealed element.
1855 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001856 else {
kezenatorec694152016-11-26 17:21:43 +10001857 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001858 return 0;
1859 }
1860 }
1861 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001862}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001863
Dmitry-Mee3225b12014-09-03 11:03:11 +04001864void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1865{
1866 if ( attribute == 0 ) {
1867 return;
1868 }
1869 MemPool* pool = attribute->_memPool;
1870 attribute->~XMLAttribute();
1871 pool->Free( attribute );
1872}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001873
Dmitry-Mea60caa22016-11-22 18:28:08 +03001874XMLAttribute* XMLElement::CreateAttribute()
1875{
1876 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
1877 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
Dmitry-Me7221b492017-03-03 15:45:51 +03001878 TIXMLASSERT( attrib );
Dmitry-Mea60caa22016-11-22 18:28:08 +03001879 attrib->_memPool = &_document->_attributePool;
1880 attrib->_memPool->SetTracked();
1881 return attrib;
1882}
1883
Lee Thomason67d61312012-01-24 16:01:51 -08001884//
1885// <ele></ele>
1886// <ele>foo<b>bar</b></ele>
1887//
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001888char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -08001889{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001890 // Read the element name.
kezenator4f756162016-11-29 19:46:27 +10001891 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomason67d61312012-01-24 16:01:51 -08001892
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001893 // The closing element is the </element> form. It is
1894 // parsed just like a regular element then deleted from
1895 // the DOM.
1896 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001897 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001898 ++p;
1899 }
Lee Thomason67d61312012-01-24 16:01:51 -08001900
Lee Thomason624d43f2012-10-12 10:58:48 -07001901 p = _value.ParseName( p );
1902 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001903 return 0;
1904 }
Lee Thomason67d61312012-01-24 16:01:51 -08001905
kezenator4f756162016-11-29 19:46:27 +10001906 p = ParseAttributes( p, curLineNumPtr );
Dmitry-Mee5035632017-04-05 18:02:40 +03001907 if ( !p || !*p || _closingType != OPEN ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001908 return p;
1909 }
Lee Thomason67d61312012-01-24 16:01:51 -08001910
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001911 p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001912 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001913}
1914
1915
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001916
1917XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1918{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001919 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001920 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001921 }
1922 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1923 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1924 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1925 }
1926 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001927}
1928
1929
1930bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1931{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001932 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001933 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001934 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001935
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001936 const XMLAttribute* a=FirstAttribute();
1937 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001938
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001939 while ( a && b ) {
1940 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1941 return false;
1942 }
1943 a = a->Next();
1944 b = b->Next();
1945 }
1946 if ( a || b ) {
1947 // different count
1948 return false;
1949 }
1950 return true;
1951 }
1952 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001953}
1954
1955
Lee Thomason751da522012-02-10 08:50:51 -08001956bool XMLElement::Accept( XMLVisitor* visitor ) const
1957{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001958 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001959 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001960 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1961 if ( !node->Accept( visitor ) ) {
1962 break;
1963 }
1964 }
1965 }
1966 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001967}
Lee Thomason56bdd022012-02-09 18:16:58 -08001968
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001969
Lee Thomason3f57d272012-01-11 15:30:03 -08001970// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001971
1972// Warning: List must match 'enum XMLError'
1973const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1974 "XML_SUCCESS",
1975 "XML_NO_ATTRIBUTE",
1976 "XML_WRONG_ATTRIBUTE_TYPE",
1977 "XML_ERROR_FILE_NOT_FOUND",
1978 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1979 "XML_ERROR_FILE_READ_ERROR",
Lee Thomason8bba8b42017-06-20 09:18:41 -07001980 "UNUSED_XML_ERROR_ELEMENT_MISMATCH",
Lee Thomason331596e2014-09-11 14:56:43 -07001981 "XML_ERROR_PARSING_ELEMENT",
1982 "XML_ERROR_PARSING_ATTRIBUTE",
Lee Thomason8bba8b42017-06-20 09:18:41 -07001983 "UNUSED_XML_ERROR_IDENTIFYING_TAG",
Lee Thomason331596e2014-09-11 14:56:43 -07001984 "XML_ERROR_PARSING_TEXT",
1985 "XML_ERROR_PARSING_CDATA",
1986 "XML_ERROR_PARSING_COMMENT",
1987 "XML_ERROR_PARSING_DECLARATION",
1988 "XML_ERROR_PARSING_UNKNOWN",
1989 "XML_ERROR_EMPTY_DOCUMENT",
1990 "XML_ERROR_MISMATCHED_ELEMENT",
1991 "XML_ERROR_PARSING",
1992 "XML_CAN_NOT_CONVERT_TEXT",
1993 "XML_NO_TEXT_NODE"
1994};
1995
1996
Dmitry-Meae8a82a2017-03-03 15:40:32 +03001997XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001998 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001999 _writeBOM( false ),
2000 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07002001 _errorID(XML_SUCCESS),
Dmitry-Meae8a82a2017-03-03 15:40:32 +03002002 _whitespaceMode( whitespaceMode ),
Dmitry-Mef89bd3e2017-01-18 18:33:55 +03002003 _errorLineNum( 0 ),
2004 _charBuffer( 0 ),
2005 _parseCurLineNum( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08002006{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03002007 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
2008 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08002009}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002010
2011
Lee Thomason3f57d272012-01-11 15:30:03 -08002012XMLDocument::~XMLDocument()
2013{
Lee Thomasonf07b9522014-10-30 13:25:12 -07002014 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08002015}
2016
2017
Lee Thomason816d3fa2017-06-05 14:35:55 -07002018void XMLDocument::MarkInUse(XMLNode* node)
2019{
Dmitry-Mec2f677b2017-06-15 12:44:27 +03002020 TIXMLASSERT(node);
Lee Thomason816d3fa2017-06-05 14:35:55 -07002021 TIXMLASSERT(node->_parent == 0);
2022
2023 for (int i = 0; i < _unlinked.Size(); ++i) {
2024 if (node == _unlinked[i]) {
2025 _unlinked.SwapRemove(i);
2026 break;
2027 }
2028 }
2029}
2030
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002031void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08002032{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002033 DeleteChildren();
Lee Thomason816d3fa2017-06-05 14:35:55 -07002034 while( _unlinked.Size()) {
2035 DeleteNode(_unlinked[0]); // Will remove from _unlinked as part of delete.
2036 }
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002037
Dmitry-Meab37df82014-11-28 12:08:36 +03002038#ifdef DEBUG
2039 const bool hadError = Error();
2040#endif
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002041 ClearError();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002042
Lee Thomason624d43f2012-10-12 10:58:48 -07002043 delete [] _charBuffer;
2044 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07002045
2046#if 0
2047 _textPool.Trace( "text" );
2048 _elementPool.Trace( "element" );
2049 _commentPool.Trace( "comment" );
2050 _attributePool.Trace( "attribute" );
2051#endif
2052
2053#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002054 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002055 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
2056 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
2057 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
2058 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
2059 }
2060#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08002061}
2062
Lee Thomason3f57d272012-01-11 15:30:03 -08002063
Shuichiro Suzuki87cd4e02017-08-24 11:20:26 +09002064void XMLDocument::DeepCopy(XMLDocument* target) const
Lee Thomason7085f002017-06-01 18:09:43 -07002065{
2066 TIXMLASSERT(target);
Lee Thomason1346a172017-06-14 15:14:19 -07002067 if (target == this) {
2068 return; // technically success - a no-op.
2069 }
Lee Thomason7085f002017-06-01 18:09:43 -07002070
2071 target->Clear();
2072 for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {
2073 target->InsertEndChild(node->DeepClone(target));
2074 }
2075}
2076
Lee Thomason2c85a712012-01-31 08:24:24 -08002077XMLElement* XMLDocument::NewElement( const char* name )
2078{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002079 XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002080 ele->SetName( name );
2081 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08002082}
2083
2084
Lee Thomason1ff38e02012-02-14 18:18:16 -08002085XMLComment* XMLDocument::NewComment( const char* str )
2086{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002087 XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002088 comment->SetValue( str );
2089 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002090}
2091
2092
2093XMLText* XMLDocument::NewText( const char* str )
2094{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002095 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002096 text->SetValue( str );
2097 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002098}
2099
2100
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002101XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2102{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002103 XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002104 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2105 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002106}
2107
2108
2109XMLUnknown* XMLDocument::NewUnknown( const char* str )
2110{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002111 XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002112 unk->SetValue( str );
2113 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002114}
2115
Dmitry-Me01578db2014-08-19 10:18:48 +04002116static FILE* callfopen( const char* filepath, const char* mode )
2117{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002118 TIXMLASSERT( filepath );
2119 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002120#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2121 FILE* fp = 0;
2122 errno_t err = fopen_s( &fp, filepath, mode );
2123 if ( err ) {
2124 return 0;
2125 }
2126#else
2127 FILE* fp = fopen( filepath, mode );
2128#endif
2129 return fp;
2130}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08002131
2132void XMLDocument::DeleteNode( XMLNode* node ) {
2133 TIXMLASSERT( node );
2134 TIXMLASSERT(node->_document == this );
2135 if (node->_parent) {
2136 node->_parent->DeleteChild( node );
2137 }
2138 else {
2139 // Isn't in the tree.
2140 // Use the parent delete.
2141 // Also, we need to mark it tracked: we 'know'
2142 // it was never used.
2143 node->_memPool->SetTracked();
2144 // Call the static XMLNode version:
2145 XMLNode::DeleteNode(node);
2146 }
2147}
2148
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002149
Lee Thomason2fa81722012-11-09 12:37:46 -08002150XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002151{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002152 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04002153 FILE* fp = callfopen( filename, "rb" );
2154 if ( !fp ) {
kezenatorec694152016-11-26 17:21:43 +10002155 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002156 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002157 }
2158 LoadFile( fp );
2159 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002160 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002161}
2162
Dmitry-Me901fed52015-09-25 10:29:51 +03002163// This is likely overengineered template art to have a check that unsigned long value incremented
2164// by one still fits into size_t. If size_t type is larger than unsigned long type
2165// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
2166// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
2167// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
2168// types sizes relate to each other.
2169template
2170<bool = (sizeof(unsigned long) >= sizeof(size_t))>
2171struct LongFitsIntoSizeTMinusOne {
2172 static bool Fits( unsigned long value )
2173 {
2174 return value < (size_t)-1;
2175 }
2176};
2177
2178template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02002179struct LongFitsIntoSizeTMinusOne<false> {
2180 static bool Fits( unsigned long )
2181 {
2182 return true;
2183 }
2184};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002185
Lee Thomason2fa81722012-11-09 12:37:46 -08002186XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002187{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002188 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002189
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002190 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002191 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
kezenatorec694152016-11-26 17:21:43 +10002192 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002193 return _errorID;
2194 }
2195
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002196 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002197 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002198 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002199 if ( filelength == -1L ) {
kezenatorec694152016-11-26 17:21:43 +10002200 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002201 return _errorID;
2202 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002203 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002204
Dmitry-Me901fed52015-09-25 10:29:51 +03002205 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002206 // Cannot handle files which won't fit in buffer together with null terminator
kezenatorec694152016-11-26 17:21:43 +10002207 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002208 return _errorID;
2209 }
2210
Dmitry-Me72801b82015-05-07 09:41:39 +03002211 if ( filelength == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10002212 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002213 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002214 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002215
Dmitry-Me72801b82015-05-07 09:41:39 +03002216 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002217 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002218 _charBuffer = new char[size+1];
2219 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002220 if ( read != size ) {
kezenatorec694152016-11-26 17:21:43 +10002221 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002222 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002223 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002224
Lee Thomason624d43f2012-10-12 10:58:48 -07002225 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002226
Dmitry-Me97476b72015-01-01 16:15:57 +03002227 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002228 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002229}
2230
2231
Lee Thomason2fa81722012-11-09 12:37:46 -08002232XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002233{
Dmitry-Me01578db2014-08-19 10:18:48 +04002234 FILE* fp = callfopen( filename, "w" );
2235 if ( !fp ) {
kezenatorec694152016-11-26 17:21:43 +10002236 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002237 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002238 }
2239 SaveFile(fp, compact);
2240 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002241 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002242}
2243
2244
Lee Thomason2fa81722012-11-09 12:37:46 -08002245XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002246{
Ant Mitchell189198f2015-03-24 16:20:36 +00002247 // Clear any error from the last save, otherwise it will get reported
2248 // for *this* call.
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002249 ClearError();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002250 XMLPrinter stream( fp, compact );
2251 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002252 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002253}
2254
Lee Thomason1ff38e02012-02-14 18:18:16 -08002255
Lee Thomason2fa81722012-11-09 12:37:46 -08002256XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002257{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002258 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002259
Lee Thomason82d32002014-02-21 22:47:18 -08002260 if ( len == 0 || !p || !*p ) {
kezenatorec694152016-11-26 17:21:43 +10002261 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002262 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002263 }
2264 if ( len == (size_t)(-1) ) {
2265 len = strlen( p );
2266 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002267 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002268 _charBuffer = new char[ len+1 ];
2269 memcpy( _charBuffer, p, len );
2270 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002271
Dmitry-Me97476b72015-01-01 16:15:57 +03002272 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002273 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002274 // clean up now essentially dangling memory.
2275 // and the parse fail can put objects in the
2276 // pools that are dead and inaccessible.
2277 DeleteChildren();
2278 _elementPool.Clear();
2279 _attributePool.Clear();
2280 _textPool.Clear();
2281 _commentPool.Clear();
2282 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002283 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002284}
2285
2286
PKEuS1c5f99e2013-07-06 11:28:39 +02002287void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002288{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002289 if ( streamer ) {
2290 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002291 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002292 else {
2293 XMLPrinter stdoutStreamer( stdout );
2294 Accept( &stdoutStreamer );
2295 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002296}
2297
2298
kezenatorec694152016-11-26 17:21:43 +10002299void XMLDocument::SetError( XMLError error, const char* str1, const char* str2, int lineNum )
Lee Thomason67d61312012-01-24 16:01:51 -08002300{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002301 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002302 _errorID = error;
Lee Thomason584af572016-09-05 14:14:16 -07002303
2304 _errorStr1.Reset();
2305 _errorStr2.Reset();
kezenatorec694152016-11-26 17:21:43 +10002306 _errorLineNum = lineNum;
Lee Thomason584af572016-09-05 14:14:16 -07002307
2308 if (str1)
2309 _errorStr1.SetStr(str1);
2310 if (str2)
2311 _errorStr2.SetStr(str2);
Lee Thomason67d61312012-01-24 16:01:51 -08002312}
2313
Lee Thomasone90e9012016-12-24 07:34:39 -08002314/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
Lee Thomason331596e2014-09-11 14:56:43 -07002315{
kezenator5a700712016-11-26 13:54:42 +10002316 TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2317 const char* errorName = _errorNames[errorID];
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002318 TIXMLASSERT( errorName && errorName[0] );
2319 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002320}
Lee Thomason5cae8972012-01-24 18:03:07 -08002321
Lee Thomason8c9e3132017-06-26 16:55:01 -07002322const char* XMLDocument::GetErrorStr1() const
2323{
2324 return _errorStr1.GetStr();
2325}
2326
2327const char* XMLDocument::GetErrorStr2() const
2328{
2329 return _errorStr2.GetStr();
2330}
2331
kezenator5a700712016-11-26 13:54:42 +10002332const char* XMLDocument::ErrorName() const
2333{
Lee Thomasone90e9012016-12-24 07:34:39 -08002334 return ErrorIDToName(_errorID);
kezenator5a700712016-11-26 13:54:42 +10002335}
2336
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002337void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002338{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002339 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002340 static const int LEN = 20;
2341 char buf1[LEN] = { 0 };
2342 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002343
Lee Thomason584af572016-09-05 14:14:16 -07002344 if ( !_errorStr1.Empty() ) {
2345 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002346 }
Lee Thomason584af572016-09-05 14:14:16 -07002347 if ( !_errorStr2.Empty() ) {
2348 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002349 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002350
Dmitry-Me2ad43202015-04-16 12:18:58 +03002351 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2352 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2353 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
kezenatorec694152016-11-26 17:21:43 +10002354 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s line=%d\n",
2355 static_cast<int>( _errorID ), ErrorName(), buf1, buf2, _errorLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002356 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002357}
2358
Dmitry-Me97476b72015-01-01 16:15:57 +03002359void XMLDocument::Parse()
2360{
2361 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2362 TIXMLASSERT( _charBuffer );
kezenatorec694152016-11-26 17:21:43 +10002363 _parseCurLineNum = 1;
2364 _parseLineNum = 1;
Lee Thomason3cebdc42015-01-05 17:16:28 -08002365 char* p = _charBuffer;
kezenator4f756162016-11-29 19:46:27 +10002366 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mee28be752015-01-09 14:59:30 +03002367 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002368 if ( !*p ) {
kezenatorec694152016-11-26 17:21:43 +10002369 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002370 return;
2371 }
kezenator4f756162016-11-29 19:46:27 +10002372 ParseDeep(p, 0, &_parseCurLineNum );
Dmitry-Me97476b72015-01-01 16:15:57 +03002373}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002374
PKEuS1bfb9542013-08-04 13:51:17 +02002375XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002376 _elementJustOpened( false ),
2377 _firstElement( true ),
2378 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002379 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002380 _textDepth( -1 ),
2381 _processEntities( true ),
2382 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002383{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002384 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002385 _entityFlag[i] = false;
2386 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002387 }
2388 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002389 const char entityValue = entities[i].value;
Dmitry-Mea28eb072017-08-25 18:34:18 +03002390 const unsigned char flagIndex = (unsigned char)entityValue;
2391 TIXMLASSERT( flagIndex < ENTITY_RANGE );
2392 _entityFlag[flagIndex] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002393 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002394 _restrictedEntityFlag[(unsigned char)'&'] = true;
2395 _restrictedEntityFlag[(unsigned char)'<'] = true;
2396 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002397 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002398}
2399
2400
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002401void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002402{
2403 va_list va;
2404 va_start( va, format );
2405
Lee Thomason624d43f2012-10-12 10:58:48 -07002406 if ( _fp ) {
2407 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002408 }
2409 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002410 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002411 // Close out and re-start the va-args
2412 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002413 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002414 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002415 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002416 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002417 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002418 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002419 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002420}
2421
2422
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002423void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002424{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002425 for( int i=0; i<depth; ++i ) {
2426 Print( " " );
2427 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002428}
2429
2430
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002431void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002432{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002433 // Look for runs of bytes between entities to print.
2434 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002435
Lee Thomason624d43f2012-10-12 10:58:48 -07002436 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002437 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002438 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002439 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002440 // Remember, char is sometimes signed. (How many times has that bitten me?)
2441 if ( *q > 0 && *q < ENTITY_RANGE ) {
2442 // Check for entities. If one is found, flush
2443 // the stream up until the entity, write the
2444 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002445 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002446 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002447 const size_t delta = q - p;
2448 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002449 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002450 Print( "%.*s", toPrint, p );
2451 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002452 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002453 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002454 for( int i=0; i<NUM_ENTITIES; ++i ) {
2455 if ( entities[i].value == *q ) {
2456 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002457 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002458 break;
2459 }
2460 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002461 if ( !entityPatternPrinted ) {
2462 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2463 TIXMLASSERT( false );
2464 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002465 ++p;
2466 }
2467 }
2468 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002469 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002470 }
2471 }
2472 // Flush the remaining string. This will be the entire
2473 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002474 TIXMLASSERT( p <= q );
2475 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002476 Print( "%s", p );
2477 }
Lee Thomason857b8682012-01-25 17:50:25 -08002478}
2479
U-Stream\Leeae25a442012-02-17 17:48:16 -08002480
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002481void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002482{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002483 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002484 static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002485 Print( "%s", bom );
2486 }
2487 if ( writeDec ) {
2488 PushDeclaration( "xml version=\"1.0\"" );
2489 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002490}
2491
2492
Uli Kusterer593a33d2014-02-01 12:48:51 +01002493void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002494{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002495 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002496 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002497
Uli Kusterer593a33d2014-02-01 12:48:51 +01002498 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002499 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002500 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002501 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002502 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002503 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002504
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002505 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002506 _elementJustOpened = true;
2507 _firstElement = false;
2508 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002509}
2510
2511
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002512void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002513{
Lee Thomason624d43f2012-10-12 10:58:48 -07002514 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002515 Print( " %s=\"", name );
2516 PrintString( value, false );
2517 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002518}
2519
2520
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002521void XMLPrinter::PushAttribute( const char* name, int v )
2522{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002523 char buf[BUF_SIZE];
2524 XMLUtil::ToStr( v, buf, BUF_SIZE );
2525 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002526}
2527
2528
2529void XMLPrinter::PushAttribute( const char* name, unsigned v )
2530{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002531 char buf[BUF_SIZE];
2532 XMLUtil::ToStr( v, buf, BUF_SIZE );
2533 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002534}
2535
2536
Lee Thomason51c12712016-06-04 20:18:49 -07002537void XMLPrinter::PushAttribute(const char* name, int64_t v)
2538{
2539 char buf[BUF_SIZE];
2540 XMLUtil::ToStr(v, buf, BUF_SIZE);
2541 PushAttribute(name, buf);
2542}
2543
2544
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002545void XMLPrinter::PushAttribute( const char* name, bool v )
2546{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002547 char buf[BUF_SIZE];
2548 XMLUtil::ToStr( v, buf, BUF_SIZE );
2549 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002550}
2551
2552
2553void XMLPrinter::PushAttribute( const char* name, double v )
2554{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002555 char buf[BUF_SIZE];
2556 XMLUtil::ToStr( v, buf, BUF_SIZE );
2557 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002558}
2559
2560
Uli Kustererca412e82014-02-01 13:35:05 +01002561void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002562{
Lee Thomason624d43f2012-10-12 10:58:48 -07002563 --_depth;
2564 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002565
Lee Thomason624d43f2012-10-12 10:58:48 -07002566 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002567 Print( "/>" );
2568 }
2569 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002570 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002571 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002572 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002573 }
2574 Print( "</%s>", name );
2575 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002576
Lee Thomason624d43f2012-10-12 10:58:48 -07002577 if ( _textDepth == _depth ) {
2578 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002579 }
Uli Kustererca412e82014-02-01 13:35:05 +01002580 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002581 Print( "\n" );
2582 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002583 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002584}
2585
2586
Dmitry-Mea092bc12014-12-23 17:57:05 +03002587void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002588{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002589 if ( !_elementJustOpened ) {
2590 return;
2591 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002592 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002593 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002594}
2595
2596
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002597void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002598{
Lee Thomason624d43f2012-10-12 10:58:48 -07002599 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002600
Dmitry-Mea092bc12014-12-23 17:57:05 +03002601 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002602 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002603 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002604 }
2605 else {
2606 PrintString( text, true );
2607 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002608}
2609
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002610void XMLPrinter::PushText( int64_t value )
2611{
2612 char buf[BUF_SIZE];
2613 XMLUtil::ToStr( value, buf, BUF_SIZE );
2614 PushText( buf, false );
2615}
2616
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002617void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002618{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002619 char buf[BUF_SIZE];
2620 XMLUtil::ToStr( value, buf, BUF_SIZE );
2621 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002622}
2623
2624
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002625void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002626{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002627 char buf[BUF_SIZE];
2628 XMLUtil::ToStr( value, buf, BUF_SIZE );
2629 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002630}
2631
2632
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002633void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002634{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002635 char buf[BUF_SIZE];
2636 XMLUtil::ToStr( value, buf, BUF_SIZE );
2637 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002638}
2639
2640
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002641void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002642{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002643 char buf[BUF_SIZE];
2644 XMLUtil::ToStr( value, buf, BUF_SIZE );
2645 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002646}
2647
2648
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002649void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002650{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002651 char buf[BUF_SIZE];
2652 XMLUtil::ToStr( value, buf, BUF_SIZE );
2653 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002654}
2655
Lee Thomason5cae8972012-01-24 18:03:07 -08002656
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002657void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002658{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002659 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002660 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002661 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002662 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002663 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002664 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002665 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002666}
Lee Thomason751da522012-02-10 08:50:51 -08002667
2668
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002669void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002670{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002671 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002672 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002673 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002674 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002675 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002676 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002677 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002678}
2679
2680
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002681void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002682{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002683 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002684 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002685 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002686 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002687 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002688 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002689 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002690}
2691
2692
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002693bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002694{
Lee Thomason624d43f2012-10-12 10:58:48 -07002695 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002696 if ( doc.HasBOM() ) {
2697 PushHeader( true, false );
2698 }
2699 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002700}
2701
2702
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002703bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002704{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002705 const XMLElement* parentElem = 0;
2706 if ( element.Parent() ) {
2707 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002708 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002709 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002710 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002711 while ( attribute ) {
2712 PushAttribute( attribute->Name(), attribute->Value() );
2713 attribute = attribute->Next();
2714 }
2715 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002716}
2717
2718
Uli Kustererca412e82014-02-01 13:35:05 +01002719bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002720{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002721 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002722 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002723}
2724
2725
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002726bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002727{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002728 PushText( text.Value(), text.CData() );
2729 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002730}
2731
2732
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002733bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002734{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002735 PushComment( comment.Value() );
2736 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002737}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002738
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002739bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002740{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002741 PushDeclaration( declaration.Value() );
2742 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002743}
2744
2745
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002746bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002747{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002748 PushUnknown( unknown.Value() );
2749 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002750}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002751
Lee Thomason685b8952012-11-12 13:00:06 -08002752} // namespace tinyxml2
2753