blob: fef6ae030683cccc74282bfbf5e7511739fa1501 [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
U-Lama\Lee560bd472011-12-28 19:42:49 -080024#include "tinyxml2.h"
25
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070026#include <new> // yes, this one new style header, is in the Android SDK.
Wilfred van Velzen67abee52016-03-25 14:01:15 +010027#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)
Lee Thomasona9cf3f92012-10-11 16:56:51 -070028# include <stddef.h>
Philipp Kloke358202c2015-07-30 16:02:26 +020029# include <stdarg.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070030#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070031# include <cstddef>
Philipp Kloke358202c2015-07-30 16:02:26 +020032# include <cstdarg>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070033#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080034
Lee Thomason53db4a62015-06-11 22:52:08 -070035#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
Dmitry-Me1ca593c2015-06-22 12:49:32 +030036 // Microsoft Visual Studio, version 2005 and higher. Not WinCE.
Lee Thomason53db4a62015-06-11 22:52:08 -070037 /*int _snprintf_s(
38 char *buffer,
39 size_t sizeOfBuffer,
40 size_t count,
41 const char *format [,
42 argument] ...
43 );*/
PKEuScac75782015-08-15 18:17:27 +020044 static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
Lee Thomason53db4a62015-06-11 22:52:08 -070045 {
46 va_list va;
47 va_start( va, format );
48 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
49 va_end( va );
50 return result;
51 }
52
PKEuScac75782015-08-15 18:17:27 +020053 static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070054 {
55 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
56 return result;
57 }
58
59 #define TIXML_VSCPRINTF _vscprintf
60 #define TIXML_SSCANF sscanf_s
61#elif defined _MSC_VER
62 // Microsoft Visual Studio 2003 and earlier or WinCE
63 #define TIXML_SNPRINTF _snprintf
64 #define TIXML_VSNPRINTF _vsnprintf
65 #define TIXML_SSCANF sscanf
Lee Thomasonaa8566b2015-06-19 16:52:40 -070066 #if (_MSC_VER < 1400 ) && (!defined WINCE)
Lee Thomason53db4a62015-06-11 22:52:08 -070067 // Microsoft Visual Studio 2003 and not WinCE.
68 #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have.
69 #else
70 // Microsoft Visual Studio 2003 and earlier or WinCE.
PKEuScac75782015-08-15 18:17:27 +020071 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070072 {
73 int len = 512;
74 for (;;) {
75 len = len*2;
76 char* str = new char[len]();
77 const int required = _vsnprintf(str, len, format, va);
78 delete[] str;
79 if ( required != -1 ) {
Dmitry-Me1d32e582015-07-27 17:11:51 +030080 TIXMLASSERT( required >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070081 len = required;
82 break;
83 }
84 }
Dmitry-Me1d32e582015-07-27 17:11:51 +030085 TIXMLASSERT( len >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070086 return len;
87 }
88 #endif
89#else
90 // GCC version 3 and higher
91 //#warning( "Using sn* functions." )
92 #define TIXML_SNPRINTF snprintf
93 #define TIXML_VSNPRINTF vsnprintf
PKEuScac75782015-08-15 18:17:27 +020094 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070095 {
96 int len = vsnprintf( 0, 0, format, va );
Dmitry-Me1d32e582015-07-27 17:11:51 +030097 TIXMLASSERT( len >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070098 return len;
99 }
100 #define TIXML_SSCANF sscanf
101#endif
102
103
Lee Thomasone4422302012-01-20 17:59:50 -0800104static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -0800105static const char LF = LINE_FEED;
106static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
107static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -0800108static const char SINGLE_QUOTE = '\'';
109static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -0800110
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800111// Bunch of unicode info at:
112// http://www.unicode.org/faq/utf_bom.html
113// ef bb bf (Microsoft "lead bytes") - designates UTF-8
114
115static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
116static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
117static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800118
Kevin Wojniak04c22d22012-11-08 11:02:22 -0800119namespace tinyxml2
120{
121
Lee Thomason8ee79892012-01-25 17:44:30 -0800122struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700123 const char* pattern;
124 int length;
125 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -0800126};
127
128static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700129static const Entity entities[NUM_ENTITIES] = {
130 { "quot", 4, DOUBLE_QUOTE },
131 { "amp", 3, '&' },
132 { "apos", 4, SINGLE_QUOTE },
133 { "lt", 2, '<' },
134 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -0800135};
136
Lee Thomasonfde6a752012-01-14 18:08:12 -0800137
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800138StrPair::~StrPair()
139{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700140 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800141}
142
143
Lee Thomason29658802014-11-27 22:31:11 -0800144void StrPair::TransferTo( StrPair* other )
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300145{
Lee Thomason29658802014-11-27 22:31:11 -0800146 if ( this == other ) {
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300147 return;
148 }
149 // This in effect implements the assignment operator by "moving"
150 // ownership (as in auto_ptr).
151
Dmitry-Medb02b212016-08-04 17:16:05 +0300152 TIXMLASSERT( other != 0 );
Lee Thomason29658802014-11-27 22:31:11 -0800153 TIXMLASSERT( other->_flags == 0 );
154 TIXMLASSERT( other->_start == 0 );
155 TIXMLASSERT( other->_end == 0 );
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300156
Lee Thomason29658802014-11-27 22:31:11 -0800157 other->Reset();
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300158
Lee Thomason29658802014-11-27 22:31:11 -0800159 other->_flags = _flags;
160 other->_start = _start;
161 other->_end = _end;
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300162
163 _flags = 0;
164 _start = 0;
165 _end = 0;
166}
167
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800168void StrPair::Reset()
169{
Lee Thomason120b3a62012-10-12 10:06:59 -0700170 if ( _flags & NEEDS_DELETE ) {
171 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700172 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700173 _flags = 0;
174 _start = 0;
175 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800176}
177
178
179void StrPair::SetStr( const char* str, int flags )
180{
Dmitry-Me0515fa92015-12-09 11:54:06 +0300181 TIXMLASSERT( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700182 Reset();
183 size_t len = strlen( str );
Dmitry-Me96f38cc2015-08-10 16:45:12 +0300184 TIXMLASSERT( _start == 0 );
Lee Thomason120b3a62012-10-12 10:06:59 -0700185 _start = new char[ len+1 ];
186 memcpy( _start, str, len+1 );
187 _end = _start + len;
188 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800189}
190
191
kezenator4f756162016-11-29 19:46:27 +1000192char* StrPair::ParseText( char* p, const char* endTag, int strFlags, int* curLineNumPtr )
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800193{
Dmitry-Mef9f3c3e2016-08-30 15:51:55 +0300194 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700195 TIXMLASSERT( endTag && *endTag );
Lee Thomasone90e9012016-12-24 07:34:39 -0800196 TIXMLASSERT(curLineNumPtr);
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800197
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400198 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700199 char endChar = *endTag;
200 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800201
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700202 // Inner loop of text parsing.
203 while ( *p ) {
204 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
205 Set( start, p, strFlags );
206 return p + length;
kezenatorec694152016-11-26 17:21:43 +1000207 } else if (*p == '\n') {
kezenator4f756162016-11-29 19:46:27 +1000208 ++(*curLineNumPtr);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700209 }
210 ++p;
Dmitry-Mef9f3c3e2016-08-30 15:51:55 +0300211 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700212 }
213 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800214}
215
216
217char* StrPair::ParseName( char* p )
218{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400219 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700220 return 0;
221 }
JayXonee525db2014-12-24 04:01:42 -0500222 if ( !XMLUtil::IsNameStartChar( *p ) ) {
223 return 0;
224 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800225
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400226 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500227 ++p;
228 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700229 ++p;
230 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800231
JayXonee525db2014-12-24 04:01:42 -0500232 Set( start, p, 0 );
233 return p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800234}
235
236
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700237void StrPair::CollapseWhitespace()
238{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400239 // Adjusting _start would cause undefined behavior on delete[]
240 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700241 // Trim leading space.
Lee Thomasone90e9012016-12-24 07:34:39 -0800242 _start = XMLUtil::SkipWhiteSpace( _start, 0 );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700243
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300244 if ( *_start ) {
Dmitry-Me24495822016-09-02 16:53:32 +0300245 const char* p = _start; // the read pointer
Lee Thomason120b3a62012-10-12 10:06:59 -0700246 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700247
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700248 while( *p ) {
249 if ( XMLUtil::IsWhiteSpace( *p )) {
Lee Thomasone90e9012016-12-24 07:34:39 -0800250 p = XMLUtil::SkipWhiteSpace( p, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700251 if ( *p == 0 ) {
252 break; // don't write to q; this trims the trailing space.
253 }
254 *q = ' ';
255 ++q;
256 }
257 *q = *p;
258 ++q;
259 ++p;
260 }
261 *q = 0;
262 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700263}
264
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800265
Lee Thomasone4422302012-01-20 17:59:50 -0800266const char* StrPair::GetStr()
267{
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300268 TIXMLASSERT( _start );
269 TIXMLASSERT( _end );
Lee Thomason120b3a62012-10-12 10:06:59 -0700270 if ( _flags & NEEDS_FLUSH ) {
271 *_end = 0;
272 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800273
Lee Thomason120b3a62012-10-12 10:06:59 -0700274 if ( _flags ) {
Dmitry-Me24495822016-09-02 16:53:32 +0300275 const char* p = _start; // the read pointer
Lee Thomason120b3a62012-10-12 10:06:59 -0700276 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800277
Lee Thomason120b3a62012-10-12 10:06:59 -0700278 while( p < _end ) {
279 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700280 // CR-LF pair becomes LF
281 // CR alone becomes LF
282 // LF-CR becomes LF
283 if ( *(p+1) == LF ) {
284 p += 2;
285 }
286 else {
287 ++p;
288 }
Dmitry-Mefed51122016-09-06 18:08:55 +0300289 *q = LF;
290 ++q;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700291 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700292 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700293 if ( *(p+1) == CR ) {
294 p += 2;
295 }
296 else {
297 ++p;
298 }
Dmitry-Mefed51122016-09-06 18:08:55 +0300299 *q = LF;
300 ++q;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700301 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700302 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700303 // Entities handled by tinyXML2:
304 // - special entities in the entity table [in/out]
305 // - numeric character reference [in]
306 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800307
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700308 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400309 const int buflen = 10;
310 char buf[buflen] = { 0 };
311 int len = 0;
Dmitry-Me6f51c802015-03-14 13:25:03 +0300312 char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
313 if ( adjusted == 0 ) {
314 *q = *p;
315 ++p;
316 ++q;
317 }
318 else {
319 TIXMLASSERT( 0 <= len && len <= buflen );
320 TIXMLASSERT( q + len <= adjusted );
321 p = adjusted;
322 memcpy( q, buf, len );
323 q += len;
324 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700325 }
326 else {
Dmitry-Me764545e2015-05-20 10:29:24 +0300327 bool entityFound = false;
328 for( int i = 0; i < NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400329 const Entity& entity = entities[i];
330 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
331 && *( p + entity.length + 1 ) == ';' ) {
332 // Found an entity - convert.
333 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700334 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400335 p += entity.length + 2;
Dmitry-Me764545e2015-05-20 10:29:24 +0300336 entityFound = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700337 break;
338 }
339 }
Dmitry-Me764545e2015-05-20 10:29:24 +0300340 if ( !entityFound ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700341 // fixme: treat as error?
342 ++p;
343 ++q;
344 }
345 }
346 }
347 else {
348 *q = *p;
349 ++p;
350 ++q;
351 }
352 }
353 *q = 0;
354 }
355 // The loop below has plenty going on, and this
356 // is a less useful mode. Break it out.
Dmitry-Me5420e542015-05-20 10:51:26 +0300357 if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700358 CollapseWhitespace();
359 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700360 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700361 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300362 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700363 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800364}
365
Lee Thomason2c85a712012-01-31 08:24:24 -0800366
Lee Thomasone4422302012-01-20 17:59:50 -0800367
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800368
Lee Thomason56bdd022012-02-09 18:16:58 -0800369// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800370
Lee Thomasonf458d262016-12-26 22:47:25 -0800371const char* XMLUtil::writeBoolTrue = "true";
372const char* XMLUtil::writeBoolFalse = "false";
Lee Thomasonce667c92016-12-26 16:45:30 -0800373
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800374void XMLUtil::SetBoolSerialization(const char* writeTrue, const char* writeFalse)
Lee Thomasonce667c92016-12-26 16:45:30 -0800375{
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800376 static const char* defTrue = "true";
Lee Thomasonce667c92016-12-26 16:45:30 -0800377 static const char* defFalse = "false";
Lee Thomasonce667c92016-12-26 16:45:30 -0800378
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800379 writeBoolTrue = (writeTrue) ? writeTrue : defTrue;
380 writeBoolFalse = (writeFalse) ? writeFalse : defFalse;
Lee Thomasonce667c92016-12-26 16:45:30 -0800381}
382
383
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800384const char* XMLUtil::ReadBOM( const char* p, bool* bom )
385{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300386 TIXMLASSERT( p );
387 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700388 *bom = false;
389 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
390 // Check for BOM:
391 if ( *(pu+0) == TIXML_UTF_LEAD_0
392 && *(pu+1) == TIXML_UTF_LEAD_1
393 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
394 *bom = true;
395 p += 3;
396 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300397 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700398 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800399}
400
401
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800402void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
403{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700404 const unsigned long BYTE_MASK = 0xBF;
405 const unsigned long BYTE_MARK = 0x80;
406 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800407
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700408 if (input < 0x80) {
409 *length = 1;
410 }
411 else if ( input < 0x800 ) {
412 *length = 2;
413 }
414 else if ( input < 0x10000 ) {
415 *length = 3;
416 }
417 else if ( input < 0x200000 ) {
418 *length = 4;
419 }
420 else {
Dmitry-Me2f465c42015-03-16 11:08:23 +0300421 *length = 0; // This code won't convert this correctly anyway.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700422 return;
423 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800424
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700425 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800426
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700427 // Scary scary fall throughs.
428 switch (*length) {
429 case 4:
430 --output;
431 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
432 input >>= 6;
433 case 3:
434 --output;
435 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
436 input >>= 6;
437 case 2:
438 --output;
439 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
440 input >>= 6;
441 case 1:
442 --output;
443 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100444 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300445 default:
446 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700447 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800448}
449
450
451const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
452{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700453 // Presume an entity, and pull it out.
454 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800455
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700456 if ( *(p+1) == '#' && *(p+2) ) {
457 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300458 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700459 ptrdiff_t delta = 0;
460 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800461 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800462
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700463 if ( *(p+2) == 'x' ) {
464 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300465 const char* q = p+3;
466 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700467 return 0;
468 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800469
Lee Thomason7e67bc82015-01-12 14:05:12 -0800470 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800471
Dmitry-Me9f56e122015-01-12 10:07:54 +0300472 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700473 return 0;
474 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800475 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800476
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700477 delta = q-p;
478 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800479
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700480 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700481 unsigned int digit = 0;
482
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700483 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300484 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700485 }
486 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300487 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700488 }
489 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300490 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700491 }
492 else {
493 return 0;
494 }
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100495 TIXMLASSERT( digit < 16 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300496 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
497 const unsigned int digitScaled = mult * digit;
498 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
499 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300500 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700501 mult *= 16;
502 --q;
503 }
504 }
505 else {
506 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300507 const char* q = p+2;
508 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700509 return 0;
510 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800511
Lee Thomason7e67bc82015-01-12 14:05:12 -0800512 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800513
Dmitry-Me9f56e122015-01-12 10:07:54 +0300514 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700515 return 0;
516 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800517 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800518
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700519 delta = q-p;
520 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800521
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700522 while ( *q != '#' ) {
523 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300524 const unsigned int digit = *q - '0';
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100525 TIXMLASSERT( digit < 10 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300526 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
527 const unsigned int digitScaled = mult * digit;
528 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
529 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700530 }
531 else {
532 return 0;
533 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300534 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700535 mult *= 10;
536 --q;
537 }
538 }
539 // convert the UCS to UTF-8
540 ConvertUTF32ToUTF8( ucs, value, length );
541 return p + delta + 1;
542 }
543 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800544}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800545
546
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700547void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700548{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700549 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700550}
551
552
553void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
554{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700555 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700556}
557
558
559void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
560{
Lee Thomasonce667c92016-12-26 16:45:30 -0800561 TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? writeBoolTrue : writeBoolFalse);
Lee Thomason21be8822012-07-15 17:27:22 -0700562}
563
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800564/*
565 ToStr() of a number is a very tricky topic.
566 https://github.com/leethomason/tinyxml2/issues/106
567*/
Lee Thomason21be8822012-07-15 17:27:22 -0700568void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
569{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800570 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700571}
572
573
574void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
575{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800576 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700577}
578
579
Lee Thomason51c12712016-06-04 20:18:49 -0700580void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize)
581{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700582 // horrible syntax trick to make the compiler happy about %lld
583 TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v);
Lee Thomason51c12712016-06-04 20:18:49 -0700584}
585
586
Lee Thomason21be8822012-07-15 17:27:22 -0700587bool XMLUtil::ToInt( const char* str, int* value )
588{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700589 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
590 return true;
591 }
592 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700593}
594
595bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
596{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700597 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
598 return true;
599 }
600 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700601}
602
603bool XMLUtil::ToBool( const char* str, bool* value )
604{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700605 int ival = 0;
606 if ( ToInt( str, &ival )) {
607 *value = (ival==0) ? false : true;
608 return true;
609 }
610 if ( StringEqual( str, "true" ) ) {
611 *value = true;
612 return true;
613 }
614 else if ( StringEqual( str, "false" ) ) {
615 *value = false;
616 return true;
617 }
618 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700619}
620
621
622bool XMLUtil::ToFloat( const char* str, float* value )
623{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700624 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
625 return true;
626 }
627 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700628}
629
Lee Thomason51c12712016-06-04 20:18:49 -0700630
Lee Thomason21be8822012-07-15 17:27:22 -0700631bool XMLUtil::ToDouble( const char* str, double* value )
632{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700633 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
634 return true;
635 }
636 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700637}
638
639
Lee Thomason51c12712016-06-04 20:18:49 -0700640bool XMLUtil::ToInt64(const char* str, int64_t* value)
641{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700642 long long v = 0; // horrible syntax trick to make the compiler happy about %lld
643 if (TIXML_SSCANF(str, "%lld", &v) == 1) {
644 *value = (int64_t)v;
Lee Thomason51c12712016-06-04 20:18:49 -0700645 return true;
646 }
647 return false;
648}
649
650
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700651char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800652{
Dmitry-Me02384662015-03-03 16:02:13 +0300653 TIXMLASSERT( node );
654 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400655 char* const start = p;
kezenatorec694152016-11-26 17:21:43 +1000656 int const startLine = _parseCurLineNum;
kezenator4f756162016-11-29 19:46:27 +1000657 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300658 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300659 *node = 0;
660 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700661 return p;
662 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800663
Dmitry-Me962083b2015-05-26 11:38:30 +0300664 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700665 static const char* xmlHeader = { "<?" };
666 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700667 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300668 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700669 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800670
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700671 static const int xmlHeaderLen = 2;
672 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700673 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300674 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700675 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800676
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700677 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
678 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400679 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700680 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300681 returnNode = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000682 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700683 p += xmlHeaderLen;
684 }
685 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300686 returnNode = CreateUnlinkedNode<XMLComment>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000687 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700688 p += commentHeaderLen;
689 }
690 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300691 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700692 returnNode = text;
kezenatorec694152016-11-26 17:21:43 +1000693 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700694 p += cdataHeaderLen;
695 text->SetCData( true );
696 }
697 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300698 returnNode = CreateUnlinkedNode<XMLUnknown>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000699 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700700 p += dtdHeaderLen;
701 }
702 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300703 returnNode = CreateUnlinkedNode<XMLElement>( _elementPool );
kezenatorec694152016-11-26 17:21:43 +1000704 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700705 p += elementHeaderLen;
706 }
707 else {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300708 returnNode = CreateUnlinkedNode<XMLText>( _textPool );
kezenatorec694152016-11-26 17:21:43 +1000709 returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700710 p = start; // Back it up, all the text counts.
kezenatorec694152016-11-26 17:21:43 +1000711 _parseCurLineNum = startLine;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700712 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800713
Dmitry-Me02384662015-03-03 16:02:13 +0300714 TIXMLASSERT( returnNode );
715 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700716 *node = returnNode;
717 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800718}
719
720
Lee Thomason751da522012-02-10 08:50:51 -0800721bool XMLDocument::Accept( XMLVisitor* visitor ) const
722{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300723 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700724 if ( visitor->VisitEnter( *this ) ) {
725 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
726 if ( !node->Accept( visitor ) ) {
727 break;
728 }
729 }
730 }
731 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800732}
Lee Thomason56bdd022012-02-09 18:16:58 -0800733
734
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800735// --------- XMLNode ----------- //
736
737XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700738 _document( doc ),
739 _parent( 0 ),
kezenatorec694152016-11-26 17:21:43 +1000740 _parseLineNum( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -0700741 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200742 _prev( 0 ), _next( 0 ),
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700743 _userData( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200744 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800745{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800746}
747
748
749XMLNode::~XMLNode()
750{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700751 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700752 if ( _parent ) {
753 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700754 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800755}
756
Michael Daumling21626882013-10-22 17:03:37 +0200757const char* XMLNode::Value() const
758{
Dmitry-Mecaa72a62016-08-10 17:34:34 +0300759 // Edge case: XMLDocuments don't have a Value. Return null.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530760 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530761 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200762 return _value.GetStr();
763}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800764
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800765void XMLNode::SetValue( const char* str, bool staticMem )
766{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700767 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700768 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700769 }
770 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700771 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700772 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800773}
774
Dmitry-Me3f63f212017-06-19 18:25:19 +0300775XMLNode* XMLNode::DeepClone(XMLDocument* target) const
Lee Thomason7085f002017-06-01 18:09:43 -0700776{
Dmitry-Me3f63f212017-06-19 18:25:19 +0300777 XMLNode* clone = this->ShallowClone(target);
Lee Thomason7085f002017-06-01 18:09:43 -0700778 if (!clone) return 0;
779
780 for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) {
Dmitry-Me3f63f212017-06-19 18:25:19 +0300781 XMLNode* childClone = child->DeepClone(target);
Lee Thomason7085f002017-06-01 18:09:43 -0700782 TIXMLASSERT(childClone);
783 clone->InsertEndChild(childClone);
784 }
785 return clone;
786}
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800787
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800788void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800789{
Lee Thomason624d43f2012-10-12 10:58:48 -0700790 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300791 TIXMLASSERT( _lastChild );
Dmitry-Me9cb4eca2016-08-18 18:10:59 +0300792 DeleteChild( _firstChild );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700793 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700794 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800795}
796
797
798void XMLNode::Unlink( XMLNode* child )
799{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300800 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300801 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300802 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700803 if ( child == _firstChild ) {
804 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700805 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700806 if ( child == _lastChild ) {
807 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700808 }
Lee Thomasond923c672012-01-23 08:44:25 -0800809
Lee Thomason624d43f2012-10-12 10:58:48 -0700810 if ( child->_prev ) {
811 child->_prev->_next = child->_next;
Lee Thomasonb754ddf2017-06-14 15:02:38 -0700812 child->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700813 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700814 if ( child->_next ) {
815 child->_next->_prev = child->_prev;
Lee Thomasonb754ddf2017-06-14 15:02:38 -0700816 child->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700817 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700818 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800819}
820
821
U-Stream\Leeae25a442012-02-17 17:48:16 -0800822void XMLNode::DeleteChild( XMLNode* node )
823{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300824 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300825 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700826 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100827 Unlink( node );
Lee Thomason816d3fa2017-06-05 14:35:55 -0700828 TIXMLASSERT(node->_prev == 0);
829 TIXMLASSERT(node->_next == 0);
830 TIXMLASSERT(node->_parent == 0);
Dmitry-Mee3225b12014-09-03 11:03:11 +0400831 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800832}
833
834
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800835XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
836{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300837 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300838 if ( addThis->_document != _document ) {
839 TIXMLASSERT( false );
840 return 0;
841 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800842 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700843
Lee Thomason624d43f2012-10-12 10:58:48 -0700844 if ( _lastChild ) {
845 TIXMLASSERT( _firstChild );
846 TIXMLASSERT( _lastChild->_next == 0 );
847 _lastChild->_next = addThis;
848 addThis->_prev = _lastChild;
849 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800850
Lee Thomason624d43f2012-10-12 10:58:48 -0700851 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700852 }
853 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700854 TIXMLASSERT( _firstChild == 0 );
855 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800856
Lee Thomason624d43f2012-10-12 10:58:48 -0700857 addThis->_prev = 0;
858 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700859 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700860 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700861 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800862}
863
864
Lee Thomason1ff38e02012-02-14 18:18:16 -0800865XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
866{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300867 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300868 if ( addThis->_document != _document ) {
869 TIXMLASSERT( false );
870 return 0;
871 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800872 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700873
Lee Thomason624d43f2012-10-12 10:58:48 -0700874 if ( _firstChild ) {
875 TIXMLASSERT( _lastChild );
876 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800877
Lee Thomason624d43f2012-10-12 10:58:48 -0700878 _firstChild->_prev = addThis;
879 addThis->_next = _firstChild;
880 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800881
Lee Thomason624d43f2012-10-12 10:58:48 -0700882 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700883 }
884 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700885 TIXMLASSERT( _lastChild == 0 );
886 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800887
Lee Thomason624d43f2012-10-12 10:58:48 -0700888 addThis->_prev = 0;
889 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700890 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700891 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400892 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800893}
894
895
896XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
897{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300898 TIXMLASSERT( addThis );
899 if ( addThis->_document != _document ) {
900 TIXMLASSERT( false );
901 return 0;
902 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700903
Dmitry-Meabb2d042014-12-09 12:59:31 +0300904 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700905
Lee Thomason624d43f2012-10-12 10:58:48 -0700906 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300907 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700908 return 0;
909 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800910
Lee Thomason624d43f2012-10-12 10:58:48 -0700911 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700912 // The last node or the only node.
913 return InsertEndChild( addThis );
914 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800915 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700916 addThis->_prev = afterThis;
917 addThis->_next = afterThis->_next;
918 afterThis->_next->_prev = addThis;
919 afterThis->_next = addThis;
920 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700921 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800922}
923
924
925
926
Dmitry-Me886ad972015-07-22 11:00:51 +0300927const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800928{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300929 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300930 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700931 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300932 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700933 }
934 }
935 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800936}
937
938
Dmitry-Me886ad972015-07-22 11:00:51 +0300939const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800940{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300941 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300942 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700943 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300944 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700945 }
946 }
947 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800948}
949
950
Dmitry-Me886ad972015-07-22 11:00:51 +0300951const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800952{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300953 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300954 const XMLElement* element = node->ToElementWithName( name );
955 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400956 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700957 }
958 }
959 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800960}
961
962
Dmitry-Me886ad972015-07-22 11:00:51 +0300963const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800964{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300965 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300966 const XMLElement* element = node->ToElementWithName( name );
967 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400968 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700969 }
970 }
971 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800972}
973
974
Dmitry-Me10b8ecc2017-04-12 17:57:44 +0300975char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -0800976{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700977 // This is a recursive method, but thinking about it "at the current level"
978 // it is a pretty simple flat list:
979 // <foo/>
980 // <!-- comment -->
981 //
982 // With a special case:
983 // <foo>
984 // </foo>
985 // <!-- comment -->
986 //
987 // Where the closing element (/foo) *must* be the next thing after the opening
988 // element, and the names must match. BUT the tricky bit is that the closing
989 // element will be read by the child.
990 //
991 // 'endTag' is the end tag for this node, it is returned by a call to a child.
992 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800993
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700994 while( p && *p ) {
995 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800996
Lee Thomason624d43f2012-10-12 10:58:48 -0700997 p = _document->Identify( p, &node );
Dmitry-Me43364312016-11-07 18:48:50 +0300998 TIXMLASSERT( p );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300999 if ( node == 0 ) {
1000 break;
1001 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001002
kezenatore3531812016-11-29 19:49:07 +10001003 int initialLineNum = node->_parseLineNum;
kezenatorec694152016-11-26 17:21:43 +10001004
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001005 StrPair endTag;
kezenator4f756162016-11-29 19:46:27 +10001006 p = node->ParseDeep( p, &endTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001007 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001008 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -07001009 if ( !_document->Error() ) {
kezenatore3531812016-11-29 19:49:07 +10001010 _document->SetError( XML_ERROR_PARSING, 0, 0, initialLineNum);
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001011 }
1012 break;
1013 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001014
Sarat Addepalli3df007e2015-05-20 10:43:51 +05301015 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301016 if ( decl ) {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001017 // Declarations are only allowed at document level
1018 bool wellLocated = ( ToDocument() != 0 );
1019 if ( wellLocated ) {
1020 // Multiple declarations are allowed but all declarations
1021 // must occur before anything else
1022 for ( const XMLNode* existingNode = _document->FirstChild(); existingNode; existingNode = existingNode->NextSibling() ) {
1023 if ( !existingNode->ToDeclaration() ) {
1024 wellLocated = false;
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301025 break;
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001026 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301027 }
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001028 }
1029 if ( !wellLocated ) {
kezenatore3531812016-11-29 19:49:07 +10001030 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0, initialLineNum);
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001031 DeleteNode( node );
1032 break;
1033 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301034 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301035
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001036 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001037 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -05001038 // We read the end tag. Return it to the parent.
1039 if ( ele->ClosingType() == XMLElement::CLOSING ) {
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001040 if ( parentEndTag ) {
1041 ele->_value.TransferTo( parentEndTag );
JayXone4bf6e32014-12-26 01:00:24 -05001042 }
1043 node->_memPool->SetTracked(); // created and then immediately deleted.
1044 DeleteNode( node );
1045 return p;
1046 }
1047
1048 // Handle an end tag returned to this level.
1049 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001050 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001051 if ( endTag.Empty() ) {
1052 if ( ele->ClosingType() == XMLElement::OPEN ) {
1053 mismatch = true;
1054 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001055 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001056 else {
1057 if ( ele->ClosingType() != XMLElement::OPEN ) {
1058 mismatch = true;
1059 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001060 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001061 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001062 }
1063 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001064 if ( mismatch ) {
kezenatore3531812016-11-29 19:49:07 +10001065 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0, initialLineNum);
JayXondbfdd8f2014-12-12 20:07:14 -05001066 DeleteNode( node );
1067 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001068 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001069 }
JayXondbfdd8f2014-12-12 20:07:14 -05001070 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001071 }
1072 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001073}
1074
Lee Thomason816d3fa2017-06-05 14:35:55 -07001075/*static*/ void XMLNode::DeleteNode( XMLNode* node )
Dmitry-Mee3225b12014-09-03 11:03:11 +04001076{
1077 if ( node == 0 ) {
1078 return;
1079 }
Lee Thomason816d3fa2017-06-05 14:35:55 -07001080 TIXMLASSERT(node->_document);
1081 if (!node->ToDocument()) {
1082 node->_document->MarkInUse(node);
1083 }
1084
Dmitry-Mee3225b12014-09-03 11:03:11 +04001085 MemPool* pool = node->_memPool;
1086 node->~XMLNode();
1087 pool->Free( node );
1088}
1089
Lee Thomason3cebdc42015-01-05 17:16:28 -08001090void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001091{
1092 TIXMLASSERT( insertThis );
1093 TIXMLASSERT( insertThis->_document == _document );
1094
Lee Thomason816d3fa2017-06-05 14:35:55 -07001095 if (insertThis->_parent) {
Dmitry-Me74e39402015-01-01 16:26:17 +03001096 insertThis->_parent->Unlink( insertThis );
Lee Thomason816d3fa2017-06-05 14:35:55 -07001097 }
1098 else {
1099 insertThis->_document->MarkInUse(insertThis);
Dmitry-Me74e39402015-01-01 16:26:17 +03001100 insertThis->_memPool->SetTracked();
Lee Thomason816d3fa2017-06-05 14:35:55 -07001101 }
Dmitry-Me74e39402015-01-01 16:26:17 +03001102}
1103
Dmitry-Meecb9b072016-10-12 16:44:59 +03001104const XMLElement* XMLNode::ToElementWithName( const char* name ) const
1105{
1106 const XMLElement* element = this->ToElement();
1107 if ( element == 0 ) {
1108 return 0;
1109 }
1110 if ( name == 0 ) {
1111 return element;
1112 }
1113 if ( XMLUtil::StringEqual( element->Name(), name ) ) {
1114 return element;
1115 }
1116 return 0;
1117}
1118
Lee Thomason5492a1c2012-01-23 15:32:10 -08001119// --------- XMLText ---------- //
kezenator4f756162016-11-29 19:46:27 +10001120char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001121{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001122 const char* start = p;
1123 if ( this->CData() ) {
kezenator4f756162016-11-29 19:46:27 +10001124 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001125 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001126 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001127 }
1128 return p;
1129 }
1130 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001131 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1132 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001133 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001134 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001135
kezenator4f756162016-11-29 19:46:27 +10001136 p = _value.ParseText( p, "<", flags, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001137 if ( p && *p ) {
1138 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001139 }
1140 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001141 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001142 }
1143 }
1144 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001145}
1146
1147
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001148XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1149{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001150 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001151 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001152 }
1153 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1154 text->SetCData( this->CData() );
1155 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001156}
1157
1158
1159bool XMLText::ShallowEqual( const XMLNode* compare ) const
1160{
Dmitry-Meba68a3a2017-03-21 11:39:48 +03001161 TIXMLASSERT( compare );
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001162 const XMLText* text = compare->ToText();
1163 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001164}
1165
1166
Lee Thomason56bdd022012-02-09 18:16:58 -08001167bool XMLText::Accept( XMLVisitor* visitor ) const
1168{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001169 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001170 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001171}
1172
1173
Lee Thomason3f57d272012-01-11 15:30:03 -08001174// --------- XMLComment ---------- //
1175
Lee Thomasone4422302012-01-20 17:59:50 -08001176XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001177{
1178}
1179
1180
Lee Thomasonce0763e2012-01-11 15:43:54 -08001181XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001182{
Lee Thomason3f57d272012-01-11 15:30:03 -08001183}
1184
1185
kezenator4f756162016-11-29 19:46:27 +10001186char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason3f57d272012-01-11 15:30:03 -08001187{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001188 // Comment parses as text.
1189 const char* start = p;
kezenator4f756162016-11-29 19:46:27 +10001190 p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001191 if ( p == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10001192 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001193 }
1194 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001195}
1196
1197
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001198XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1199{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001200 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001201 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001202 }
1203 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1204 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001205}
1206
1207
1208bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1209{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001210 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001211 const XMLComment* comment = compare->ToComment();
1212 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001213}
1214
1215
Lee Thomason751da522012-02-10 08:50:51 -08001216bool XMLComment::Accept( XMLVisitor* visitor ) const
1217{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001218 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001219 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001220}
Lee Thomason56bdd022012-02-09 18:16:58 -08001221
1222
Lee Thomason50f97b22012-02-11 16:33:40 -08001223// --------- XMLDeclaration ---------- //
1224
1225XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1226{
1227}
1228
1229
1230XMLDeclaration::~XMLDeclaration()
1231{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001232 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001233}
1234
1235
kezenator4f756162016-11-29 19:46:27 +10001236char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001237{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001238 // Declaration parses as text.
1239 const char* start = p;
kezenator4f756162016-11-29 19:46:27 +10001240 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001241 if ( p == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10001242 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001243 }
1244 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001245}
1246
1247
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001248XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1249{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001250 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001251 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001252 }
1253 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1254 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001255}
1256
1257
1258bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1259{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001260 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001261 const XMLDeclaration* declaration = compare->ToDeclaration();
1262 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001263}
1264
1265
1266
Lee Thomason50f97b22012-02-11 16:33:40 -08001267bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1268{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001269 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001270 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001271}
1272
1273// --------- XMLUnknown ---------- //
1274
1275XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1276{
1277}
1278
1279
1280XMLUnknown::~XMLUnknown()
1281{
1282}
1283
1284
kezenator4f756162016-11-29 19:46:27 +10001285char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001286{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001287 // Unknown parses as text.
1288 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001289
kezenator4f756162016-11-29 19:46:27 +10001290 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001291 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001292 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001293 }
1294 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001295}
1296
1297
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001298XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1299{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001300 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001301 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001302 }
1303 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1304 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001305}
1306
1307
1308bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1309{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001310 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001311 const XMLUnknown* unknown = compare->ToUnknown();
1312 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001313}
1314
1315
Lee Thomason50f97b22012-02-11 16:33:40 -08001316bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1317{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001318 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001319 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001320}
1321
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001322// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001323
1324const char* XMLAttribute::Name() const
1325{
1326 return _name.GetStr();
1327}
1328
1329const char* XMLAttribute::Value() const
1330{
1331 return _value.GetStr();
1332}
1333
kezenator4f756162016-11-29 19:46:27 +10001334char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001335{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001336 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001337 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001338 if ( !p || !*p ) {
1339 return 0;
1340 }
Lee Thomason22aead12012-01-23 13:29:35 -08001341
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001342 // Skip white space before =
kezenator4f756162016-11-29 19:46:27 +10001343 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001344 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001345 return 0;
1346 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001347
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001348 ++p; // move up to opening quote
kezenator4f756162016-11-29 19:46:27 +10001349 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001350 if ( *p != '\"' && *p != '\'' ) {
1351 return 0;
1352 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001353
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001354 char endTag[2] = { *p, 0 };
1355 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001356
kezenator4f756162016-11-29 19:46:27 +10001357 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001358 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001359}
1360
1361
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001362void XMLAttribute::SetName( const char* n )
1363{
Lee Thomason624d43f2012-10-12 10:58:48 -07001364 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001365}
1366
1367
Lee Thomason2fa81722012-11-09 12:37:46 -08001368XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001369{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001370 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001371 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001372 }
1373 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001374}
1375
1376
Lee Thomason2fa81722012-11-09 12:37:46 -08001377XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001378{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001379 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001380 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001381 }
1382 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001383}
1384
1385
Lee Thomason51c12712016-06-04 20:18:49 -07001386XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1387{
1388 if (XMLUtil::ToInt64(Value(), value)) {
1389 return XML_SUCCESS;
1390 }
1391 return XML_WRONG_ATTRIBUTE_TYPE;
1392}
1393
1394
Lee Thomason2fa81722012-11-09 12:37:46 -08001395XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001396{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001397 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001398 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001399 }
1400 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001401}
1402
1403
Lee Thomason2fa81722012-11-09 12:37:46 -08001404XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001405{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001406 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001407 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001408 }
1409 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001410}
1411
1412
Lee Thomason2fa81722012-11-09 12:37:46 -08001413XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001414{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001415 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001416 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001417 }
1418 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001419}
1420
1421
1422void XMLAttribute::SetAttribute( const char* v )
1423{
Lee Thomason624d43f2012-10-12 10:58:48 -07001424 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001425}
1426
1427
Lee Thomason1ff38e02012-02-14 18:18:16 -08001428void XMLAttribute::SetAttribute( int v )
1429{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001430 char buf[BUF_SIZE];
1431 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001432 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001433}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001434
1435
1436void XMLAttribute::SetAttribute( unsigned v )
1437{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001438 char buf[BUF_SIZE];
1439 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001440 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001441}
1442
1443
Lee Thomason51c12712016-06-04 20:18:49 -07001444void XMLAttribute::SetAttribute(int64_t v)
1445{
1446 char buf[BUF_SIZE];
1447 XMLUtil::ToStr(v, buf, BUF_SIZE);
1448 _value.SetStr(buf);
1449}
1450
1451
1452
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001453void XMLAttribute::SetAttribute( bool v )
1454{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001455 char buf[BUF_SIZE];
1456 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001457 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001458}
1459
1460void XMLAttribute::SetAttribute( double v )
1461{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001462 char buf[BUF_SIZE];
1463 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001464 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001465}
1466
1467void XMLAttribute::SetAttribute( float v )
1468{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001469 char buf[BUF_SIZE];
1470 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001471 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001472}
1473
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001474
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001475// --------- XMLElement ---------- //
1476XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Dmitry-Mee5035632017-04-05 18:02:40 +03001477 _closingType( OPEN ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001478 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001479{
1480}
1481
1482
1483XMLElement::~XMLElement()
1484{
Lee Thomason624d43f2012-10-12 10:58:48 -07001485 while( _rootAttribute ) {
1486 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001487 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001488 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001489 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001490}
1491
1492
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001493const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1494{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001495 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001496 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1497 return a;
1498 }
1499 }
1500 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001501}
1502
1503
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001504const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001505{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001506 const XMLAttribute* a = FindAttribute( name );
1507 if ( !a ) {
1508 return 0;
1509 }
1510 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1511 return a->Value();
1512 }
1513 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001514}
1515
Josh Wittnercf3dd092016-10-11 18:57:17 -07001516int XMLElement::IntAttribute(const char* name, int defaultValue) const
1517{
1518 int i = defaultValue;
1519 QueryIntAttribute(name, &i);
1520 return i;
1521}
1522
1523unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
1524{
1525 unsigned i = defaultValue;
1526 QueryUnsignedAttribute(name, &i);
1527 return i;
1528}
1529
1530int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
1531{
1532 int64_t i = defaultValue;
1533 QueryInt64Attribute(name, &i);
1534 return i;
1535}
1536
1537bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
1538{
1539 bool b = defaultValue;
1540 QueryBoolAttribute(name, &b);
1541 return b;
1542}
1543
1544double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
1545{
1546 double d = defaultValue;
1547 QueryDoubleAttribute(name, &d);
1548 return d;
1549}
1550
1551float XMLElement::FloatAttribute(const char* name, float defaultValue) const
1552{
1553 float f = defaultValue;
1554 QueryFloatAttribute(name, &f);
1555 return f;
1556}
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001557
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001558const char* XMLElement::GetText() const
1559{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001560 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001561 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001562 }
1563 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001564}
1565
1566
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001567void XMLElement::SetText( const char* inText )
1568{
Uli Kusterer869bb592014-01-21 01:36:16 +01001569 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001570 FirstChild()->SetValue( inText );
1571 else {
1572 XMLText* theText = GetDocument()->NewText( inText );
1573 InsertFirstChild( theText );
1574 }
1575}
1576
Lee Thomason5bb2d802014-01-24 10:42:57 -08001577
1578void XMLElement::SetText( int v )
1579{
1580 char buf[BUF_SIZE];
1581 XMLUtil::ToStr( v, buf, BUF_SIZE );
1582 SetText( buf );
1583}
1584
1585
1586void XMLElement::SetText( unsigned v )
1587{
1588 char buf[BUF_SIZE];
1589 XMLUtil::ToStr( v, buf, BUF_SIZE );
1590 SetText( buf );
1591}
1592
1593
Lee Thomason51c12712016-06-04 20:18:49 -07001594void XMLElement::SetText(int64_t v)
1595{
1596 char buf[BUF_SIZE];
1597 XMLUtil::ToStr(v, buf, BUF_SIZE);
1598 SetText(buf);
1599}
1600
1601
1602void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001603{
1604 char buf[BUF_SIZE];
1605 XMLUtil::ToStr( v, buf, BUF_SIZE );
1606 SetText( buf );
1607}
1608
1609
1610void XMLElement::SetText( float v )
1611{
1612 char buf[BUF_SIZE];
1613 XMLUtil::ToStr( v, buf, BUF_SIZE );
1614 SetText( buf );
1615}
1616
1617
1618void XMLElement::SetText( double v )
1619{
1620 char buf[BUF_SIZE];
1621 XMLUtil::ToStr( v, buf, BUF_SIZE );
1622 SetText( buf );
1623}
1624
1625
MortenMacFly4ee49f12013-01-14 20:03:14 +01001626XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001627{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001628 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001629 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001630 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001631 return XML_SUCCESS;
1632 }
1633 return XML_CAN_NOT_CONVERT_TEXT;
1634 }
1635 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001636}
1637
1638
MortenMacFly4ee49f12013-01-14 20:03:14 +01001639XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001640{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001641 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001642 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001643 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001644 return XML_SUCCESS;
1645 }
1646 return XML_CAN_NOT_CONVERT_TEXT;
1647 }
1648 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001649}
1650
1651
Lee Thomason51c12712016-06-04 20:18:49 -07001652XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1653{
1654 if (FirstChild() && FirstChild()->ToText()) {
1655 const char* t = FirstChild()->Value();
1656 if (XMLUtil::ToInt64(t, ival)) {
1657 return XML_SUCCESS;
1658 }
1659 return XML_CAN_NOT_CONVERT_TEXT;
1660 }
1661 return XML_NO_TEXT_NODE;
1662}
1663
1664
MortenMacFly4ee49f12013-01-14 20:03:14 +01001665XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001666{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001667 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001668 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001669 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001670 return XML_SUCCESS;
1671 }
1672 return XML_CAN_NOT_CONVERT_TEXT;
1673 }
1674 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001675}
1676
1677
MortenMacFly4ee49f12013-01-14 20:03:14 +01001678XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001679{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001680 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001681 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001682 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001683 return XML_SUCCESS;
1684 }
1685 return XML_CAN_NOT_CONVERT_TEXT;
1686 }
1687 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001688}
1689
1690
MortenMacFly4ee49f12013-01-14 20:03:14 +01001691XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001692{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001693 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001694 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001695 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001696 return XML_SUCCESS;
1697 }
1698 return XML_CAN_NOT_CONVERT_TEXT;
1699 }
1700 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001701}
1702
Josh Wittnercf3dd092016-10-11 18:57:17 -07001703int XMLElement::IntText(int defaultValue) const
1704{
1705 int i = defaultValue;
1706 QueryIntText(&i);
1707 return i;
1708}
1709
1710unsigned XMLElement::UnsignedText(unsigned defaultValue) const
1711{
1712 unsigned i = defaultValue;
1713 QueryUnsignedText(&i);
1714 return i;
1715}
1716
1717int64_t XMLElement::Int64Text(int64_t defaultValue) const
1718{
1719 int64_t i = defaultValue;
1720 QueryInt64Text(&i);
1721 return i;
1722}
1723
1724bool XMLElement::BoolText(bool defaultValue) const
1725{
1726 bool b = defaultValue;
1727 QueryBoolText(&b);
1728 return b;
1729}
1730
1731double XMLElement::DoubleText(double defaultValue) const
1732{
1733 double d = defaultValue;
1734 QueryDoubleText(&d);
1735 return d;
1736}
1737
1738float XMLElement::FloatText(float defaultValue) const
1739{
1740 float f = defaultValue;
1741 QueryFloatText(&f);
1742 return f;
1743}
Lee Thomason21be8822012-07-15 17:27:22 -07001744
1745
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001746XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1747{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001748 XMLAttribute* last = 0;
1749 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001750 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001751 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001752 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001753 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1754 break;
1755 }
1756 }
1757 if ( !attrib ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001758 attrib = CreateAttribute();
1759 TIXMLASSERT( attrib );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001760 if ( last ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001761 TIXMLASSERT( last->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001762 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001763 }
1764 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001765 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001766 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001767 }
1768 attrib->SetName( name );
1769 }
1770 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001771}
1772
1773
U-Stream\Leeae25a442012-02-17 17:48:16 -08001774void XMLElement::DeleteAttribute( const char* name )
1775{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001776 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001777 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001778 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1779 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001780 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001781 }
1782 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001783 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001784 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001785 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001786 break;
1787 }
1788 prev = a;
1789 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001790}
1791
1792
kezenator4f756162016-11-29 19:46:27 +10001793char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001794{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001795 const char* start = p;
1796 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001797
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001798 // Read the attributes.
1799 while( p ) {
kezenator4f756162016-11-29 19:46:27 +10001800 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001801 if ( !(*p) ) {
kezenatorec694152016-11-26 17:21:43 +10001802 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name(), _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001803 return 0;
1804 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001805
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001806 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001807 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001808 XMLAttribute* attrib = CreateAttribute();
1809 TIXMLASSERT( attrib );
kezenatorec694152016-11-26 17:21:43 +10001810 attrib->_parseLineNum = _document->_parseCurLineNum;
Lee Thomasond1983222012-02-06 08:41:24 -08001811
kezenatorec694152016-11-26 17:21:43 +10001812 int attrLineNum = attrib->_parseLineNum;
1813
kezenator4f756162016-11-29 19:46:27 +10001814 p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001815 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001816 DeleteAttribute( attrib );
kezenatorec694152016-11-26 17:21:43 +10001817 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p, attrLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001818 return 0;
1819 }
1820 // There is a minor bug here: if the attribute in the source xml
1821 // document is duplicated, it will not be detected and the
1822 // attribute will be doubly added. However, tracking the 'prevAttribute'
1823 // avoids re-scanning the attribute list. Preferring performance for
1824 // now, may reconsider in the future.
1825 if ( prevAttribute ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001826 TIXMLASSERT( prevAttribute->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001827 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001828 }
1829 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001830 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001831 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001832 }
1833 prevAttribute = attrib;
1834 }
1835 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001836 else if ( *p == '>' ) {
1837 ++p;
1838 break;
1839 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001840 // end of the tag
1841 else if ( *p == '/' && *(p+1) == '>' ) {
1842 _closingType = CLOSED;
1843 return p+2; // done; sealed element.
1844 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001845 else {
kezenatorec694152016-11-26 17:21:43 +10001846 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001847 return 0;
1848 }
1849 }
1850 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001851}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001852
Dmitry-Mee3225b12014-09-03 11:03:11 +04001853void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1854{
1855 if ( attribute == 0 ) {
1856 return;
1857 }
1858 MemPool* pool = attribute->_memPool;
1859 attribute->~XMLAttribute();
1860 pool->Free( attribute );
1861}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001862
Dmitry-Mea60caa22016-11-22 18:28:08 +03001863XMLAttribute* XMLElement::CreateAttribute()
1864{
1865 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
1866 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
Dmitry-Me7221b492017-03-03 15:45:51 +03001867 TIXMLASSERT( attrib );
Dmitry-Mea60caa22016-11-22 18:28:08 +03001868 attrib->_memPool = &_document->_attributePool;
1869 attrib->_memPool->SetTracked();
1870 return attrib;
1871}
1872
Lee Thomason67d61312012-01-24 16:01:51 -08001873//
1874// <ele></ele>
1875// <ele>foo<b>bar</b></ele>
1876//
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001877char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -08001878{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001879 // Read the element name.
kezenator4f756162016-11-29 19:46:27 +10001880 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomason67d61312012-01-24 16:01:51 -08001881
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001882 // The closing element is the </element> form. It is
1883 // parsed just like a regular element then deleted from
1884 // the DOM.
1885 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001886 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001887 ++p;
1888 }
Lee Thomason67d61312012-01-24 16:01:51 -08001889
Lee Thomason624d43f2012-10-12 10:58:48 -07001890 p = _value.ParseName( p );
1891 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001892 return 0;
1893 }
Lee Thomason67d61312012-01-24 16:01:51 -08001894
kezenator4f756162016-11-29 19:46:27 +10001895 p = ParseAttributes( p, curLineNumPtr );
Dmitry-Mee5035632017-04-05 18:02:40 +03001896 if ( !p || !*p || _closingType != OPEN ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001897 return p;
1898 }
Lee Thomason67d61312012-01-24 16:01:51 -08001899
Dmitry-Me10b8ecc2017-04-12 17:57:44 +03001900 p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001901 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001902}
1903
1904
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001905
1906XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1907{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001908 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001909 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001910 }
1911 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1912 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1913 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1914 }
1915 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001916}
1917
1918
1919bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1920{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001921 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001922 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001923 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001924
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001925 const XMLAttribute* a=FirstAttribute();
1926 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001927
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001928 while ( a && b ) {
1929 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1930 return false;
1931 }
1932 a = a->Next();
1933 b = b->Next();
1934 }
1935 if ( a || b ) {
1936 // different count
1937 return false;
1938 }
1939 return true;
1940 }
1941 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001942}
1943
1944
Lee Thomason751da522012-02-10 08:50:51 -08001945bool XMLElement::Accept( XMLVisitor* visitor ) const
1946{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001947 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001948 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001949 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1950 if ( !node->Accept( visitor ) ) {
1951 break;
1952 }
1953 }
1954 }
1955 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001956}
Lee Thomason56bdd022012-02-09 18:16:58 -08001957
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001958
Lee Thomason3f57d272012-01-11 15:30:03 -08001959// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001960
1961// Warning: List must match 'enum XMLError'
1962const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1963 "XML_SUCCESS",
1964 "XML_NO_ATTRIBUTE",
1965 "XML_WRONG_ATTRIBUTE_TYPE",
1966 "XML_ERROR_FILE_NOT_FOUND",
1967 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1968 "XML_ERROR_FILE_READ_ERROR",
1969 "XML_ERROR_ELEMENT_MISMATCH",
1970 "XML_ERROR_PARSING_ELEMENT",
1971 "XML_ERROR_PARSING_ATTRIBUTE",
1972 "XML_ERROR_IDENTIFYING_TAG",
1973 "XML_ERROR_PARSING_TEXT",
1974 "XML_ERROR_PARSING_CDATA",
1975 "XML_ERROR_PARSING_COMMENT",
1976 "XML_ERROR_PARSING_DECLARATION",
1977 "XML_ERROR_PARSING_UNKNOWN",
1978 "XML_ERROR_EMPTY_DOCUMENT",
1979 "XML_ERROR_MISMATCHED_ELEMENT",
1980 "XML_ERROR_PARSING",
1981 "XML_CAN_NOT_CONVERT_TEXT",
1982 "XML_NO_TEXT_NODE"
1983};
1984
1985
Dmitry-Meae8a82a2017-03-03 15:40:32 +03001986XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001987 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001988 _writeBOM( false ),
1989 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07001990 _errorID(XML_SUCCESS),
Dmitry-Meae8a82a2017-03-03 15:40:32 +03001991 _whitespaceMode( whitespaceMode ),
Dmitry-Mef89bd3e2017-01-18 18:33:55 +03001992 _errorLineNum( 0 ),
1993 _charBuffer( 0 ),
1994 _parseCurLineNum( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001995{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03001996 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
1997 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08001998}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001999
2000
Lee Thomason3f57d272012-01-11 15:30:03 -08002001XMLDocument::~XMLDocument()
2002{
Lee Thomasonf07b9522014-10-30 13:25:12 -07002003 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08002004}
2005
2006
Lee Thomason816d3fa2017-06-05 14:35:55 -07002007void XMLDocument::MarkInUse(XMLNode* node)
2008{
Dmitry-Mec2f677b2017-06-15 12:44:27 +03002009 TIXMLASSERT(node);
Lee Thomason816d3fa2017-06-05 14:35:55 -07002010 TIXMLASSERT(node->_parent == 0);
2011
2012 for (int i = 0; i < _unlinked.Size(); ++i) {
2013 if (node == _unlinked[i]) {
2014 _unlinked.SwapRemove(i);
2015 break;
2016 }
2017 }
2018}
2019
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002020void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08002021{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002022 DeleteChildren();
Lee Thomason816d3fa2017-06-05 14:35:55 -07002023 while( _unlinked.Size()) {
2024 DeleteNode(_unlinked[0]); // Will remove from _unlinked as part of delete.
2025 }
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002026
Dmitry-Meab37df82014-11-28 12:08:36 +03002027#ifdef DEBUG
2028 const bool hadError = Error();
2029#endif
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002030 ClearError();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002031
Lee Thomason624d43f2012-10-12 10:58:48 -07002032 delete [] _charBuffer;
2033 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07002034
2035#if 0
2036 _textPool.Trace( "text" );
2037 _elementPool.Trace( "element" );
2038 _commentPool.Trace( "comment" );
2039 _attributePool.Trace( "attribute" );
2040#endif
2041
2042#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002043 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002044 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
2045 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
2046 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
2047 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
2048 }
2049#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08002050}
2051
Lee Thomason3f57d272012-01-11 15:30:03 -08002052
Lee Thomason7085f002017-06-01 18:09:43 -07002053void XMLDocument::DeepCopy(XMLDocument* target)
2054{
2055 TIXMLASSERT(target);
Lee Thomason1346a172017-06-14 15:14:19 -07002056 if (target == this) {
2057 return; // technically success - a no-op.
2058 }
Lee Thomason7085f002017-06-01 18:09:43 -07002059
2060 target->Clear();
2061 for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {
2062 target->InsertEndChild(node->DeepClone(target));
2063 }
2064}
2065
Lee Thomason2c85a712012-01-31 08:24:24 -08002066XMLElement* XMLDocument::NewElement( const char* name )
2067{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002068 XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002069 ele->SetName( name );
2070 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08002071}
2072
2073
Lee Thomason1ff38e02012-02-14 18:18:16 -08002074XMLComment* XMLDocument::NewComment( const char* str )
2075{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002076 XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002077 comment->SetValue( str );
2078 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002079}
2080
2081
2082XMLText* XMLDocument::NewText( const char* str )
2083{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002084 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002085 text->SetValue( str );
2086 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002087}
2088
2089
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002090XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2091{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002092 XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002093 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2094 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002095}
2096
2097
2098XMLUnknown* XMLDocument::NewUnknown( const char* str )
2099{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002100 XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002101 unk->SetValue( str );
2102 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002103}
2104
Dmitry-Me01578db2014-08-19 10:18:48 +04002105static FILE* callfopen( const char* filepath, const char* mode )
2106{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002107 TIXMLASSERT( filepath );
2108 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002109#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2110 FILE* fp = 0;
2111 errno_t err = fopen_s( &fp, filepath, mode );
2112 if ( err ) {
2113 return 0;
2114 }
2115#else
2116 FILE* fp = fopen( filepath, mode );
2117#endif
2118 return fp;
2119}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08002120
2121void XMLDocument::DeleteNode( XMLNode* node ) {
2122 TIXMLASSERT( node );
2123 TIXMLASSERT(node->_document == this );
2124 if (node->_parent) {
2125 node->_parent->DeleteChild( node );
2126 }
2127 else {
2128 // Isn't in the tree.
2129 // Use the parent delete.
2130 // Also, we need to mark it tracked: we 'know'
2131 // it was never used.
2132 node->_memPool->SetTracked();
2133 // Call the static XMLNode version:
2134 XMLNode::DeleteNode(node);
2135 }
2136}
2137
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002138
Lee Thomason2fa81722012-11-09 12:37:46 -08002139XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002140{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002141 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04002142 FILE* fp = callfopen( filename, "rb" );
2143 if ( !fp ) {
kezenatorec694152016-11-26 17:21:43 +10002144 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002145 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002146 }
2147 LoadFile( fp );
2148 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002149 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002150}
2151
Dmitry-Me901fed52015-09-25 10:29:51 +03002152// This is likely overengineered template art to have a check that unsigned long value incremented
2153// by one still fits into size_t. If size_t type is larger than unsigned long type
2154// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
2155// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
2156// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
2157// types sizes relate to each other.
2158template
2159<bool = (sizeof(unsigned long) >= sizeof(size_t))>
2160struct LongFitsIntoSizeTMinusOne {
2161 static bool Fits( unsigned long value )
2162 {
2163 return value < (size_t)-1;
2164 }
2165};
2166
2167template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02002168struct LongFitsIntoSizeTMinusOne<false> {
2169 static bool Fits( unsigned long )
2170 {
2171 return true;
2172 }
2173};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002174
Lee Thomason2fa81722012-11-09 12:37:46 -08002175XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002176{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002177 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002178
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002179 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002180 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
kezenatorec694152016-11-26 17:21:43 +10002181 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002182 return _errorID;
2183 }
2184
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002185 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002186 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002187 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002188 if ( filelength == -1L ) {
kezenatorec694152016-11-26 17:21:43 +10002189 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002190 return _errorID;
2191 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002192 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002193
Dmitry-Me901fed52015-09-25 10:29:51 +03002194 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002195 // Cannot handle files which won't fit in buffer together with null terminator
kezenatorec694152016-11-26 17:21:43 +10002196 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002197 return _errorID;
2198 }
2199
Dmitry-Me72801b82015-05-07 09:41:39 +03002200 if ( filelength == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10002201 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002202 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002203 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002204
Dmitry-Me72801b82015-05-07 09:41:39 +03002205 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002206 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002207 _charBuffer = new char[size+1];
2208 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002209 if ( read != size ) {
kezenatorec694152016-11-26 17:21:43 +10002210 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002211 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002212 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002213
Lee Thomason624d43f2012-10-12 10:58:48 -07002214 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002215
Dmitry-Me97476b72015-01-01 16:15:57 +03002216 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002217 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002218}
2219
2220
Lee Thomason2fa81722012-11-09 12:37:46 -08002221XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002222{
Dmitry-Me01578db2014-08-19 10:18:48 +04002223 FILE* fp = callfopen( filename, "w" );
2224 if ( !fp ) {
kezenatorec694152016-11-26 17:21:43 +10002225 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002226 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002227 }
2228 SaveFile(fp, compact);
2229 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002230 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002231}
2232
2233
Lee Thomason2fa81722012-11-09 12:37:46 -08002234XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002235{
Ant Mitchell189198f2015-03-24 16:20:36 +00002236 // Clear any error from the last save, otherwise it will get reported
2237 // for *this* call.
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002238 ClearError();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002239 XMLPrinter stream( fp, compact );
2240 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002241 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002242}
2243
Lee Thomason1ff38e02012-02-14 18:18:16 -08002244
Lee Thomason2fa81722012-11-09 12:37:46 -08002245XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002246{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002247 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002248
Lee Thomason82d32002014-02-21 22:47:18 -08002249 if ( len == 0 || !p || !*p ) {
kezenatorec694152016-11-26 17:21:43 +10002250 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002251 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002252 }
2253 if ( len == (size_t)(-1) ) {
2254 len = strlen( p );
2255 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002256 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002257 _charBuffer = new char[ len+1 ];
2258 memcpy( _charBuffer, p, len );
2259 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002260
Dmitry-Me97476b72015-01-01 16:15:57 +03002261 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002262 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002263 // clean up now essentially dangling memory.
2264 // and the parse fail can put objects in the
2265 // pools that are dead and inaccessible.
2266 DeleteChildren();
2267 _elementPool.Clear();
2268 _attributePool.Clear();
2269 _textPool.Clear();
2270 _commentPool.Clear();
2271 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002272 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002273}
2274
2275
PKEuS1c5f99e2013-07-06 11:28:39 +02002276void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002277{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002278 if ( streamer ) {
2279 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002280 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002281 else {
2282 XMLPrinter stdoutStreamer( stdout );
2283 Accept( &stdoutStreamer );
2284 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002285}
2286
2287
kezenatorec694152016-11-26 17:21:43 +10002288void XMLDocument::SetError( XMLError error, const char* str1, const char* str2, int lineNum )
Lee Thomason67d61312012-01-24 16:01:51 -08002289{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002290 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002291 _errorID = error;
Lee Thomason584af572016-09-05 14:14:16 -07002292
2293 _errorStr1.Reset();
2294 _errorStr2.Reset();
kezenatorec694152016-11-26 17:21:43 +10002295 _errorLineNum = lineNum;
Lee Thomason584af572016-09-05 14:14:16 -07002296
2297 if (str1)
2298 _errorStr1.SetStr(str1);
2299 if (str2)
2300 _errorStr2.SetStr(str2);
Lee Thomason67d61312012-01-24 16:01:51 -08002301}
2302
Lee Thomasone90e9012016-12-24 07:34:39 -08002303/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
Lee Thomason331596e2014-09-11 14:56:43 -07002304{
kezenator5a700712016-11-26 13:54:42 +10002305 TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2306 const char* errorName = _errorNames[errorID];
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002307 TIXMLASSERT( errorName && errorName[0] );
2308 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002309}
Lee Thomason5cae8972012-01-24 18:03:07 -08002310
kezenator5a700712016-11-26 13:54:42 +10002311const char* XMLDocument::ErrorName() const
2312{
Lee Thomasone90e9012016-12-24 07:34:39 -08002313 return ErrorIDToName(_errorID);
kezenator5a700712016-11-26 13:54:42 +10002314}
2315
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002316void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002317{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002318 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002319 static const int LEN = 20;
2320 char buf1[LEN] = { 0 };
2321 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002322
Lee Thomason584af572016-09-05 14:14:16 -07002323 if ( !_errorStr1.Empty() ) {
2324 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002325 }
Lee Thomason584af572016-09-05 14:14:16 -07002326 if ( !_errorStr2.Empty() ) {
2327 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002328 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002329
Dmitry-Me2ad43202015-04-16 12:18:58 +03002330 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2331 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2332 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
kezenatorec694152016-11-26 17:21:43 +10002333 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s line=%d\n",
2334 static_cast<int>( _errorID ), ErrorName(), buf1, buf2, _errorLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002335 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002336}
2337
Dmitry-Me97476b72015-01-01 16:15:57 +03002338void XMLDocument::Parse()
2339{
2340 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2341 TIXMLASSERT( _charBuffer );
kezenatorec694152016-11-26 17:21:43 +10002342 _parseCurLineNum = 1;
2343 _parseLineNum = 1;
Lee Thomason3cebdc42015-01-05 17:16:28 -08002344 char* p = _charBuffer;
kezenator4f756162016-11-29 19:46:27 +10002345 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mee28be752015-01-09 14:59:30 +03002346 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002347 if ( !*p ) {
kezenatorec694152016-11-26 17:21:43 +10002348 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002349 return;
2350 }
kezenator4f756162016-11-29 19:46:27 +10002351 ParseDeep(p, 0, &_parseCurLineNum );
Dmitry-Me97476b72015-01-01 16:15:57 +03002352}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002353
PKEuS1bfb9542013-08-04 13:51:17 +02002354XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002355 _elementJustOpened( false ),
2356 _firstElement( true ),
2357 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002358 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002359 _textDepth( -1 ),
2360 _processEntities( true ),
2361 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002362{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002363 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002364 _entityFlag[i] = false;
2365 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002366 }
2367 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002368 const char entityValue = entities[i].value;
Dmitry-Mec5f1e7c2016-10-14 10:33:02 +03002369 TIXMLASSERT( ((unsigned char)entityValue) < ENTITY_RANGE );
Dmitry-Me8b67d742014-12-22 11:35:12 +03002370 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002371 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002372 _restrictedEntityFlag[(unsigned char)'&'] = true;
2373 _restrictedEntityFlag[(unsigned char)'<'] = true;
2374 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002375 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002376}
2377
2378
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002379void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002380{
2381 va_list va;
2382 va_start( va, format );
2383
Lee Thomason624d43f2012-10-12 10:58:48 -07002384 if ( _fp ) {
2385 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002386 }
2387 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002388 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002389 // Close out and re-start the va-args
2390 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002391 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002392 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002393 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002394 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002395 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002396 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002397 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002398}
2399
2400
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002401void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002402{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002403 for( int i=0; i<depth; ++i ) {
2404 Print( " " );
2405 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002406}
2407
2408
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002409void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002410{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002411 // Look for runs of bytes between entities to print.
2412 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002413
Lee Thomason624d43f2012-10-12 10:58:48 -07002414 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002415 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002416 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002417 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002418 // Remember, char is sometimes signed. (How many times has that bitten me?)
2419 if ( *q > 0 && *q < ENTITY_RANGE ) {
2420 // Check for entities. If one is found, flush
2421 // the stream up until the entity, write the
2422 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002423 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002424 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002425 const size_t delta = q - p;
2426 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002427 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002428 Print( "%.*s", toPrint, p );
2429 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002430 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002431 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002432 for( int i=0; i<NUM_ENTITIES; ++i ) {
2433 if ( entities[i].value == *q ) {
2434 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002435 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002436 break;
2437 }
2438 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002439 if ( !entityPatternPrinted ) {
2440 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2441 TIXMLASSERT( false );
2442 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002443 ++p;
2444 }
2445 }
2446 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002447 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002448 }
2449 }
2450 // Flush the remaining string. This will be the entire
2451 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002452 TIXMLASSERT( p <= q );
2453 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002454 Print( "%s", p );
2455 }
Lee Thomason857b8682012-01-25 17:50:25 -08002456}
2457
U-Stream\Leeae25a442012-02-17 17:48:16 -08002458
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002459void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002460{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002461 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002462 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 -07002463 Print( "%s", bom );
2464 }
2465 if ( writeDec ) {
2466 PushDeclaration( "xml version=\"1.0\"" );
2467 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002468}
2469
2470
Uli Kusterer593a33d2014-02-01 12:48:51 +01002471void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002472{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002473 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002474 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002475
Uli Kusterer593a33d2014-02-01 12:48:51 +01002476 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002477 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002478 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002479 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002480 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002481 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002482
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002483 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002484 _elementJustOpened = true;
2485 _firstElement = false;
2486 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002487}
2488
2489
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002490void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002491{
Lee Thomason624d43f2012-10-12 10:58:48 -07002492 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002493 Print( " %s=\"", name );
2494 PrintString( value, false );
2495 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002496}
2497
2498
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002499void XMLPrinter::PushAttribute( const char* name, int v )
2500{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002501 char buf[BUF_SIZE];
2502 XMLUtil::ToStr( v, buf, BUF_SIZE );
2503 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002504}
2505
2506
2507void XMLPrinter::PushAttribute( const char* name, unsigned v )
2508{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002509 char buf[BUF_SIZE];
2510 XMLUtil::ToStr( v, buf, BUF_SIZE );
2511 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002512}
2513
2514
Lee Thomason51c12712016-06-04 20:18:49 -07002515void XMLPrinter::PushAttribute(const char* name, int64_t v)
2516{
2517 char buf[BUF_SIZE];
2518 XMLUtil::ToStr(v, buf, BUF_SIZE);
2519 PushAttribute(name, buf);
2520}
2521
2522
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002523void XMLPrinter::PushAttribute( const char* name, bool v )
2524{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002525 char buf[BUF_SIZE];
2526 XMLUtil::ToStr( v, buf, BUF_SIZE );
2527 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002528}
2529
2530
2531void XMLPrinter::PushAttribute( const char* name, double v )
2532{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002533 char buf[BUF_SIZE];
2534 XMLUtil::ToStr( v, buf, BUF_SIZE );
2535 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002536}
2537
2538
Uli Kustererca412e82014-02-01 13:35:05 +01002539void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002540{
Lee Thomason624d43f2012-10-12 10:58:48 -07002541 --_depth;
2542 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002543
Lee Thomason624d43f2012-10-12 10:58:48 -07002544 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002545 Print( "/>" );
2546 }
2547 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002548 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002549 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002550 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002551 }
2552 Print( "</%s>", name );
2553 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002554
Lee Thomason624d43f2012-10-12 10:58:48 -07002555 if ( _textDepth == _depth ) {
2556 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002557 }
Uli Kustererca412e82014-02-01 13:35:05 +01002558 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002559 Print( "\n" );
2560 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002561 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002562}
2563
2564
Dmitry-Mea092bc12014-12-23 17:57:05 +03002565void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002566{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002567 if ( !_elementJustOpened ) {
2568 return;
2569 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002570 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002571 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002572}
2573
2574
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002575void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002576{
Lee Thomason624d43f2012-10-12 10:58:48 -07002577 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002578
Dmitry-Mea092bc12014-12-23 17:57:05 +03002579 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002580 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002581 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002582 }
2583 else {
2584 PrintString( text, true );
2585 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002586}
2587
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002588void XMLPrinter::PushText( int64_t value )
2589{
2590 char buf[BUF_SIZE];
2591 XMLUtil::ToStr( value, buf, BUF_SIZE );
2592 PushText( buf, false );
2593}
2594
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002595void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002596{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002597 char buf[BUF_SIZE];
2598 XMLUtil::ToStr( value, buf, BUF_SIZE );
2599 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002600}
2601
2602
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002603void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002604{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002605 char buf[BUF_SIZE];
2606 XMLUtil::ToStr( value, buf, BUF_SIZE );
2607 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002608}
2609
2610
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002611void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002612{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002613 char buf[BUF_SIZE];
2614 XMLUtil::ToStr( value, buf, BUF_SIZE );
2615 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002616}
2617
2618
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002619void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002620{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002621 char buf[BUF_SIZE];
2622 XMLUtil::ToStr( value, buf, BUF_SIZE );
2623 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002624}
2625
2626
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002627void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002628{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002629 char buf[BUF_SIZE];
2630 XMLUtil::ToStr( value, buf, BUF_SIZE );
2631 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002632}
2633
Lee Thomason5cae8972012-01-24 18:03:07 -08002634
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002635void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002636{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002637 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002638 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002639 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002640 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002641 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002642 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002643 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002644}
Lee Thomason751da522012-02-10 08:50:51 -08002645
2646
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002647void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002648{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002649 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002650 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002651 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002652 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002653 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002654 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002655 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002656}
2657
2658
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002659void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002660{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002661 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002662 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002663 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002664 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002665 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002666 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002667 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002668}
2669
2670
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002671bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002672{
Lee Thomason624d43f2012-10-12 10:58:48 -07002673 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002674 if ( doc.HasBOM() ) {
2675 PushHeader( true, false );
2676 }
2677 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002678}
2679
2680
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002681bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002682{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002683 const XMLElement* parentElem = 0;
2684 if ( element.Parent() ) {
2685 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002686 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002687 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002688 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002689 while ( attribute ) {
2690 PushAttribute( attribute->Name(), attribute->Value() );
2691 attribute = attribute->Next();
2692 }
2693 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002694}
2695
2696
Uli Kustererca412e82014-02-01 13:35:05 +01002697bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002698{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002699 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002700 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002701}
2702
2703
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002704bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002705{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002706 PushText( text.Value(), text.CData() );
2707 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002708}
2709
2710
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002711bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002712{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002713 PushComment( comment.Value() );
2714 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002715}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002716
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002717bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002718{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002719 PushDeclaration( declaration.Value() );
2720 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002721}
2722
2723
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002724bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002725{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002726 PushUnknown( unknown.Value() );
2727 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002728}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002729
Lee Thomason685b8952012-11-12 13:00:06 -08002730} // namespace tinyxml2
2731