blob: 8f0116bf7665c1ca1815ec56bfe4acdb088bc172 [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
U-Lama\Lee560bd472011-12-28 19:42:49 -080024#include "tinyxml2.h"
25
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070026#include <new> // yes, this one new style header, is in the Android SDK.
Wilfred van Velzen67abee52016-03-25 14:01:15 +010027#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)
Lee Thomasona9cf3f92012-10-11 16:56:51 -070028# include <stddef.h>
Philipp Kloke358202c2015-07-30 16:02:26 +020029# include <stdarg.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070030#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070031# include <cstddef>
Philipp Kloke358202c2015-07-30 16:02:26 +020032# include <cstdarg>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070033#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080034
Lee Thomason53db4a62015-06-11 22:52:08 -070035#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
Dmitry-Me1ca593c2015-06-22 12:49:32 +030036 // Microsoft Visual Studio, version 2005 and higher. Not WinCE.
Lee Thomason53db4a62015-06-11 22:52:08 -070037 /*int _snprintf_s(
38 char *buffer,
39 size_t sizeOfBuffer,
40 size_t count,
41 const char *format [,
42 argument] ...
43 );*/
PKEuScac75782015-08-15 18:17:27 +020044 static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
Lee Thomason53db4a62015-06-11 22:52:08 -070045 {
46 va_list va;
47 va_start( va, format );
48 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
49 va_end( va );
50 return result;
51 }
52
PKEuScac75782015-08-15 18:17:27 +020053 static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070054 {
55 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
56 return result;
57 }
58
59 #define TIXML_VSCPRINTF _vscprintf
60 #define TIXML_SSCANF sscanf_s
61#elif defined _MSC_VER
62 // Microsoft Visual Studio 2003 and earlier or WinCE
63 #define TIXML_SNPRINTF _snprintf
64 #define TIXML_VSNPRINTF _vsnprintf
65 #define TIXML_SSCANF sscanf
Lee Thomasonaa8566b2015-06-19 16:52:40 -070066 #if (_MSC_VER < 1400 ) && (!defined WINCE)
Lee Thomason53db4a62015-06-11 22:52:08 -070067 // Microsoft Visual Studio 2003 and not WinCE.
68 #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have.
69 #else
70 // Microsoft Visual Studio 2003 and earlier or WinCE.
PKEuScac75782015-08-15 18:17:27 +020071 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070072 {
73 int len = 512;
74 for (;;) {
75 len = len*2;
76 char* str = new char[len]();
77 const int required = _vsnprintf(str, len, format, va);
78 delete[] str;
79 if ( required != -1 ) {
Dmitry-Me1d32e582015-07-27 17:11:51 +030080 TIXMLASSERT( required >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070081 len = required;
82 break;
83 }
84 }
Dmitry-Me1d32e582015-07-27 17:11:51 +030085 TIXMLASSERT( len >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070086 return len;
87 }
88 #endif
89#else
90 // GCC version 3 and higher
91 //#warning( "Using sn* functions." )
92 #define TIXML_SNPRINTF snprintf
93 #define TIXML_VSNPRINTF vsnprintf
PKEuScac75782015-08-15 18:17:27 +020094 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070095 {
96 int len = vsnprintf( 0, 0, format, va );
Dmitry-Me1d32e582015-07-27 17:11:51 +030097 TIXMLASSERT( len >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070098 return len;
99 }
100 #define TIXML_SSCANF sscanf
101#endif
102
103
Lee Thomasone4422302012-01-20 17:59:50 -0800104static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -0800105static const char LF = LINE_FEED;
106static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
107static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -0800108static const char SINGLE_QUOTE = '\'';
109static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -0800110
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800111// Bunch of unicode info at:
112// http://www.unicode.org/faq/utf_bom.html
113// ef bb bf (Microsoft "lead bytes") - designates UTF-8
114
115static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
116static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
117static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800118
Kevin Wojniak04c22d22012-11-08 11:02:22 -0800119namespace tinyxml2
120{
121
Lee Thomason8ee79892012-01-25 17:44:30 -0800122struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700123 const char* pattern;
124 int length;
125 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -0800126};
127
128static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700129static const Entity entities[NUM_ENTITIES] = {
130 { "quot", 4, DOUBLE_QUOTE },
131 { "amp", 3, '&' },
132 { "apos", 4, SINGLE_QUOTE },
133 { "lt", 2, '<' },
134 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -0800135};
136
Lee Thomasonfde6a752012-01-14 18:08:12 -0800137
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800138StrPair::~StrPair()
139{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700140 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800141}
142
143
Lee Thomason29658802014-11-27 22:31:11 -0800144void StrPair::TransferTo( StrPair* other )
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300145{
Lee Thomason29658802014-11-27 22:31:11 -0800146 if ( this == other ) {
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300147 return;
148 }
149 // This in effect implements the assignment operator by "moving"
150 // ownership (as in auto_ptr).
151
Dmitry-Medb02b212016-08-04 17:16:05 +0300152 TIXMLASSERT( other != 0 );
Lee Thomason29658802014-11-27 22:31:11 -0800153 TIXMLASSERT( other->_flags == 0 );
154 TIXMLASSERT( other->_start == 0 );
155 TIXMLASSERT( other->_end == 0 );
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300156
Lee Thomason29658802014-11-27 22:31:11 -0800157 other->Reset();
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300158
Lee Thomason29658802014-11-27 22:31:11 -0800159 other->_flags = _flags;
160 other->_start = _start;
161 other->_end = _end;
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300162
163 _flags = 0;
164 _start = 0;
165 _end = 0;
166}
167
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800168void StrPair::Reset()
169{
Lee Thomason120b3a62012-10-12 10:06:59 -0700170 if ( _flags & NEEDS_DELETE ) {
171 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700172 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700173 _flags = 0;
174 _start = 0;
175 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800176}
177
178
179void StrPair::SetStr( const char* str, int flags )
180{
Dmitry-Me0515fa92015-12-09 11:54:06 +0300181 TIXMLASSERT( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700182 Reset();
183 size_t len = strlen( str );
Dmitry-Me96f38cc2015-08-10 16:45:12 +0300184 TIXMLASSERT( _start == 0 );
Lee Thomason120b3a62012-10-12 10:06:59 -0700185 _start = new char[ len+1 ];
186 memcpy( _start, str, len+1 );
187 _end = _start + len;
188 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800189}
190
191
kezenator4f756162016-11-29 19:46:27 +1000192char* StrPair::ParseText( char* p, const char* endTag, int strFlags, int* curLineNumPtr )
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800193{
Dmitry-Mef9f3c3e2016-08-30 15:51:55 +0300194 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700195 TIXMLASSERT( endTag && *endTag );
Lee Thomasone90e9012016-12-24 07:34:39 -0800196 TIXMLASSERT(curLineNumPtr);
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800197
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400198 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700199 char endChar = *endTag;
200 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800201
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700202 // Inner loop of text parsing.
203 while ( *p ) {
204 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
205 Set( start, p, strFlags );
206 return p + length;
kezenatorec694152016-11-26 17:21:43 +1000207 } else if (*p == '\n') {
kezenator4f756162016-11-29 19:46:27 +1000208 ++(*curLineNumPtr);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700209 }
210 ++p;
Dmitry-Mef9f3c3e2016-08-30 15:51:55 +0300211 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700212 }
213 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800214}
215
216
217char* StrPair::ParseName( char* p )
218{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400219 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700220 return 0;
221 }
JayXonee525db2014-12-24 04:01:42 -0500222 if ( !XMLUtil::IsNameStartChar( *p ) ) {
223 return 0;
224 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800225
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400226 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500227 ++p;
228 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700229 ++p;
230 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800231
JayXonee525db2014-12-24 04:01:42 -0500232 Set( start, p, 0 );
233 return p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800234}
235
236
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700237void StrPair::CollapseWhitespace()
238{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400239 // Adjusting _start would cause undefined behavior on delete[]
240 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700241 // Trim leading space.
Lee Thomasone90e9012016-12-24 07:34:39 -0800242 _start = XMLUtil::SkipWhiteSpace( _start, 0 );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700243
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300244 if ( *_start ) {
Dmitry-Me24495822016-09-02 16:53:32 +0300245 const char* p = _start; // the read pointer
Lee Thomason120b3a62012-10-12 10:06:59 -0700246 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700247
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700248 while( *p ) {
249 if ( XMLUtil::IsWhiteSpace( *p )) {
Lee Thomasone90e9012016-12-24 07:34:39 -0800250 p = XMLUtil::SkipWhiteSpace( p, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700251 if ( *p == 0 ) {
252 break; // don't write to q; this trims the trailing space.
253 }
254 *q = ' ';
255 ++q;
256 }
257 *q = *p;
258 ++q;
259 ++p;
260 }
261 *q = 0;
262 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700263}
264
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800265
Lee Thomasone4422302012-01-20 17:59:50 -0800266const char* StrPair::GetStr()
267{
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300268 TIXMLASSERT( _start );
269 TIXMLASSERT( _end );
Lee Thomason120b3a62012-10-12 10:06:59 -0700270 if ( _flags & NEEDS_FLUSH ) {
271 *_end = 0;
272 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800273
Lee Thomason120b3a62012-10-12 10:06:59 -0700274 if ( _flags ) {
Dmitry-Me24495822016-09-02 16:53:32 +0300275 const char* p = _start; // the read pointer
Lee Thomason120b3a62012-10-12 10:06:59 -0700276 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800277
Lee Thomason120b3a62012-10-12 10:06:59 -0700278 while( p < _end ) {
279 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700280 // CR-LF pair becomes LF
281 // CR alone becomes LF
282 // LF-CR becomes LF
283 if ( *(p+1) == LF ) {
284 p += 2;
285 }
286 else {
287 ++p;
288 }
Dmitry-Mefed51122016-09-06 18:08:55 +0300289 *q = LF;
290 ++q;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700291 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700292 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700293 if ( *(p+1) == CR ) {
294 p += 2;
295 }
296 else {
297 ++p;
298 }
Dmitry-Mefed51122016-09-06 18:08:55 +0300299 *q = LF;
300 ++q;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700301 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700302 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700303 // Entities handled by tinyXML2:
304 // - special entities in the entity table [in/out]
305 // - numeric character reference [in]
306 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800307
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700308 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400309 const int buflen = 10;
310 char buf[buflen] = { 0 };
311 int len = 0;
Dmitry-Me6f51c802015-03-14 13:25:03 +0300312 char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
313 if ( adjusted == 0 ) {
314 *q = *p;
315 ++p;
316 ++q;
317 }
318 else {
319 TIXMLASSERT( 0 <= len && len <= buflen );
320 TIXMLASSERT( q + len <= adjusted );
321 p = adjusted;
322 memcpy( q, buf, len );
323 q += len;
324 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700325 }
326 else {
Dmitry-Me764545e2015-05-20 10:29:24 +0300327 bool entityFound = false;
328 for( int i = 0; i < NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400329 const Entity& entity = entities[i];
330 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
331 && *( p + entity.length + 1 ) == ';' ) {
332 // Found an entity - convert.
333 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700334 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400335 p += entity.length + 2;
Dmitry-Me764545e2015-05-20 10:29:24 +0300336 entityFound = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700337 break;
338 }
339 }
Dmitry-Me764545e2015-05-20 10:29:24 +0300340 if ( !entityFound ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700341 // fixme: treat as error?
342 ++p;
343 ++q;
344 }
345 }
346 }
347 else {
348 *q = *p;
349 ++p;
350 ++q;
351 }
352 }
353 *q = 0;
354 }
355 // The loop below has plenty going on, and this
356 // is a less useful mode. Break it out.
Dmitry-Me5420e542015-05-20 10:51:26 +0300357 if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700358 CollapseWhitespace();
359 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700360 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700361 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300362 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700363 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800364}
365
Lee Thomason2c85a712012-01-31 08:24:24 -0800366
Lee Thomasone4422302012-01-20 17:59:50 -0800367
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800368
Lee Thomason56bdd022012-02-09 18:16:58 -0800369// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800370
Lee Thomasonf458d262016-12-26 22:47:25 -0800371const char* XMLUtil::writeBoolTrue = "true";
372const char* XMLUtil::writeBoolFalse = "false";
Lee Thomasonce667c92016-12-26 16:45:30 -0800373
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800374void XMLUtil::SetBoolSerialization(const char* writeTrue, const char* writeFalse)
Lee Thomasonce667c92016-12-26 16:45:30 -0800375{
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800376 static const char* defTrue = "true";
Lee Thomasonce667c92016-12-26 16:45:30 -0800377 static const char* defFalse = "false";
Lee Thomasonce667c92016-12-26 16:45:30 -0800378
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800379 writeBoolTrue = (writeTrue) ? writeTrue : defTrue;
380 writeBoolFalse = (writeFalse) ? writeFalse : defFalse;
Lee Thomasonce667c92016-12-26 16:45:30 -0800381}
382
383
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800384const char* XMLUtil::ReadBOM( const char* p, bool* bom )
385{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300386 TIXMLASSERT( p );
387 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700388 *bom = false;
389 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
390 // Check for BOM:
391 if ( *(pu+0) == TIXML_UTF_LEAD_0
392 && *(pu+1) == TIXML_UTF_LEAD_1
393 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
394 *bom = true;
395 p += 3;
396 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300397 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700398 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800399}
400
401
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800402void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
403{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700404 const unsigned long BYTE_MASK = 0xBF;
405 const unsigned long BYTE_MARK = 0x80;
406 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800407
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700408 if (input < 0x80) {
409 *length = 1;
410 }
411 else if ( input < 0x800 ) {
412 *length = 2;
413 }
414 else if ( input < 0x10000 ) {
415 *length = 3;
416 }
417 else if ( input < 0x200000 ) {
418 *length = 4;
419 }
420 else {
Dmitry-Me2f465c42015-03-16 11:08:23 +0300421 *length = 0; // This code won't convert this correctly anyway.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700422 return;
423 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800424
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700425 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800426
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300427 // Scary scary fall throughs are annotated with carefully designed comments
428 // to suppress compiler warnings such as -Wimplicit-fallthrough in gcc
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700429 switch (*length) {
430 case 4:
431 --output;
432 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
433 input >>= 6;
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300434 //fall through
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700435 case 3:
436 --output;
437 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
438 input >>= 6;
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300439 //fall through
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700440 case 2:
441 --output;
442 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
443 input >>= 6;
Dmitry-Me3cc6f5c2017-08-03 18:42:20 +0300444 //fall through
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700445 case 1:
446 --output;
447 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100448 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300449 default:
450 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700451 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800452}
453
454
455const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
456{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700457 // Presume an entity, and pull it out.
458 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800459
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700460 if ( *(p+1) == '#' && *(p+2) ) {
461 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300462 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700463 ptrdiff_t delta = 0;
464 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800465 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800466
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700467 if ( *(p+2) == 'x' ) {
468 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300469 const char* q = p+3;
470 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700471 return 0;
472 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800473
Lee Thomason7e67bc82015-01-12 14:05:12 -0800474 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800475
Dmitry-Me9f56e122015-01-12 10:07:54 +0300476 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700477 return 0;
478 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800479 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800480
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700481 delta = q-p;
482 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800483
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700484 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700485 unsigned int digit = 0;
486
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700487 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300488 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700489 }
490 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300491 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700492 }
493 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300494 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700495 }
496 else {
497 return 0;
498 }
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100499 TIXMLASSERT( digit < 16 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300500 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
501 const unsigned int digitScaled = mult * digit;
502 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
503 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300504 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700505 mult *= 16;
506 --q;
507 }
508 }
509 else {
510 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300511 const char* q = p+2;
512 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700513 return 0;
514 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800515
Lee Thomason7e67bc82015-01-12 14:05:12 -0800516 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800517
Dmitry-Me9f56e122015-01-12 10:07:54 +0300518 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700519 return 0;
520 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800521 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800522
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700523 delta = q-p;
524 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800525
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700526 while ( *q != '#' ) {
527 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300528 const unsigned int digit = *q - '0';
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100529 TIXMLASSERT( digit < 10 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300530 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
531 const unsigned int digitScaled = mult * digit;
532 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
533 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700534 }
535 else {
536 return 0;
537 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300538 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700539 mult *= 10;
540 --q;
541 }
542 }
543 // convert the UCS to UTF-8
544 ConvertUTF32ToUTF8( ucs, value, length );
545 return p + delta + 1;
546 }
547 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800548}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800549
550
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700551void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700552{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700553 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700554}
555
556
557void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
558{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700559 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700560}
561
562
563void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
564{
Lee Thomasonce667c92016-12-26 16:45:30 -0800565 TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? writeBoolTrue : writeBoolFalse);
Lee Thomason21be8822012-07-15 17:27:22 -0700566}
567
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800568/*
569 ToStr() of a number is a very tricky topic.
570 https://github.com/leethomason/tinyxml2/issues/106
571*/
Lee Thomason21be8822012-07-15 17:27:22 -0700572void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
573{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800574 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700575}
576
577
578void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
579{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800580 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700581}
582
583
Lee Thomason51c12712016-06-04 20:18:49 -0700584void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize)
585{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700586 // horrible syntax trick to make the compiler happy about %lld
587 TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v);
Lee Thomason51c12712016-06-04 20:18:49 -0700588}
589
590
Lee Thomason21be8822012-07-15 17:27:22 -0700591bool XMLUtil::ToInt( const char* str, int* value )
592{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700593 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
594 return true;
595 }
596 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700597}
598
599bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
600{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700601 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
602 return true;
603 }
604 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700605}
606
607bool XMLUtil::ToBool( const char* str, bool* value )
608{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700609 int ival = 0;
610 if ( ToInt( str, &ival )) {
611 *value = (ival==0) ? false : true;
612 return true;
613 }
614 if ( StringEqual( str, "true" ) ) {
615 *value = true;
616 return true;
617 }
618 else if ( StringEqual( str, "false" ) ) {
619 *value = false;
620 return true;
621 }
622 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700623}
624
625
626bool XMLUtil::ToFloat( const char* str, float* value )
627{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700628 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
629 return true;
630 }
631 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700632}
633
Lee Thomason51c12712016-06-04 20:18:49 -0700634
Lee Thomason21be8822012-07-15 17:27:22 -0700635bool XMLUtil::ToDouble( const char* str, double* value )
636{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700637 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
638 return true;
639 }
640 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700641}
642
643
Lee Thomason51c12712016-06-04 20:18:49 -0700644bool XMLUtil::ToInt64(const char* str, int64_t* value)
645{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700646 long long v = 0; // horrible syntax trick to make the compiler happy about %lld
647 if (TIXML_SSCANF(str, "%lld", &v) == 1) {
648 *value = (int64_t)v;
Lee Thomason51c12712016-06-04 20:18:49 -0700649 return true;
650 }
651 return false;
652}
653
654
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700655char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800656{
Dmitry-Me02384662015-03-03 16:02:13 +0300657 TIXMLASSERT( node );
658 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400659 char* const start = p;
kezenatorec694152016-11-26 17:21:43 +1000660 int const startLine = _parseCurLineNum;
kezenator4f756162016-11-29 19:46:27 +1000661 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300662 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300663 *node = 0;
664 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700665 return p;
666 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800667
Dmitry-Me962083b2015-05-26 11:38:30 +0300668 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700669 static const char* xmlHeader = { "<?" };
670 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700671 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300672 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700673 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800674
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700675 static const int xmlHeaderLen = 2;
676 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700677 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300678 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700679 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800680
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700681 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
682 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400683 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700684 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300685 returnNode = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000686 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700687 p += xmlHeaderLen;
688 }
689 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300690 returnNode = CreateUnlinkedNode<XMLComment>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000691 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700692 p += commentHeaderLen;
693 }
694 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300695 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700696 returnNode = text;
kezenatorec694152016-11-26 17:21:43 +1000697 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700698 p += cdataHeaderLen;
699 text->SetCData( true );
700 }
701 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300702 returnNode = CreateUnlinkedNode<XMLUnknown>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000703 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700704 p += dtdHeaderLen;
705 }
706 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300707 returnNode = CreateUnlinkedNode<XMLElement>( _elementPool );
kezenatorec694152016-11-26 17:21:43 +1000708 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700709 p += elementHeaderLen;
710 }
711 else {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300712 returnNode = CreateUnlinkedNode<XMLText>( _textPool );
kezenatorec694152016-11-26 17:21:43 +1000713 returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700714 p = start; // Back it up, all the text counts.
kezenatorec694152016-11-26 17:21:43 +1000715 _parseCurLineNum = startLine;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700716 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800717
Dmitry-Me02384662015-03-03 16:02:13 +0300718 TIXMLASSERT( returnNode );
719 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700720 *node = returnNode;
721 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800722}
723
724
Lee Thomason751da522012-02-10 08:50:51 -0800725bool XMLDocument::Accept( XMLVisitor* visitor ) const
726{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300727 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700728 if ( visitor->VisitEnter( *this ) ) {
729 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
730 if ( !node->Accept( visitor ) ) {
731 break;
732 }
733 }
734 }
735 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800736}
Lee Thomason56bdd022012-02-09 18:16:58 -0800737
738
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800739// --------- XMLNode ----------- //
740
741XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700742 _document( doc ),
743 _parent( 0 ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +0200744 _value(),
kezenatorec694152016-11-26 17:21:43 +1000745 _parseLineNum( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -0700746 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200747 _prev( 0 ), _next( 0 ),
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700748 _userData( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200749 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800750{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800751}
752
753
754XMLNode::~XMLNode()
755{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700756 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700757 if ( _parent ) {
758 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700759 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800760}
761
Michael Daumling21626882013-10-22 17:03:37 +0200762const char* XMLNode::Value() const
763{
Dmitry-Mecaa72a62016-08-10 17:34:34 +0300764 // Edge case: XMLDocuments don't have a Value. Return null.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530765 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530766 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200767 return _value.GetStr();
768}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800769
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800770void XMLNode::SetValue( const char* str, bool staticMem )
771{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700772 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700773 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700774 }
775 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700776 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700777 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800778}
779
Dmitry-Me3f63f212017-06-19 18:25:19 +0300780XMLNode* XMLNode::DeepClone(XMLDocument* target) const
Lee Thomason7085f002017-06-01 18:09:43 -0700781{
Dmitry-Me3f63f212017-06-19 18:25:19 +0300782 XMLNode* clone = this->ShallowClone(target);
Lee Thomason7085f002017-06-01 18:09:43 -0700783 if (!clone) return 0;
784
785 for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) {
Dmitry-Me3f63f212017-06-19 18:25:19 +0300786 XMLNode* childClone = child->DeepClone(target);
Lee Thomason7085f002017-06-01 18:09:43 -0700787 TIXMLASSERT(childClone);
788 clone->InsertEndChild(childClone);
789 }
790 return clone;
791}
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800792
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800793void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800794{
Lee Thomason624d43f2012-10-12 10:58:48 -0700795 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300796 TIXMLASSERT( _lastChild );
Dmitry-Me9cb4eca2016-08-18 18:10:59 +0300797 DeleteChild( _firstChild );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700798 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700799 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800800}
801
802
803void XMLNode::Unlink( XMLNode* child )
804{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300805 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300806 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300807 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700808 if ( child == _firstChild ) {
809 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700810 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700811 if ( child == _lastChild ) {
812 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700813 }
Lee Thomasond923c672012-01-23 08:44:25 -0800814
Lee Thomason624d43f2012-10-12 10:58:48 -0700815 if ( child->_prev ) {
816 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700817 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700818 if ( child->_next ) {
819 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700820 }
Lee Thomason8a763612017-06-16 09:30:16 -0700821 child->_next = 0;
822 child->_prev = 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700823 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800824}
825
826
U-Stream\Leeae25a442012-02-17 17:48:16 -0800827void XMLNode::DeleteChild( XMLNode* node )
828{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300829 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300830 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700831 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100832 Unlink( node );
Lee Thomason816d3fa2017-06-05 14:35:55 -0700833 TIXMLASSERT(node->_prev == 0);
834 TIXMLASSERT(node->_next == 0);
835 TIXMLASSERT(node->_parent == 0);
Dmitry-Mee3225b12014-09-03 11:03:11 +0400836 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800837}
838
839
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800840XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
841{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300842 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300843 if ( addThis->_document != _document ) {
844 TIXMLASSERT( false );
845 return 0;
846 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800847 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700848
Lee Thomason624d43f2012-10-12 10:58:48 -0700849 if ( _lastChild ) {
850 TIXMLASSERT( _firstChild );
851 TIXMLASSERT( _lastChild->_next == 0 );
852 _lastChild->_next = addThis;
853 addThis->_prev = _lastChild;
854 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800855
Lee Thomason624d43f2012-10-12 10:58:48 -0700856 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700857 }
858 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700859 TIXMLASSERT( _firstChild == 0 );
860 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800861
Lee Thomason624d43f2012-10-12 10:58:48 -0700862 addThis->_prev = 0;
863 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700864 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700865 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700866 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800867}
868
869
Lee Thomason1ff38e02012-02-14 18:18:16 -0800870XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
871{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300872 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300873 if ( addThis->_document != _document ) {
874 TIXMLASSERT( false );
875 return 0;
876 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800877 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700878
Lee Thomason624d43f2012-10-12 10:58:48 -0700879 if ( _firstChild ) {
880 TIXMLASSERT( _lastChild );
881 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800882
Lee Thomason624d43f2012-10-12 10:58:48 -0700883 _firstChild->_prev = addThis;
884 addThis->_next = _firstChild;
885 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800886
Lee Thomason624d43f2012-10-12 10:58:48 -0700887 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700888 }
889 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700890 TIXMLASSERT( _lastChild == 0 );
891 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800892
Lee Thomason624d43f2012-10-12 10:58:48 -0700893 addThis->_prev = 0;
894 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700895 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700896 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400897 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800898}
899
900
901XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
902{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300903 TIXMLASSERT( addThis );
904 if ( addThis->_document != _document ) {
905 TIXMLASSERT( false );
906 return 0;
907 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700908
Dmitry-Meabb2d042014-12-09 12:59:31 +0300909 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700910
Lee Thomason624d43f2012-10-12 10:58:48 -0700911 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300912 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700913 return 0;
914 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800915
Lee Thomason624d43f2012-10-12 10:58:48 -0700916 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700917 // The last node or the only node.
918 return InsertEndChild( addThis );
919 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800920 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700921 addThis->_prev = afterThis;
922 addThis->_next = afterThis->_next;
923 afterThis->_next->_prev = addThis;
924 afterThis->_next = addThis;
925 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700926 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800927}
928
929
930
931
Dmitry-Me886ad972015-07-22 11:00:51 +0300932const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800933{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300934 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300935 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700936 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300937 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700938 }
939 }
940 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800941}
942
943
Dmitry-Me886ad972015-07-22 11:00:51 +0300944const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800945{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300946 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300947 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700948 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300949 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700950 }
951 }
952 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800953}
954
955
Dmitry-Me886ad972015-07-22 11:00:51 +0300956const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800957{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300958 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300959 const XMLElement* element = node->ToElementWithName( name );
960 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400961 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700962 }
963 }
964 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800965}
966
967
Dmitry-Me886ad972015-07-22 11:00:51 +0300968const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800969{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300970 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300971 const XMLElement* element = node->ToElementWithName( name );
972 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400973 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700974 }
975 }
976 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800977}
978
979
Dmitry-Me10b8ecc2017-04-12 17:57:44 +0300980char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -0800981{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700982 // This is a recursive method, but thinking about it "at the current level"
983 // it is a pretty simple flat list:
984 // <foo/>
985 // <!-- comment -->
986 //
987 // With a special case:
988 // <foo>
989 // </foo>
990 // <!-- comment -->
991 //
992 // Where the closing element (/foo) *must* be the next thing after the opening
993 // element, and the names must match. BUT the tricky bit is that the closing
994 // element will be read by the child.
995 //
996 // 'endTag' is the end tag for this node, it is returned by a call to a child.
997 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800998
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700999 while( p && *p ) {
1000 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -08001001
Lee Thomason624d43f2012-10-12 10:58:48 -07001002 p = _document->Identify( p, &node );
Dmitry-Me43364312016-11-07 18:48:50 +03001003 TIXMLASSERT( p );
Dmitry-Me9fcb8762015-03-05 17:53:34 +03001004 if ( node == 0 ) {
1005 break;
1006 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001007
kezenatore3531812016-11-29 19:49:07 +10001008 int initialLineNum = node->_parseLineNum;
kezenatorec694152016-11-26 17:21:43 +10001009
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001010 StrPair endTag;
kezenator4f756162016-11-29 19:46:27 +10001011 p = node->ParseDeep( p, &endTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001012 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001013 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -07001014 if ( !_document->Error() ) {
kezenatore3531812016-11-29 19:49:07 +10001015 _document->SetError( XML_ERROR_PARSING, 0, 0, initialLineNum);
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001016 }
1017 break;
1018 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001019
Sarat Addepalli3df007e2015-05-20 10:43:51 +05301020 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301021 if ( decl ) {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001022 // Declarations are only allowed at document level
1023 bool wellLocated = ( ToDocument() != 0 );
1024 if ( wellLocated ) {
1025 // Multiple declarations are allowed but all declarations
1026 // must occur before anything else
1027 for ( const XMLNode* existingNode = _document->FirstChild(); existingNode; existingNode = existingNode->NextSibling() ) {
1028 if ( !existingNode->ToDeclaration() ) {
1029 wellLocated = false;
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301030 break;
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001031 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301032 }
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001033 }
1034 if ( !wellLocated ) {
kezenatore3531812016-11-29 19:49:07 +10001035 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0, initialLineNum);
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001036 DeleteNode( node );
1037 break;
1038 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301039 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301040
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001041 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001042 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -05001043 // We read the end tag. Return it to the parent.
1044 if ( ele->ClosingType() == XMLElement::CLOSING ) {
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001045 if ( parentEndTag ) {
1046 ele->_value.TransferTo( parentEndTag );
JayXone4bf6e32014-12-26 01:00:24 -05001047 }
1048 node->_memPool->SetTracked(); // created and then immediately deleted.
1049 DeleteNode( node );
1050 return p;
1051 }
1052
1053 // Handle an end tag returned to this level.
1054 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001055 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001056 if ( endTag.Empty() ) {
1057 if ( ele->ClosingType() == XMLElement::OPEN ) {
1058 mismatch = true;
1059 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001060 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001061 else {
1062 if ( ele->ClosingType() != XMLElement::OPEN ) {
1063 mismatch = true;
1064 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001065 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001066 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001067 }
1068 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001069 if ( mismatch ) {
kezenatore3531812016-11-29 19:49:07 +10001070 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0, initialLineNum);
JayXondbfdd8f2014-12-12 20:07:14 -05001071 DeleteNode( node );
1072 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001073 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001074 }
JayXondbfdd8f2014-12-12 20:07:14 -05001075 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001076 }
1077 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001078}
1079
Lee Thomason816d3fa2017-06-05 14:35:55 -07001080/*static*/ void XMLNode::DeleteNode( XMLNode* node )
Dmitry-Mee3225b12014-09-03 11:03:11 +04001081{
1082 if ( node == 0 ) {
1083 return;
1084 }
Lee Thomason816d3fa2017-06-05 14:35:55 -07001085 TIXMLASSERT(node->_document);
1086 if (!node->ToDocument()) {
1087 node->_document->MarkInUse(node);
1088 }
1089
Dmitry-Mee3225b12014-09-03 11:03:11 +04001090 MemPool* pool = node->_memPool;
1091 node->~XMLNode();
1092 pool->Free( node );
1093}
1094
Lee Thomason3cebdc42015-01-05 17:16:28 -08001095void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001096{
1097 TIXMLASSERT( insertThis );
1098 TIXMLASSERT( insertThis->_document == _document );
1099
Lee Thomason816d3fa2017-06-05 14:35:55 -07001100 if (insertThis->_parent) {
Dmitry-Me74e39402015-01-01 16:26:17 +03001101 insertThis->_parent->Unlink( insertThis );
Lee Thomason816d3fa2017-06-05 14:35:55 -07001102 }
1103 else {
1104 insertThis->_document->MarkInUse(insertThis);
Dmitry-Me74e39402015-01-01 16:26:17 +03001105 insertThis->_memPool->SetTracked();
Lee Thomason816d3fa2017-06-05 14:35:55 -07001106 }
Dmitry-Me74e39402015-01-01 16:26:17 +03001107}
1108
Dmitry-Meecb9b072016-10-12 16:44:59 +03001109const XMLElement* XMLNode::ToElementWithName( const char* name ) const
1110{
1111 const XMLElement* element = this->ToElement();
1112 if ( element == 0 ) {
1113 return 0;
1114 }
1115 if ( name == 0 ) {
1116 return element;
1117 }
1118 if ( XMLUtil::StringEqual( element->Name(), name ) ) {
1119 return element;
1120 }
1121 return 0;
1122}
1123
Lee Thomason5492a1c2012-01-23 15:32:10 -08001124// --------- XMLText ---------- //
kezenator4f756162016-11-29 19:46:27 +10001125char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001126{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001127 const char* start = p;
1128 if ( this->CData() ) {
kezenator4f756162016-11-29 19:46:27 +10001129 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001130 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001131 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001132 }
1133 return p;
1134 }
1135 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001136 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1137 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001138 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001139 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001140
kezenator4f756162016-11-29 19:46:27 +10001141 p = _value.ParseText( p, "<", flags, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001142 if ( p && *p ) {
1143 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001144 }
1145 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001146 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001147 }
1148 }
1149 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001150}
1151
1152
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001153XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1154{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001155 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001156 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001157 }
1158 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1159 text->SetCData( this->CData() );
1160 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001161}
1162
1163
1164bool XMLText::ShallowEqual( const XMLNode* compare ) const
1165{
Dmitry-Meba68a3a2017-03-21 11:39:48 +03001166 TIXMLASSERT( compare );
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001167 const XMLText* text = compare->ToText();
1168 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001169}
1170
1171
Lee Thomason56bdd022012-02-09 18:16:58 -08001172bool XMLText::Accept( XMLVisitor* visitor ) const
1173{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001174 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001175 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001176}
1177
1178
Lee Thomason3f57d272012-01-11 15:30:03 -08001179// --------- XMLComment ---------- //
1180
Lee Thomasone4422302012-01-20 17:59:50 -08001181XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001182{
1183}
1184
1185
Lee Thomasonce0763e2012-01-11 15:43:54 -08001186XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001187{
Lee Thomason3f57d272012-01-11 15:30:03 -08001188}
1189
1190
kezenator4f756162016-11-29 19:46:27 +10001191char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason3f57d272012-01-11 15:30:03 -08001192{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001193 // Comment parses as text.
1194 const char* start = p;
kezenator4f756162016-11-29 19:46:27 +10001195 p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001196 if ( p == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10001197 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001198 }
1199 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001200}
1201
1202
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001203XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1204{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001205 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001206 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001207 }
1208 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1209 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001210}
1211
1212
1213bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1214{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001215 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001216 const XMLComment* comment = compare->ToComment();
1217 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001218}
1219
1220
Lee Thomason751da522012-02-10 08:50:51 -08001221bool XMLComment::Accept( XMLVisitor* visitor ) const
1222{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001223 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001224 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001225}
Lee Thomason56bdd022012-02-09 18:16:58 -08001226
1227
Lee Thomason50f97b22012-02-11 16:33:40 -08001228// --------- XMLDeclaration ---------- //
1229
1230XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1231{
1232}
1233
1234
1235XMLDeclaration::~XMLDeclaration()
1236{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001237 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001238}
1239
1240
kezenator4f756162016-11-29 19:46:27 +10001241char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001242{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001243 // Declaration parses as text.
1244 const char* start = p;
kezenator4f756162016-11-29 19:46:27 +10001245 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001246 if ( p == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10001247 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001248 }
1249 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001250}
1251
1252
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001253XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1254{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001255 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001256 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001257 }
1258 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1259 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001260}
1261
1262
1263bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1264{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001265 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001266 const XMLDeclaration* declaration = compare->ToDeclaration();
1267 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001268}
1269
1270
1271
Lee Thomason50f97b22012-02-11 16:33:40 -08001272bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1273{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001274 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001275 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001276}
1277
1278// --------- XMLUnknown ---------- //
1279
1280XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1281{
1282}
1283
1284
1285XMLUnknown::~XMLUnknown()
1286{
1287}
1288
1289
kezenator4f756162016-11-29 19:46:27 +10001290char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001291{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001292 // Unknown parses as text.
1293 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001294
kezenator4f756162016-11-29 19:46:27 +10001295 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001296 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001297 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001298 }
1299 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001300}
1301
1302
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001303XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1304{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001305 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001306 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001307 }
1308 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1309 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001310}
1311
1312
1313bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1314{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001315 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001316 const XMLUnknown* unknown = compare->ToUnknown();
1317 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001318}
1319
1320
Lee Thomason50f97b22012-02-11 16:33:40 -08001321bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1322{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001323 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001324 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001325}
1326
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001327// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001328
1329const char* XMLAttribute::Name() const
1330{
1331 return _name.GetStr();
1332}
1333
1334const char* XMLAttribute::Value() const
1335{
1336 return _value.GetStr();
1337}
1338
kezenator4f756162016-11-29 19:46:27 +10001339char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001340{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001341 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001342 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001343 if ( !p || !*p ) {
1344 return 0;
1345 }
Lee Thomason22aead12012-01-23 13:29:35 -08001346
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001347 // Skip white space before =
kezenator4f756162016-11-29 19:46:27 +10001348 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001349 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001350 return 0;
1351 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001352
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001353 ++p; // move up to opening quote
kezenator4f756162016-11-29 19:46:27 +10001354 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001355 if ( *p != '\"' && *p != '\'' ) {
1356 return 0;
1357 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001358
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001359 char endTag[2] = { *p, 0 };
1360 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001361
kezenator4f756162016-11-29 19:46:27 +10001362 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001363 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001364}
1365
1366
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001367void XMLAttribute::SetName( const char* n )
1368{
Lee Thomason624d43f2012-10-12 10:58:48 -07001369 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001370}
1371
1372
Lee Thomason2fa81722012-11-09 12:37:46 -08001373XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001374{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001375 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001376 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001377 }
1378 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001379}
1380
1381
Lee Thomason2fa81722012-11-09 12:37:46 -08001382XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001383{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001384 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001385 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001386 }
1387 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001388}
1389
1390
Lee Thomason51c12712016-06-04 20:18:49 -07001391XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1392{
1393 if (XMLUtil::ToInt64(Value(), value)) {
1394 return XML_SUCCESS;
1395 }
1396 return XML_WRONG_ATTRIBUTE_TYPE;
1397}
1398
1399
Lee Thomason2fa81722012-11-09 12:37:46 -08001400XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001401{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001402 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001403 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001404 }
1405 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001406}
1407
1408
Lee Thomason2fa81722012-11-09 12:37:46 -08001409XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001410{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001411 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001412 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001413 }
1414 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001415}
1416
1417
Lee Thomason2fa81722012-11-09 12:37:46 -08001418XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001419{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001420 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001421 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001422 }
1423 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001424}
1425
1426
1427void XMLAttribute::SetAttribute( const char* v )
1428{
Lee Thomason624d43f2012-10-12 10:58:48 -07001429 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001430}
1431
1432
Lee Thomason1ff38e02012-02-14 18:18:16 -08001433void XMLAttribute::SetAttribute( int v )
1434{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001435 char buf[BUF_SIZE];
1436 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001437 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001438}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001439
1440
1441void XMLAttribute::SetAttribute( unsigned v )
1442{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001443 char buf[BUF_SIZE];
1444 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001445 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001446}
1447
1448
Lee Thomason51c12712016-06-04 20:18:49 -07001449void XMLAttribute::SetAttribute(int64_t v)
1450{
1451 char buf[BUF_SIZE];
1452 XMLUtil::ToStr(v, buf, BUF_SIZE);
1453 _value.SetStr(buf);
1454}
1455
1456
1457
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001458void XMLAttribute::SetAttribute( bool v )
1459{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001460 char buf[BUF_SIZE];
1461 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001462 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001463}
1464
1465void XMLAttribute::SetAttribute( double v )
1466{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001467 char buf[BUF_SIZE];
1468 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001469 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001470}
1471
1472void XMLAttribute::SetAttribute( float v )
1473{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001474 char buf[BUF_SIZE];
1475 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001476 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001477}
1478
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001479
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001480// --------- XMLElement ---------- //
1481XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Dmitry-Mee5035632017-04-05 18:02:40 +03001482 _closingType( OPEN ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001483 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001484{
1485}
1486
1487
1488XMLElement::~XMLElement()
1489{
Lee Thomason624d43f2012-10-12 10:58:48 -07001490 while( _rootAttribute ) {
1491 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001492 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001493 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001494 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001495}
1496
1497
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001498const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1499{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001500 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001501 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1502 return a;
1503 }
1504 }
1505 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001506}
1507
1508
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001509const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001510{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001511 const XMLAttribute* a = FindAttribute( name );
1512 if ( !a ) {
1513 return 0;
1514 }
1515 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1516 return a->Value();
1517 }
1518 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001519}
1520
Josh Wittnercf3dd092016-10-11 18:57:17 -07001521int XMLElement::IntAttribute(const char* name, int defaultValue) const
1522{
1523 int i = defaultValue;
1524 QueryIntAttribute(name, &i);
1525 return i;
1526}
1527
1528unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
1529{
1530 unsigned i = defaultValue;
1531 QueryUnsignedAttribute(name, &i);
1532 return i;
1533}
1534
1535int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
1536{
1537 int64_t i = defaultValue;
1538 QueryInt64Attribute(name, &i);
1539 return i;
1540}
1541
1542bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
1543{
1544 bool b = defaultValue;
1545 QueryBoolAttribute(name, &b);
1546 return b;
1547}
1548
1549double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
1550{
1551 double d = defaultValue;
1552 QueryDoubleAttribute(name, &d);
1553 return d;
1554}
1555
1556float XMLElement::FloatAttribute(const char* name, float defaultValue) const
1557{
1558 float f = defaultValue;
1559 QueryFloatAttribute(name, &f);
1560 return f;
1561}
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001562
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001563const char* XMLElement::GetText() const
1564{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001565 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001566 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001567 }
1568 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001569}
1570
1571
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001572void XMLElement::SetText( const char* inText )
1573{
Uli Kusterer869bb592014-01-21 01:36:16 +01001574 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001575 FirstChild()->SetValue( inText );
1576 else {
1577 XMLText* theText = GetDocument()->NewText( inText );
1578 InsertFirstChild( theText );
1579 }
1580}
1581
Lee Thomason5bb2d802014-01-24 10:42:57 -08001582
1583void XMLElement::SetText( int v )
1584{
1585 char buf[BUF_SIZE];
1586 XMLUtil::ToStr( v, buf, BUF_SIZE );
1587 SetText( buf );
1588}
1589
1590
1591void XMLElement::SetText( unsigned v )
1592{
1593 char buf[BUF_SIZE];
1594 XMLUtil::ToStr( v, buf, BUF_SIZE );
1595 SetText( buf );
1596}
1597
1598
Lee Thomason51c12712016-06-04 20:18:49 -07001599void XMLElement::SetText(int64_t v)
1600{
1601 char buf[BUF_SIZE];
1602 XMLUtil::ToStr(v, buf, BUF_SIZE);
1603 SetText(buf);
1604}
1605
1606
1607void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001608{
1609 char buf[BUF_SIZE];
1610 XMLUtil::ToStr( v, buf, BUF_SIZE );
1611 SetText( buf );
1612}
1613
1614
1615void XMLElement::SetText( float v )
1616{
1617 char buf[BUF_SIZE];
1618 XMLUtil::ToStr( v, buf, BUF_SIZE );
1619 SetText( buf );
1620}
1621
1622
1623void XMLElement::SetText( double v )
1624{
1625 char buf[BUF_SIZE];
1626 XMLUtil::ToStr( v, buf, BUF_SIZE );
1627 SetText( buf );
1628}
1629
1630
MortenMacFly4ee49f12013-01-14 20:03:14 +01001631XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001632{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001633 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001634 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001635 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001636 return XML_SUCCESS;
1637 }
1638 return XML_CAN_NOT_CONVERT_TEXT;
1639 }
1640 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001641}
1642
1643
MortenMacFly4ee49f12013-01-14 20:03:14 +01001644XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001645{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001646 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001647 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001648 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001649 return XML_SUCCESS;
1650 }
1651 return XML_CAN_NOT_CONVERT_TEXT;
1652 }
1653 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001654}
1655
1656
Lee Thomason51c12712016-06-04 20:18:49 -07001657XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1658{
1659 if (FirstChild() && FirstChild()->ToText()) {
1660 const char* t = FirstChild()->Value();
1661 if (XMLUtil::ToInt64(t, ival)) {
1662 return XML_SUCCESS;
1663 }
1664 return XML_CAN_NOT_CONVERT_TEXT;
1665 }
1666 return XML_NO_TEXT_NODE;
1667}
1668
1669
MortenMacFly4ee49f12013-01-14 20:03:14 +01001670XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001671{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001672 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001673 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001674 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001675 return XML_SUCCESS;
1676 }
1677 return XML_CAN_NOT_CONVERT_TEXT;
1678 }
1679 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001680}
1681
1682
MortenMacFly4ee49f12013-01-14 20:03:14 +01001683XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001684{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001685 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001686 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001687 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001688 return XML_SUCCESS;
1689 }
1690 return XML_CAN_NOT_CONVERT_TEXT;
1691 }
1692 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001693}
1694
1695
MortenMacFly4ee49f12013-01-14 20:03:14 +01001696XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001697{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001698 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001699 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001700 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001701 return XML_SUCCESS;
1702 }
1703 return XML_CAN_NOT_CONVERT_TEXT;
1704 }
1705 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001706}
1707
Josh Wittnercf3dd092016-10-11 18:57:17 -07001708int XMLElement::IntText(int defaultValue) const
1709{
1710 int i = defaultValue;
1711 QueryIntText(&i);
1712 return i;
1713}
1714
1715unsigned XMLElement::UnsignedText(unsigned defaultValue) const
1716{
1717 unsigned i = defaultValue;
1718 QueryUnsignedText(&i);
1719 return i;
1720}
1721
1722int64_t XMLElement::Int64Text(int64_t defaultValue) const
1723{
1724 int64_t i = defaultValue;
1725 QueryInt64Text(&i);
1726 return i;
1727}
1728
1729bool XMLElement::BoolText(bool defaultValue) const
1730{
1731 bool b = defaultValue;
1732 QueryBoolText(&b);
1733 return b;
1734}
1735
1736double XMLElement::DoubleText(double defaultValue) const
1737{
1738 double d = defaultValue;
1739 QueryDoubleText(&d);
1740 return d;
1741}
1742
1743float XMLElement::FloatText(float defaultValue) const
1744{
1745 float f = defaultValue;
1746 QueryFloatText(&f);
1747 return f;
1748}
Lee Thomason21be8822012-07-15 17:27:22 -07001749
1750
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001751XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1752{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001753 XMLAttribute* last = 0;
1754 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001755 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001756 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001757 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001758 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1759 break;
1760 }
1761 }
1762 if ( !attrib ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001763 attrib = CreateAttribute();
1764 TIXMLASSERT( attrib );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001765 if ( last ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001766 TIXMLASSERT( last->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001767 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001768 }
1769 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001770 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001771 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001772 }
1773 attrib->SetName( name );
1774 }
1775 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001776}
1777
1778
U-Stream\Leeae25a442012-02-17 17:48:16 -08001779void XMLElement::DeleteAttribute( const char* name )
1780{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001781 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001782 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001783 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1784 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001785 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001786 }
1787 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001788 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001789 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001790 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001791 break;
1792 }
1793 prev = a;
1794 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001795}
1796
1797
kezenator4f756162016-11-29 19:46:27 +10001798char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001799{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001800 const char* start = p;
1801 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001802
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001803 // Read the attributes.
1804 while( p ) {
kezenator4f756162016-11-29 19:46:27 +10001805 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001806 if ( !(*p) ) {
kezenatorec694152016-11-26 17:21:43 +10001807 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name(), _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001808 return 0;
1809 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001810
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001811 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001812 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001813 XMLAttribute* attrib = CreateAttribute();
1814 TIXMLASSERT( attrib );
kezenatorec694152016-11-26 17:21:43 +10001815 attrib->_parseLineNum = _document->_parseCurLineNum;
Lee Thomasond1983222012-02-06 08:41:24 -08001816
kezenatorec694152016-11-26 17:21:43 +10001817 int attrLineNum = attrib->_parseLineNum;
1818
kezenator4f756162016-11-29 19:46:27 +10001819 p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001820 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001821 DeleteAttribute( attrib );
kezenatorec694152016-11-26 17:21:43 +10001822 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p, attrLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001823 return 0;
1824 }
1825 // There is a minor bug here: if the attribute in the source xml
1826 // document is duplicated, it will not be detected and the
1827 // attribute will be doubly added. However, tracking the 'prevAttribute'
1828 // avoids re-scanning the attribute list. Preferring performance for
1829 // now, may reconsider in the future.
1830 if ( prevAttribute ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001831 TIXMLASSERT( prevAttribute->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001832 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001833 }
1834 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001835 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001836 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001837 }
1838 prevAttribute = attrib;
1839 }
1840 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001841 else if ( *p == '>' ) {
1842 ++p;
1843 break;
1844 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001845 // end of the tag
1846 else if ( *p == '/' && *(p+1) == '>' ) {
1847 _closingType = CLOSED;
1848 return p+2; // done; sealed element.
1849 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001850 else {
kezenatorec694152016-11-26 17:21:43 +10001851 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001852 return 0;
1853 }
1854 }
1855 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001856}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001857
Dmitry-Mee3225b12014-09-03 11:03:11 +04001858void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1859{
1860 if ( attribute == 0 ) {
1861 return;
1862 }
1863 MemPool* pool = attribute->_memPool;
1864 attribute->~XMLAttribute();
1865 pool->Free( attribute );
1866}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001867
Dmitry-Mea60caa22016-11-22 18:28:08 +03001868XMLAttribute* XMLElement::CreateAttribute()
1869{
1870 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
1871 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
Dmitry-Me7221b492017-03-03 15:45:51 +03001872 TIXMLASSERT( attrib );
Dmitry-Mea60caa22016-11-22 18:28:08 +03001873 attrib->_memPool = &_document->_attributePool;
1874 attrib->_memPool->SetTracked();
1875 return attrib;
1876}
1877
Lee Thomason67d61312012-01-24 16:01:51 -08001878//
1879// <ele></ele>
1880// <ele>foo<b>bar</b></ele>
1881//
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001882char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -08001883{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001884 // Read the element name.
kezenator4f756162016-11-29 19:46:27 +10001885 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomason67d61312012-01-24 16:01:51 -08001886
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001887 // The closing element is the </element> form. It is
1888 // parsed just like a regular element then deleted from
1889 // the DOM.
1890 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001891 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001892 ++p;
1893 }
Lee Thomason67d61312012-01-24 16:01:51 -08001894
Lee Thomason624d43f2012-10-12 10:58:48 -07001895 p = _value.ParseName( p );
1896 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001897 return 0;
1898 }
Lee Thomason67d61312012-01-24 16:01:51 -08001899
kezenator4f756162016-11-29 19:46:27 +10001900 p = ParseAttributes( p, curLineNumPtr );
Dmitry-Mee5035632017-04-05 18:02:40 +03001901 if ( !p || !*p || _closingType != OPEN ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001902 return p;
1903 }
Lee Thomason67d61312012-01-24 16:01:51 -08001904
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001905 p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001906 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001907}
1908
1909
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001910
1911XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1912{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001913 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001914 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001915 }
1916 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1917 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1918 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1919 }
1920 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001921}
1922
1923
1924bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1925{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001926 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001927 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001928 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001929
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001930 const XMLAttribute* a=FirstAttribute();
1931 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001932
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001933 while ( a && b ) {
1934 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1935 return false;
1936 }
1937 a = a->Next();
1938 b = b->Next();
1939 }
1940 if ( a || b ) {
1941 // different count
1942 return false;
1943 }
1944 return true;
1945 }
1946 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001947}
1948
1949
Lee Thomason751da522012-02-10 08:50:51 -08001950bool XMLElement::Accept( XMLVisitor* visitor ) const
1951{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001952 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001953 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001954 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1955 if ( !node->Accept( visitor ) ) {
1956 break;
1957 }
1958 }
1959 }
1960 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001961}
Lee Thomason56bdd022012-02-09 18:16:58 -08001962
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001963
Lee Thomason3f57d272012-01-11 15:30:03 -08001964// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001965
1966// Warning: List must match 'enum XMLError'
1967const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1968 "XML_SUCCESS",
1969 "XML_NO_ATTRIBUTE",
1970 "XML_WRONG_ATTRIBUTE_TYPE",
1971 "XML_ERROR_FILE_NOT_FOUND",
1972 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1973 "XML_ERROR_FILE_READ_ERROR",
Lee Thomason8bba8b42017-06-20 09:18:41 -07001974 "UNUSED_XML_ERROR_ELEMENT_MISMATCH",
Lee Thomason331596e2014-09-11 14:56:43 -07001975 "XML_ERROR_PARSING_ELEMENT",
1976 "XML_ERROR_PARSING_ATTRIBUTE",
Lee Thomason8bba8b42017-06-20 09:18:41 -07001977 "UNUSED_XML_ERROR_IDENTIFYING_TAG",
Lee Thomason331596e2014-09-11 14:56:43 -07001978 "XML_ERROR_PARSING_TEXT",
1979 "XML_ERROR_PARSING_CDATA",
1980 "XML_ERROR_PARSING_COMMENT",
1981 "XML_ERROR_PARSING_DECLARATION",
1982 "XML_ERROR_PARSING_UNKNOWN",
1983 "XML_ERROR_EMPTY_DOCUMENT",
1984 "XML_ERROR_MISMATCHED_ELEMENT",
1985 "XML_ERROR_PARSING",
1986 "XML_CAN_NOT_CONVERT_TEXT",
1987 "XML_NO_TEXT_NODE"
1988};
1989
1990
Dmitry-Meae8a82a2017-03-03 15:40:32 +03001991XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001992 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001993 _writeBOM( false ),
1994 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07001995 _errorID(XML_SUCCESS),
Dmitry-Meae8a82a2017-03-03 15:40:32 +03001996 _whitespaceMode( whitespaceMode ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02001997 _errorStr1(),
1998 _errorStr2(),
Dmitry-Mef89bd3e2017-01-18 18:33:55 +03001999 _errorLineNum( 0 ),
2000 _charBuffer( 0 ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002001 _parseCurLineNum( 0 ),
2002 _unlinked(),
2003 _elementPool(),
2004 _attributePool(),
2005 _textPool(),
2006 _commentPool()
U-Lama\Lee560bd472011-12-28 19:42:49 -08002007{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03002008 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
2009 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08002010}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08002011
2012
Lee Thomason3f57d272012-01-11 15:30:03 -08002013XMLDocument::~XMLDocument()
2014{
Lee Thomasonf07b9522014-10-30 13:25:12 -07002015 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08002016}
2017
2018
Lee Thomason816d3fa2017-06-05 14:35:55 -07002019void XMLDocument::MarkInUse(XMLNode* node)
2020{
Dmitry-Mec2f677b2017-06-15 12:44:27 +03002021 TIXMLASSERT(node);
Lee Thomason816d3fa2017-06-05 14:35:55 -07002022 TIXMLASSERT(node->_parent == 0);
2023
2024 for (int i = 0; i < _unlinked.Size(); ++i) {
2025 if (node == _unlinked[i]) {
2026 _unlinked.SwapRemove(i);
2027 break;
2028 }
2029 }
2030}
2031
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002032void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08002033{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002034 DeleteChildren();
Lee Thomason816d3fa2017-06-05 14:35:55 -07002035 while( _unlinked.Size()) {
2036 DeleteNode(_unlinked[0]); // Will remove from _unlinked as part of delete.
2037 }
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002038
Dmitry-Meab37df82014-11-28 12:08:36 +03002039#ifdef DEBUG
2040 const bool hadError = Error();
2041#endif
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002042 ClearError();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002043
Lee Thomason624d43f2012-10-12 10:58:48 -07002044 delete [] _charBuffer;
2045 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07002046
2047#if 0
2048 _textPool.Trace( "text" );
2049 _elementPool.Trace( "element" );
2050 _commentPool.Trace( "comment" );
2051 _attributePool.Trace( "attribute" );
2052#endif
2053
2054#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002055 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002056 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
2057 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
2058 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
2059 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
2060 }
2061#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08002062}
2063
Lee Thomason3f57d272012-01-11 15:30:03 -08002064
Shuichiro Suzuki87cd4e02017-08-24 11:20:26 +09002065void XMLDocument::DeepCopy(XMLDocument* target) const
Lee Thomason7085f002017-06-01 18:09:43 -07002066{
2067 TIXMLASSERT(target);
Lee Thomason1346a172017-06-14 15:14:19 -07002068 if (target == this) {
2069 return; // technically success - a no-op.
2070 }
Lee Thomason7085f002017-06-01 18:09:43 -07002071
2072 target->Clear();
2073 for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {
2074 target->InsertEndChild(node->DeepClone(target));
2075 }
2076}
2077
Lee Thomason2c85a712012-01-31 08:24:24 -08002078XMLElement* XMLDocument::NewElement( const char* name )
2079{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002080 XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002081 ele->SetName( name );
2082 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08002083}
2084
2085
Lee Thomason1ff38e02012-02-14 18:18:16 -08002086XMLComment* XMLDocument::NewComment( const char* str )
2087{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002088 XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002089 comment->SetValue( str );
2090 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002091}
2092
2093
2094XMLText* XMLDocument::NewText( const char* str )
2095{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002096 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002097 text->SetValue( str );
2098 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002099}
2100
2101
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002102XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2103{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002104 XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002105 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2106 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002107}
2108
2109
2110XMLUnknown* XMLDocument::NewUnknown( const char* str )
2111{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002112 XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002113 unk->SetValue( str );
2114 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002115}
2116
Dmitry-Me01578db2014-08-19 10:18:48 +04002117static FILE* callfopen( const char* filepath, const char* mode )
2118{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002119 TIXMLASSERT( filepath );
2120 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002121#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2122 FILE* fp = 0;
2123 errno_t err = fopen_s( &fp, filepath, mode );
2124 if ( err ) {
2125 return 0;
2126 }
2127#else
2128 FILE* fp = fopen( filepath, mode );
2129#endif
2130 return fp;
2131}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08002132
2133void XMLDocument::DeleteNode( XMLNode* node ) {
2134 TIXMLASSERT( node );
2135 TIXMLASSERT(node->_document == this );
2136 if (node->_parent) {
2137 node->_parent->DeleteChild( node );
2138 }
2139 else {
2140 // Isn't in the tree.
2141 // Use the parent delete.
2142 // Also, we need to mark it tracked: we 'know'
2143 // it was never used.
2144 node->_memPool->SetTracked();
2145 // Call the static XMLNode version:
2146 XMLNode::DeleteNode(node);
2147 }
2148}
2149
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002150
Lee Thomason2fa81722012-11-09 12:37:46 -08002151XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002152{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002153 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04002154 FILE* fp = callfopen( filename, "rb" );
2155 if ( !fp ) {
kezenatorec694152016-11-26 17:21:43 +10002156 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002157 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002158 }
2159 LoadFile( fp );
2160 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002161 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002162}
2163
Dmitry-Me901fed52015-09-25 10:29:51 +03002164// This is likely overengineered template art to have a check that unsigned long value incremented
2165// by one still fits into size_t. If size_t type is larger than unsigned long type
2166// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
2167// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
2168// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
2169// types sizes relate to each other.
2170template
2171<bool = (sizeof(unsigned long) >= sizeof(size_t))>
2172struct LongFitsIntoSizeTMinusOne {
2173 static bool Fits( unsigned long value )
2174 {
2175 return value < (size_t)-1;
2176 }
2177};
2178
2179template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02002180struct LongFitsIntoSizeTMinusOne<false> {
2181 static bool Fits( unsigned long )
2182 {
2183 return true;
2184 }
2185};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002186
Lee Thomason2fa81722012-11-09 12:37:46 -08002187XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002188{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002189 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002190
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002191 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002192 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
kezenatorec694152016-11-26 17:21:43 +10002193 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002194 return _errorID;
2195 }
2196
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002197 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002198 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002199 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002200 if ( filelength == -1L ) {
kezenatorec694152016-11-26 17:21:43 +10002201 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002202 return _errorID;
2203 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002204 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002205
Dmitry-Me901fed52015-09-25 10:29:51 +03002206 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002207 // Cannot handle files which won't fit in buffer together with null terminator
kezenatorec694152016-11-26 17:21:43 +10002208 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002209 return _errorID;
2210 }
2211
Dmitry-Me72801b82015-05-07 09:41:39 +03002212 if ( filelength == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10002213 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002214 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002215 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002216
Dmitry-Me72801b82015-05-07 09:41:39 +03002217 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002218 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002219 _charBuffer = new char[size+1];
2220 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002221 if ( read != size ) {
kezenatorec694152016-11-26 17:21:43 +10002222 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002223 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002224 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002225
Lee Thomason624d43f2012-10-12 10:58:48 -07002226 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002227
Dmitry-Me97476b72015-01-01 16:15:57 +03002228 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002229 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002230}
2231
2232
Lee Thomason2fa81722012-11-09 12:37:46 -08002233XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002234{
Dmitry-Me01578db2014-08-19 10:18:48 +04002235 FILE* fp = callfopen( filename, "w" );
2236 if ( !fp ) {
kezenatorec694152016-11-26 17:21:43 +10002237 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002238 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002239 }
2240 SaveFile(fp, compact);
2241 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002242 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002243}
2244
2245
Lee Thomason2fa81722012-11-09 12:37:46 -08002246XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002247{
Ant Mitchell189198f2015-03-24 16:20:36 +00002248 // Clear any error from the last save, otherwise it will get reported
2249 // for *this* call.
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002250 ClearError();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002251 XMLPrinter stream( fp, compact );
2252 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002253 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002254}
2255
Lee Thomason1ff38e02012-02-14 18:18:16 -08002256
Lee Thomason2fa81722012-11-09 12:37:46 -08002257XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002258{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002259 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002260
Lee Thomason82d32002014-02-21 22:47:18 -08002261 if ( len == 0 || !p || !*p ) {
kezenatorec694152016-11-26 17:21:43 +10002262 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002263 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002264 }
2265 if ( len == (size_t)(-1) ) {
2266 len = strlen( p );
2267 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002268 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002269 _charBuffer = new char[ len+1 ];
2270 memcpy( _charBuffer, p, len );
2271 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002272
Dmitry-Me97476b72015-01-01 16:15:57 +03002273 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002274 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002275 // clean up now essentially dangling memory.
2276 // and the parse fail can put objects in the
2277 // pools that are dead and inaccessible.
2278 DeleteChildren();
2279 _elementPool.Clear();
2280 _attributePool.Clear();
2281 _textPool.Clear();
2282 _commentPool.Clear();
2283 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002284 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002285}
2286
2287
PKEuS1c5f99e2013-07-06 11:28:39 +02002288void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002289{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002290 if ( streamer ) {
2291 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002292 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002293 else {
2294 XMLPrinter stdoutStreamer( stdout );
2295 Accept( &stdoutStreamer );
2296 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002297}
2298
2299
kezenatorec694152016-11-26 17:21:43 +10002300void XMLDocument::SetError( XMLError error, const char* str1, const char* str2, int lineNum )
Lee Thomason67d61312012-01-24 16:01:51 -08002301{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002302 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002303 _errorID = error;
Lee Thomason584af572016-09-05 14:14:16 -07002304
2305 _errorStr1.Reset();
2306 _errorStr2.Reset();
kezenatorec694152016-11-26 17:21:43 +10002307 _errorLineNum = lineNum;
Lee Thomason584af572016-09-05 14:14:16 -07002308
2309 if (str1)
2310 _errorStr1.SetStr(str1);
2311 if (str2)
2312 _errorStr2.SetStr(str2);
Lee Thomason67d61312012-01-24 16:01:51 -08002313}
2314
Lee Thomasone90e9012016-12-24 07:34:39 -08002315/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
Lee Thomason331596e2014-09-11 14:56:43 -07002316{
kezenator5a700712016-11-26 13:54:42 +10002317 TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2318 const char* errorName = _errorNames[errorID];
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002319 TIXMLASSERT( errorName && errorName[0] );
2320 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002321}
Lee Thomason5cae8972012-01-24 18:03:07 -08002322
Lee Thomason8c9e3132017-06-26 16:55:01 -07002323const char* XMLDocument::GetErrorStr1() const
2324{
2325 return _errorStr1.GetStr();
2326}
2327
2328const char* XMLDocument::GetErrorStr2() const
2329{
2330 return _errorStr2.GetStr();
2331}
2332
kezenator5a700712016-11-26 13:54:42 +10002333const char* XMLDocument::ErrorName() const
2334{
Lee Thomasone90e9012016-12-24 07:34:39 -08002335 return ErrorIDToName(_errorID);
kezenator5a700712016-11-26 13:54:42 +10002336}
2337
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002338void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002339{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002340 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002341 static const int LEN = 20;
2342 char buf1[LEN] = { 0 };
2343 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002344
Lee Thomason584af572016-09-05 14:14:16 -07002345 if ( !_errorStr1.Empty() ) {
2346 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002347 }
Lee Thomason584af572016-09-05 14:14:16 -07002348 if ( !_errorStr2.Empty() ) {
2349 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002350 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002351
Dmitry-Me2ad43202015-04-16 12:18:58 +03002352 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2353 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2354 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
kezenatorec694152016-11-26 17:21:43 +10002355 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s line=%d\n",
2356 static_cast<int>( _errorID ), ErrorName(), buf1, buf2, _errorLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002357 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002358}
2359
Dmitry-Me97476b72015-01-01 16:15:57 +03002360void XMLDocument::Parse()
2361{
2362 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2363 TIXMLASSERT( _charBuffer );
kezenatorec694152016-11-26 17:21:43 +10002364 _parseCurLineNum = 1;
2365 _parseLineNum = 1;
Lee Thomason3cebdc42015-01-05 17:16:28 -08002366 char* p = _charBuffer;
kezenator4f756162016-11-29 19:46:27 +10002367 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mee28be752015-01-09 14:59:30 +03002368 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002369 if ( !*p ) {
kezenatorec694152016-11-26 17:21:43 +10002370 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002371 return;
2372 }
kezenator4f756162016-11-29 19:46:27 +10002373 ParseDeep(p, 0, &_parseCurLineNum );
Dmitry-Me97476b72015-01-01 16:15:57 +03002374}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002375
PKEuS1bfb9542013-08-04 13:51:17 +02002376XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002377 _elementJustOpened( false ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002378 _stack(),
Lee Thomason624d43f2012-10-12 10:58:48 -07002379 _firstElement( true ),
2380 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002381 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002382 _textDepth( -1 ),
2383 _processEntities( true ),
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002384 _compactMode( compact ),
2385 _buffer()
Lee Thomason5cae8972012-01-24 18:03:07 -08002386{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002387 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002388 _entityFlag[i] = false;
2389 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002390 }
2391 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002392 const char entityValue = entities[i].value;
Dmitry-Mea28eb072017-08-25 18:34:18 +03002393 const unsigned char flagIndex = (unsigned char)entityValue;
2394 TIXMLASSERT( flagIndex < ENTITY_RANGE );
2395 _entityFlag[flagIndex] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002396 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002397 _restrictedEntityFlag[(unsigned char)'&'] = true;
2398 _restrictedEntityFlag[(unsigned char)'<'] = true;
2399 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002400 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002401}
2402
2403
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002404void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002405{
2406 va_list va;
2407 va_start( va, format );
2408
Lee Thomason624d43f2012-10-12 10:58:48 -07002409 if ( _fp ) {
2410 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002411 }
2412 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002413 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002414 // Close out and re-start the va-args
2415 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002416 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002417 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002418 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002419 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002420 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002421 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002422 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002423}
2424
2425
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002426void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002427{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002428 for( int i=0; i<depth; ++i ) {
2429 Print( " " );
2430 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002431}
2432
2433
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002434void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002435{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002436 // Look for runs of bytes between entities to print.
2437 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002438
Lee Thomason624d43f2012-10-12 10:58:48 -07002439 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002440 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002441 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002442 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002443 // Remember, char is sometimes signed. (How many times has that bitten me?)
2444 if ( *q > 0 && *q < ENTITY_RANGE ) {
2445 // Check for entities. If one is found, flush
2446 // the stream up until the entity, write the
2447 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002448 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002449 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002450 const size_t delta = q - p;
2451 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002452 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002453 Print( "%.*s", toPrint, p );
2454 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002455 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002456 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002457 for( int i=0; i<NUM_ENTITIES; ++i ) {
2458 if ( entities[i].value == *q ) {
2459 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002460 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002461 break;
2462 }
2463 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002464 if ( !entityPatternPrinted ) {
2465 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2466 TIXMLASSERT( false );
2467 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002468 ++p;
2469 }
2470 }
2471 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002472 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002473 }
2474 }
2475 // Flush the remaining string. This will be the entire
2476 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002477 TIXMLASSERT( p <= q );
2478 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002479 Print( "%s", p );
2480 }
Lee Thomason857b8682012-01-25 17:50:25 -08002481}
2482
U-Stream\Leeae25a442012-02-17 17:48:16 -08002483
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002484void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002485{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002486 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002487 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 -07002488 Print( "%s", bom );
2489 }
2490 if ( writeDec ) {
2491 PushDeclaration( "xml version=\"1.0\"" );
2492 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002493}
2494
2495
Uli Kusterer593a33d2014-02-01 12:48:51 +01002496void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002497{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002498 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002499 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002500
Uli Kusterer593a33d2014-02-01 12:48:51 +01002501 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002502 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002503 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002504 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002505 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002506 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002507
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002508 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002509 _elementJustOpened = true;
2510 _firstElement = false;
2511 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002512}
2513
2514
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002515void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002516{
Lee Thomason624d43f2012-10-12 10:58:48 -07002517 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002518 Print( " %s=\"", name );
2519 PrintString( value, false );
2520 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002521}
2522
2523
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002524void XMLPrinter::PushAttribute( const char* name, int v )
2525{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002526 char buf[BUF_SIZE];
2527 XMLUtil::ToStr( v, buf, BUF_SIZE );
2528 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002529}
2530
2531
2532void XMLPrinter::PushAttribute( const char* name, unsigned v )
2533{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002534 char buf[BUF_SIZE];
2535 XMLUtil::ToStr( v, buf, BUF_SIZE );
2536 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002537}
2538
2539
Lee Thomason51c12712016-06-04 20:18:49 -07002540void XMLPrinter::PushAttribute(const char* name, int64_t v)
2541{
2542 char buf[BUF_SIZE];
2543 XMLUtil::ToStr(v, buf, BUF_SIZE);
2544 PushAttribute(name, buf);
2545}
2546
2547
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002548void XMLPrinter::PushAttribute( const char* name, bool v )
2549{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002550 char buf[BUF_SIZE];
2551 XMLUtil::ToStr( v, buf, BUF_SIZE );
2552 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002553}
2554
2555
2556void XMLPrinter::PushAttribute( const char* name, double v )
2557{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002558 char buf[BUF_SIZE];
2559 XMLUtil::ToStr( v, buf, BUF_SIZE );
2560 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002561}
2562
2563
Uli Kustererca412e82014-02-01 13:35:05 +01002564void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002565{
Lee Thomason624d43f2012-10-12 10:58:48 -07002566 --_depth;
2567 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002568
Lee Thomason624d43f2012-10-12 10:58:48 -07002569 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002570 Print( "/>" );
2571 }
2572 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002573 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002574 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002575 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002576 }
2577 Print( "</%s>", name );
2578 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002579
Lee Thomason624d43f2012-10-12 10:58:48 -07002580 if ( _textDepth == _depth ) {
2581 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002582 }
Uli Kustererca412e82014-02-01 13:35:05 +01002583 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002584 Print( "\n" );
2585 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002586 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002587}
2588
2589
Dmitry-Mea092bc12014-12-23 17:57:05 +03002590void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002591{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002592 if ( !_elementJustOpened ) {
2593 return;
2594 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002595 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002596 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002597}
2598
2599
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002600void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002601{
Lee Thomason624d43f2012-10-12 10:58:48 -07002602 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002603
Dmitry-Mea092bc12014-12-23 17:57:05 +03002604 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002605 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002606 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002607 }
2608 else {
2609 PrintString( text, true );
2610 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002611}
2612
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002613void XMLPrinter::PushText( int64_t value )
2614{
2615 char buf[BUF_SIZE];
2616 XMLUtil::ToStr( value, buf, BUF_SIZE );
2617 PushText( buf, false );
2618}
2619
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002620void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002621{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002622 char buf[BUF_SIZE];
2623 XMLUtil::ToStr( value, buf, BUF_SIZE );
2624 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002625}
2626
2627
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002628void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002629{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002630 char buf[BUF_SIZE];
2631 XMLUtil::ToStr( value, buf, BUF_SIZE );
2632 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002633}
2634
2635
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002636void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002637{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002638 char buf[BUF_SIZE];
2639 XMLUtil::ToStr( value, buf, BUF_SIZE );
2640 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002641}
2642
2643
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002644void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002645{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002646 char buf[BUF_SIZE];
2647 XMLUtil::ToStr( value, buf, BUF_SIZE );
2648 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002649}
2650
2651
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002652void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002653{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002654 char buf[BUF_SIZE];
2655 XMLUtil::ToStr( value, buf, BUF_SIZE );
2656 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002657}
2658
Lee Thomason5cae8972012-01-24 18:03:07 -08002659
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002660void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002661{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002662 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002663 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002664 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002665 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002666 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002667 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002668 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002669}
Lee Thomason751da522012-02-10 08:50:51 -08002670
2671
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002672void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002673{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002674 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002675 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002676 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002677 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002678 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002679 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002680 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002681}
2682
2683
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002684void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002685{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002686 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002687 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002688 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002689 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002690 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002691 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002692 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002693}
2694
2695
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002696bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002697{
Lee Thomason624d43f2012-10-12 10:58:48 -07002698 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002699 if ( doc.HasBOM() ) {
2700 PushHeader( true, false );
2701 }
2702 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002703}
2704
2705
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002706bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002707{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002708 const XMLElement* parentElem = 0;
2709 if ( element.Parent() ) {
2710 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002711 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002712 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002713 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002714 while ( attribute ) {
2715 PushAttribute( attribute->Name(), attribute->Value() );
2716 attribute = attribute->Next();
2717 }
2718 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002719}
2720
2721
Uli Kustererca412e82014-02-01 13:35:05 +01002722bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002723{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002724 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002725 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002726}
2727
2728
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002729bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002730{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002731 PushText( text.Value(), text.CData() );
2732 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002733}
2734
2735
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002736bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002737{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002738 PushComment( comment.Value() );
2739 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002740}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002741
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002742bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002743{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002744 PushDeclaration( declaration.Value() );
2745 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002746}
2747
2748
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002749bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002750{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002751 PushUnknown( unknown.Value() );
2752 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002753}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002754
Lee Thomason685b8952012-11-12 13:00:06 -08002755} // namespace tinyxml2
2756