blob: 819382b7222a5b786c194f834d8b769464a0679d [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 Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800371const char* XMLUtil::ReadBOM( const char* p, bool* bom )
372{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300373 TIXMLASSERT( p );
374 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700375 *bom = false;
376 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
377 // Check for BOM:
378 if ( *(pu+0) == TIXML_UTF_LEAD_0
379 && *(pu+1) == TIXML_UTF_LEAD_1
380 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
381 *bom = true;
382 p += 3;
383 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300384 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700385 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800386}
387
388
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800389void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
390{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700391 const unsigned long BYTE_MASK = 0xBF;
392 const unsigned long BYTE_MARK = 0x80;
393 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800394
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700395 if (input < 0x80) {
396 *length = 1;
397 }
398 else if ( input < 0x800 ) {
399 *length = 2;
400 }
401 else if ( input < 0x10000 ) {
402 *length = 3;
403 }
404 else if ( input < 0x200000 ) {
405 *length = 4;
406 }
407 else {
Dmitry-Me2f465c42015-03-16 11:08:23 +0300408 *length = 0; // This code won't convert this correctly anyway.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700409 return;
410 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800411
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700412 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800413
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700414 // Scary scary fall throughs.
415 switch (*length) {
416 case 4:
417 --output;
418 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
419 input >>= 6;
420 case 3:
421 --output;
422 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
423 input >>= 6;
424 case 2:
425 --output;
426 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
427 input >>= 6;
428 case 1:
429 --output;
430 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100431 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300432 default:
433 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700434 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800435}
436
437
438const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
439{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700440 // Presume an entity, and pull it out.
441 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800442
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700443 if ( *(p+1) == '#' && *(p+2) ) {
444 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300445 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700446 ptrdiff_t delta = 0;
447 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800448 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800449
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700450 if ( *(p+2) == 'x' ) {
451 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300452 const char* q = p+3;
453 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700454 return 0;
455 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800456
Lee Thomason7e67bc82015-01-12 14:05:12 -0800457 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800458
Dmitry-Me9f56e122015-01-12 10:07:54 +0300459 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700460 return 0;
461 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800462 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800463
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700464 delta = q-p;
465 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800466
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700467 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700468 unsigned int digit = 0;
469
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700470 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300471 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700472 }
473 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300474 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700475 }
476 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300477 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700478 }
479 else {
480 return 0;
481 }
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100482 TIXMLASSERT( digit < 16 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300483 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
484 const unsigned int digitScaled = mult * digit;
485 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
486 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300487 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700488 mult *= 16;
489 --q;
490 }
491 }
492 else {
493 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300494 const char* q = p+2;
495 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700496 return 0;
497 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800498
Lee Thomason7e67bc82015-01-12 14:05:12 -0800499 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800500
Dmitry-Me9f56e122015-01-12 10:07:54 +0300501 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700502 return 0;
503 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800504 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800505
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700506 delta = q-p;
507 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800508
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700509 while ( *q != '#' ) {
510 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300511 const unsigned int digit = *q - '0';
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100512 TIXMLASSERT( digit < 10 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300513 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
514 const unsigned int digitScaled = mult * digit;
515 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
516 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700517 }
518 else {
519 return 0;
520 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300521 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700522 mult *= 10;
523 --q;
524 }
525 }
526 // convert the UCS to UTF-8
527 ConvertUTF32ToUTF8( ucs, value, length );
528 return p + delta + 1;
529 }
530 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800531}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800532
533
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700534void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700535{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700536 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700537}
538
539
540void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
541{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700542 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700543}
544
545
546void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
547{
Doruk Turakde45d042016-08-28 20:47:08 +0200548 TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? "true" : "false" );
Lee Thomason21be8822012-07-15 17:27:22 -0700549}
550
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800551/*
552 ToStr() of a number is a very tricky topic.
553 https://github.com/leethomason/tinyxml2/issues/106
554*/
Lee Thomason21be8822012-07-15 17:27:22 -0700555void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
556{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800557 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700558}
559
560
561void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
562{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800563 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700564}
565
566
Lee Thomason51c12712016-06-04 20:18:49 -0700567void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize)
568{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700569 // horrible syntax trick to make the compiler happy about %lld
570 TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v);
Lee Thomason51c12712016-06-04 20:18:49 -0700571}
572
573
Lee Thomason21be8822012-07-15 17:27:22 -0700574bool XMLUtil::ToInt( const char* str, int* value )
575{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700576 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
577 return true;
578 }
579 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700580}
581
582bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
583{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700584 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
585 return true;
586 }
587 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700588}
589
590bool XMLUtil::ToBool( const char* str, bool* value )
591{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700592 int ival = 0;
593 if ( ToInt( str, &ival )) {
594 *value = (ival==0) ? false : true;
595 return true;
596 }
597 if ( StringEqual( str, "true" ) ) {
598 *value = true;
599 return true;
600 }
601 else if ( StringEqual( str, "false" ) ) {
602 *value = false;
603 return true;
604 }
605 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700606}
607
608
609bool XMLUtil::ToFloat( const char* str, float* value )
610{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700611 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
612 return true;
613 }
614 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700615}
616
Lee Thomason51c12712016-06-04 20:18:49 -0700617
Lee Thomason21be8822012-07-15 17:27:22 -0700618bool XMLUtil::ToDouble( const char* str, double* value )
619{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700620 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
621 return true;
622 }
623 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700624}
625
626
Lee Thomason51c12712016-06-04 20:18:49 -0700627bool XMLUtil::ToInt64(const char* str, int64_t* value)
628{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700629 long long v = 0; // horrible syntax trick to make the compiler happy about %lld
630 if (TIXML_SSCANF(str, "%lld", &v) == 1) {
631 *value = (int64_t)v;
Lee Thomason51c12712016-06-04 20:18:49 -0700632 return true;
633 }
634 return false;
635}
636
637
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700638char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800639{
Dmitry-Me02384662015-03-03 16:02:13 +0300640 TIXMLASSERT( node );
641 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400642 char* const start = p;
kezenatorec694152016-11-26 17:21:43 +1000643 int const startLine = _parseCurLineNum;
kezenator4f756162016-11-29 19:46:27 +1000644 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300645 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300646 *node = 0;
647 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700648 return p;
649 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800650
Dmitry-Me962083b2015-05-26 11:38:30 +0300651 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700652 static const char* xmlHeader = { "<?" };
653 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700654 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300655 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700656 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800657
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700658 static const int xmlHeaderLen = 2;
659 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700660 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300661 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700662 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800663
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700664 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
665 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400666 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700667 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300668 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700669 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
kezenatorec694152016-11-26 17:21:43 +1000670 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomason624d43f2012-10-12 10:58:48 -0700671 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700672 p += xmlHeaderLen;
673 }
674 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300675 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700676 returnNode = new (_commentPool.Alloc()) XMLComment( this );
kezenatorec694152016-11-26 17:21:43 +1000677 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomason624d43f2012-10-12 10:58:48 -0700678 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700679 p += commentHeaderLen;
680 }
681 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300682 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700683 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700684 returnNode = text;
kezenatorec694152016-11-26 17:21:43 +1000685 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomason624d43f2012-10-12 10:58:48 -0700686 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700687 p += cdataHeaderLen;
688 text->SetCData( true );
689 }
690 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300691 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700692 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
kezenatorec694152016-11-26 17:21:43 +1000693 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomason624d43f2012-10-12 10:58:48 -0700694 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700695 p += dtdHeaderLen;
696 }
697 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300698 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700699 returnNode = new (_elementPool.Alloc()) XMLElement( this );
kezenatorec694152016-11-26 17:21:43 +1000700 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomason624d43f2012-10-12 10:58:48 -0700701 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700702 p += elementHeaderLen;
703 }
704 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300705 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700706 returnNode = new (_textPool.Alloc()) XMLText( this );
707 returnNode->_memPool = &_textPool;
kezenatorec694152016-11-26 17:21:43 +1000708 returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700709 p = start; // Back it up, all the text counts.
kezenatorec694152016-11-26 17:21:43 +1000710 _parseCurLineNum = startLine;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700711 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800712
Dmitry-Me02384662015-03-03 16:02:13 +0300713 TIXMLASSERT( returnNode );
714 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700715 *node = returnNode;
716 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800717}
718
719
Lee Thomason751da522012-02-10 08:50:51 -0800720bool XMLDocument::Accept( XMLVisitor* visitor ) const
721{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300722 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700723 if ( visitor->VisitEnter( *this ) ) {
724 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
725 if ( !node->Accept( visitor ) ) {
726 break;
727 }
728 }
729 }
730 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800731}
Lee Thomason56bdd022012-02-09 18:16:58 -0800732
733
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800734// --------- XMLNode ----------- //
735
736XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700737 _document( doc ),
738 _parent( 0 ),
kezenatorec694152016-11-26 17:21:43 +1000739 _parseLineNum( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -0700740 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200741 _prev( 0 ), _next( 0 ),
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700742 _userData( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200743 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800744{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800745}
746
747
748XMLNode::~XMLNode()
749{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700750 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700751 if ( _parent ) {
752 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700753 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800754}
755
Michael Daumling21626882013-10-22 17:03:37 +0200756const char* XMLNode::Value() const
757{
Dmitry-Mecaa72a62016-08-10 17:34:34 +0300758 // Edge case: XMLDocuments don't have a Value. Return null.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530759 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530760 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200761 return _value.GetStr();
762}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800763
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800764void XMLNode::SetValue( const char* str, bool staticMem )
765{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700766 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700767 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700768 }
769 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700770 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700771 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800772}
773
Lee Thomason7085f002017-06-01 18:09:43 -0700774XMLNode* XMLNode::DeepClone(XMLDocument* document) const
775{
776 XMLNode* clone = this->ShallowClone(document);
777 if (!clone) return 0;
778
779 for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) {
780 XMLNode* childClone = child->DeepClone(document);
781 TIXMLASSERT(childClone);
782 clone->InsertEndChild(childClone);
783 }
784 return clone;
785}
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800786
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800787void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800788{
Lee Thomason624d43f2012-10-12 10:58:48 -0700789 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300790 TIXMLASSERT( _lastChild );
Dmitry-Me9cb4eca2016-08-18 18:10:59 +0300791 DeleteChild( _firstChild );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700792 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700793 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800794}
795
796
797void XMLNode::Unlink( XMLNode* child )
798{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300799 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300800 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300801 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700802 if ( child == _firstChild ) {
803 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700804 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700805 if ( child == _lastChild ) {
806 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700807 }
Lee Thomasond923c672012-01-23 08:44:25 -0800808
Lee Thomason624d43f2012-10-12 10:58:48 -0700809 if ( child->_prev ) {
810 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700811 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700812 if ( child->_next ) {
813 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700814 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700815 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800816}
817
818
U-Stream\Leeae25a442012-02-17 17:48:16 -0800819void XMLNode::DeleteChild( XMLNode* node )
820{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300821 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300822 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700823 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100824 Unlink( node );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400825 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800826}
827
828
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800829XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
830{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300831 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300832 if ( addThis->_document != _document ) {
833 TIXMLASSERT( false );
834 return 0;
835 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800836 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700837
Lee Thomason624d43f2012-10-12 10:58:48 -0700838 if ( _lastChild ) {
839 TIXMLASSERT( _firstChild );
840 TIXMLASSERT( _lastChild->_next == 0 );
841 _lastChild->_next = addThis;
842 addThis->_prev = _lastChild;
843 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800844
Lee Thomason624d43f2012-10-12 10:58:48 -0700845 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700846 }
847 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700848 TIXMLASSERT( _firstChild == 0 );
849 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800850
Lee Thomason624d43f2012-10-12 10:58:48 -0700851 addThis->_prev = 0;
852 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700853 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700854 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700855 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800856}
857
858
Lee Thomason1ff38e02012-02-14 18:18:16 -0800859XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
860{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300861 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300862 if ( addThis->_document != _document ) {
863 TIXMLASSERT( false );
864 return 0;
865 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800866 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700867
Lee Thomason624d43f2012-10-12 10:58:48 -0700868 if ( _firstChild ) {
869 TIXMLASSERT( _lastChild );
870 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800871
Lee Thomason624d43f2012-10-12 10:58:48 -0700872 _firstChild->_prev = addThis;
873 addThis->_next = _firstChild;
874 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800875
Lee Thomason624d43f2012-10-12 10:58:48 -0700876 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700877 }
878 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700879 TIXMLASSERT( _lastChild == 0 );
880 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800881
Lee Thomason624d43f2012-10-12 10:58:48 -0700882 addThis->_prev = 0;
883 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700884 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700885 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400886 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800887}
888
889
890XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
891{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300892 TIXMLASSERT( addThis );
893 if ( addThis->_document != _document ) {
894 TIXMLASSERT( false );
895 return 0;
896 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700897
Dmitry-Meabb2d042014-12-09 12:59:31 +0300898 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700899
Lee Thomason624d43f2012-10-12 10:58:48 -0700900 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300901 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700902 return 0;
903 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800904
Lee Thomason624d43f2012-10-12 10:58:48 -0700905 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700906 // The last node or the only node.
907 return InsertEndChild( addThis );
908 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800909 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700910 addThis->_prev = afterThis;
911 addThis->_next = afterThis->_next;
912 afterThis->_next->_prev = addThis;
913 afterThis->_next = addThis;
914 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700915 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800916}
917
918
919
920
Dmitry-Me886ad972015-07-22 11:00:51 +0300921const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800922{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300923 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300924 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700925 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300926 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700927 }
928 }
929 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800930}
931
932
Dmitry-Me886ad972015-07-22 11:00:51 +0300933const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800934{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300935 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300936 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700937 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300938 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700939 }
940 }
941 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800942}
943
944
Dmitry-Me886ad972015-07-22 11:00:51 +0300945const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800946{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300947 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300948 const XMLElement* element = node->ToElementWithName( name );
949 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400950 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700951 }
952 }
953 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800954}
955
956
Dmitry-Me886ad972015-07-22 11:00:51 +0300957const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800958{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300959 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300960 const XMLElement* element = node->ToElementWithName( name );
961 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400962 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700963 }
964 }
965 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800966}
967
968
kezenator4f756162016-11-29 19:46:27 +1000969char* XMLNode::ParseDeep( char* p, StrPair* parentEnd, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -0800970{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700971 // This is a recursive method, but thinking about it "at the current level"
972 // it is a pretty simple flat list:
973 // <foo/>
974 // <!-- comment -->
975 //
976 // With a special case:
977 // <foo>
978 // </foo>
979 // <!-- comment -->
980 //
981 // Where the closing element (/foo) *must* be the next thing after the opening
982 // element, and the names must match. BUT the tricky bit is that the closing
983 // element will be read by the child.
984 //
985 // 'endTag' is the end tag for this node, it is returned by a call to a child.
986 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800987
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700988 while( p && *p ) {
989 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800990
Lee Thomason624d43f2012-10-12 10:58:48 -0700991 p = _document->Identify( p, &node );
Dmitry-Me43364312016-11-07 18:48:50 +0300992 TIXMLASSERT( p );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300993 if ( node == 0 ) {
994 break;
995 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800996
kezenatore3531812016-11-29 19:49:07 +1000997 int initialLineNum = node->_parseLineNum;
kezenatorec694152016-11-26 17:21:43 +1000998
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700999 StrPair endTag;
kezenator4f756162016-11-29 19:46:27 +10001000 p = node->ParseDeep( p, &endTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001001 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001002 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -07001003 if ( !_document->Error() ) {
kezenatore3531812016-11-29 19:49:07 +10001004 _document->SetError( XML_ERROR_PARSING, 0, 0, initialLineNum);
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001005 }
1006 break;
1007 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001008
Sarat Addepalli3df007e2015-05-20 10:43:51 +05301009 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301010 if ( decl ) {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001011 // Declarations are only allowed at document level
1012 bool wellLocated = ( ToDocument() != 0 );
1013 if ( wellLocated ) {
1014 // Multiple declarations are allowed but all declarations
1015 // must occur before anything else
1016 for ( const XMLNode* existingNode = _document->FirstChild(); existingNode; existingNode = existingNode->NextSibling() ) {
1017 if ( !existingNode->ToDeclaration() ) {
1018 wellLocated = false;
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301019 break;
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001020 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301021 }
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001022 }
1023 if ( !wellLocated ) {
kezenatore3531812016-11-29 19:49:07 +10001024 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0, initialLineNum);
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001025 DeleteNode( node );
1026 break;
1027 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301028 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301029
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001030 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001031 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -05001032 // We read the end tag. Return it to the parent.
1033 if ( ele->ClosingType() == XMLElement::CLOSING ) {
1034 if ( parentEnd ) {
1035 ele->_value.TransferTo( parentEnd );
1036 }
1037 node->_memPool->SetTracked(); // created and then immediately deleted.
1038 DeleteNode( node );
1039 return p;
1040 }
1041
1042 // Handle an end tag returned to this level.
1043 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001044 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001045 if ( endTag.Empty() ) {
1046 if ( ele->ClosingType() == XMLElement::OPEN ) {
1047 mismatch = true;
1048 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001049 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001050 else {
1051 if ( ele->ClosingType() != XMLElement::OPEN ) {
1052 mismatch = true;
1053 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001054 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001055 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001056 }
1057 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001058 if ( mismatch ) {
kezenatore3531812016-11-29 19:49:07 +10001059 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0, initialLineNum);
JayXondbfdd8f2014-12-12 20:07:14 -05001060 DeleteNode( node );
1061 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001062 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001063 }
JayXondbfdd8f2014-12-12 20:07:14 -05001064 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001065 }
1066 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001067}
1068
Dmitry-Mee3225b12014-09-03 11:03:11 +04001069void XMLNode::DeleteNode( XMLNode* node )
1070{
1071 if ( node == 0 ) {
1072 return;
1073 }
1074 MemPool* pool = node->_memPool;
1075 node->~XMLNode();
1076 pool->Free( node );
1077}
1078
Lee Thomason3cebdc42015-01-05 17:16:28 -08001079void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001080{
1081 TIXMLASSERT( insertThis );
1082 TIXMLASSERT( insertThis->_document == _document );
1083
1084 if ( insertThis->_parent )
1085 insertThis->_parent->Unlink( insertThis );
1086 else
1087 insertThis->_memPool->SetTracked();
1088}
1089
Dmitry-Meecb9b072016-10-12 16:44:59 +03001090const XMLElement* XMLNode::ToElementWithName( const char* name ) const
1091{
1092 const XMLElement* element = this->ToElement();
1093 if ( element == 0 ) {
1094 return 0;
1095 }
1096 if ( name == 0 ) {
1097 return element;
1098 }
1099 if ( XMLUtil::StringEqual( element->Name(), name ) ) {
1100 return element;
1101 }
1102 return 0;
1103}
1104
Lee Thomason5492a1c2012-01-23 15:32:10 -08001105// --------- XMLText ---------- //
kezenator4f756162016-11-29 19:46:27 +10001106char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001107{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001108 const char* start = p;
1109 if ( this->CData() ) {
kezenator4f756162016-11-29 19:46:27 +10001110 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001111 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001112 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001113 }
1114 return p;
1115 }
1116 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001117 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1118 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001119 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001120 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001121
kezenator4f756162016-11-29 19:46:27 +10001122 p = _value.ParseText( p, "<", flags, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001123 if ( p && *p ) {
1124 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001125 }
1126 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001127 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001128 }
1129 }
1130 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001131}
1132
1133
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001134XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1135{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001136 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001137 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001138 }
1139 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1140 text->SetCData( this->CData() );
1141 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001142}
1143
1144
1145bool XMLText::ShallowEqual( const XMLNode* compare ) const
1146{
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001147 const XMLText* text = compare->ToText();
1148 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001149}
1150
1151
Lee Thomason56bdd022012-02-09 18:16:58 -08001152bool XMLText::Accept( XMLVisitor* visitor ) const
1153{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001154 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001155 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001156}
1157
1158
Lee Thomason3f57d272012-01-11 15:30:03 -08001159// --------- XMLComment ---------- //
1160
Lee Thomasone4422302012-01-20 17:59:50 -08001161XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001162{
1163}
1164
1165
Lee Thomasonce0763e2012-01-11 15:43:54 -08001166XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001167{
Lee Thomason3f57d272012-01-11 15:30:03 -08001168}
1169
1170
kezenator4f756162016-11-29 19:46:27 +10001171char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason3f57d272012-01-11 15:30:03 -08001172{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001173 // Comment parses as text.
1174 const char* start = p;
kezenator4f756162016-11-29 19:46:27 +10001175 p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001176 if ( p == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10001177 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001178 }
1179 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001180}
1181
1182
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001183XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1184{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001185 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001186 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001187 }
1188 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1189 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001190}
1191
1192
1193bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1194{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001195 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001196 const XMLComment* comment = compare->ToComment();
1197 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001198}
1199
1200
Lee Thomason751da522012-02-10 08:50:51 -08001201bool XMLComment::Accept( XMLVisitor* visitor ) const
1202{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001203 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001204 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001205}
Lee Thomason56bdd022012-02-09 18:16:58 -08001206
1207
Lee Thomason50f97b22012-02-11 16:33:40 -08001208// --------- XMLDeclaration ---------- //
1209
1210XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1211{
1212}
1213
1214
1215XMLDeclaration::~XMLDeclaration()
1216{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001217 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001218}
1219
1220
kezenator4f756162016-11-29 19:46:27 +10001221char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001222{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001223 // Declaration parses as text.
1224 const char* start = p;
kezenator4f756162016-11-29 19:46:27 +10001225 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001226 if ( p == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10001227 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001228 }
1229 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001230}
1231
1232
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001233XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1234{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001235 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001236 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001237 }
1238 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1239 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001240}
1241
1242
1243bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1244{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001245 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001246 const XMLDeclaration* declaration = compare->ToDeclaration();
1247 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001248}
1249
1250
1251
Lee Thomason50f97b22012-02-11 16:33:40 -08001252bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1253{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001254 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001255 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001256}
1257
1258// --------- XMLUnknown ---------- //
1259
1260XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1261{
1262}
1263
1264
1265XMLUnknown::~XMLUnknown()
1266{
1267}
1268
1269
kezenator4f756162016-11-29 19:46:27 +10001270char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001271{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001272 // Unknown parses as text.
1273 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001274
kezenator4f756162016-11-29 19:46:27 +10001275 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001276 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001277 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001278 }
1279 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001280}
1281
1282
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001283XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1284{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001285 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001286 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001287 }
1288 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1289 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001290}
1291
1292
1293bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1294{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001295 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001296 const XMLUnknown* unknown = compare->ToUnknown();
1297 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001298}
1299
1300
Lee Thomason50f97b22012-02-11 16:33:40 -08001301bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1302{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001303 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001304 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001305}
1306
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001307// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001308
1309const char* XMLAttribute::Name() const
1310{
1311 return _name.GetStr();
1312}
1313
1314const char* XMLAttribute::Value() const
1315{
1316 return _value.GetStr();
1317}
1318
kezenator4f756162016-11-29 19:46:27 +10001319char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001320{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001321 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001322 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001323 if ( !p || !*p ) {
1324 return 0;
1325 }
Lee Thomason22aead12012-01-23 13:29:35 -08001326
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001327 // Skip white space before =
kezenator4f756162016-11-29 19:46:27 +10001328 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001329 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001330 return 0;
1331 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001332
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001333 ++p; // move up to opening quote
kezenator4f756162016-11-29 19:46:27 +10001334 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001335 if ( *p != '\"' && *p != '\'' ) {
1336 return 0;
1337 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001338
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001339 char endTag[2] = { *p, 0 };
1340 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001341
kezenator4f756162016-11-29 19:46:27 +10001342 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001343 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001344}
1345
1346
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001347void XMLAttribute::SetName( const char* n )
1348{
Lee Thomason624d43f2012-10-12 10:58:48 -07001349 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001350}
1351
1352
Lee Thomason2fa81722012-11-09 12:37:46 -08001353XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001354{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001355 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001356 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001357 }
1358 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001359}
1360
1361
Lee Thomason2fa81722012-11-09 12:37:46 -08001362XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001363{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001364 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001365 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001366 }
1367 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001368}
1369
1370
Lee Thomason51c12712016-06-04 20:18:49 -07001371XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1372{
1373 if (XMLUtil::ToInt64(Value(), value)) {
1374 return XML_SUCCESS;
1375 }
1376 return XML_WRONG_ATTRIBUTE_TYPE;
1377}
1378
1379
Lee Thomason2fa81722012-11-09 12:37:46 -08001380XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001381{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001382 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001383 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001384 }
1385 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001386}
1387
1388
Lee Thomason2fa81722012-11-09 12:37:46 -08001389XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001390{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001391 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001392 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001393 }
1394 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001395}
1396
1397
Lee Thomason2fa81722012-11-09 12:37:46 -08001398XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001399{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001400 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001401 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001402 }
1403 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001404}
1405
1406
1407void XMLAttribute::SetAttribute( const char* v )
1408{
Lee Thomason624d43f2012-10-12 10:58:48 -07001409 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001410}
1411
1412
Lee Thomason1ff38e02012-02-14 18:18:16 -08001413void XMLAttribute::SetAttribute( int v )
1414{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001415 char buf[BUF_SIZE];
1416 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001417 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001418}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001419
1420
1421void XMLAttribute::SetAttribute( unsigned v )
1422{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001423 char buf[BUF_SIZE];
1424 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001425 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001426}
1427
1428
Lee Thomason51c12712016-06-04 20:18:49 -07001429void XMLAttribute::SetAttribute(int64_t v)
1430{
1431 char buf[BUF_SIZE];
1432 XMLUtil::ToStr(v, buf, BUF_SIZE);
1433 _value.SetStr(buf);
1434}
1435
1436
1437
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001438void XMLAttribute::SetAttribute( bool v )
1439{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001440 char buf[BUF_SIZE];
1441 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001442 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001443}
1444
1445void XMLAttribute::SetAttribute( double v )
1446{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001447 char buf[BUF_SIZE];
1448 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001449 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001450}
1451
1452void XMLAttribute::SetAttribute( float v )
1453{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001454 char buf[BUF_SIZE];
1455 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001456 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001457}
1458
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001459
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001460// --------- XMLElement ---------- //
1461XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001462 _closingType( 0 ),
1463 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001464{
1465}
1466
1467
1468XMLElement::~XMLElement()
1469{
Lee Thomason624d43f2012-10-12 10:58:48 -07001470 while( _rootAttribute ) {
1471 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001472 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001473 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001474 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001475}
1476
1477
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001478const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1479{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001480 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001481 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1482 return a;
1483 }
1484 }
1485 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001486}
1487
1488
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001489const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001490{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001491 const XMLAttribute* a = FindAttribute( name );
1492 if ( !a ) {
1493 return 0;
1494 }
1495 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1496 return a->Value();
1497 }
1498 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001499}
1500
Josh Wittnercf3dd092016-10-11 18:57:17 -07001501int XMLElement::IntAttribute(const char* name, int defaultValue) const
1502{
1503 int i = defaultValue;
1504 QueryIntAttribute(name, &i);
1505 return i;
1506}
1507
1508unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
1509{
1510 unsigned i = defaultValue;
1511 QueryUnsignedAttribute(name, &i);
1512 return i;
1513}
1514
1515int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
1516{
1517 int64_t i = defaultValue;
1518 QueryInt64Attribute(name, &i);
1519 return i;
1520}
1521
1522bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
1523{
1524 bool b = defaultValue;
1525 QueryBoolAttribute(name, &b);
1526 return b;
1527}
1528
1529double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
1530{
1531 double d = defaultValue;
1532 QueryDoubleAttribute(name, &d);
1533 return d;
1534}
1535
1536float XMLElement::FloatAttribute(const char* name, float defaultValue) const
1537{
1538 float f = defaultValue;
1539 QueryFloatAttribute(name, &f);
1540 return f;
1541}
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001542
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001543const char* XMLElement::GetText() const
1544{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001545 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001546 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001547 }
1548 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001549}
1550
1551
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001552void XMLElement::SetText( const char* inText )
1553{
Uli Kusterer869bb592014-01-21 01:36:16 +01001554 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001555 FirstChild()->SetValue( inText );
1556 else {
1557 XMLText* theText = GetDocument()->NewText( inText );
1558 InsertFirstChild( theText );
1559 }
1560}
1561
Lee Thomason5bb2d802014-01-24 10:42:57 -08001562
1563void XMLElement::SetText( int v )
1564{
1565 char buf[BUF_SIZE];
1566 XMLUtil::ToStr( v, buf, BUF_SIZE );
1567 SetText( buf );
1568}
1569
1570
1571void XMLElement::SetText( unsigned v )
1572{
1573 char buf[BUF_SIZE];
1574 XMLUtil::ToStr( v, buf, BUF_SIZE );
1575 SetText( buf );
1576}
1577
1578
Lee Thomason51c12712016-06-04 20:18:49 -07001579void XMLElement::SetText(int64_t v)
1580{
1581 char buf[BUF_SIZE];
1582 XMLUtil::ToStr(v, buf, BUF_SIZE);
1583 SetText(buf);
1584}
1585
1586
1587void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001588{
1589 char buf[BUF_SIZE];
1590 XMLUtil::ToStr( v, buf, BUF_SIZE );
1591 SetText( buf );
1592}
1593
1594
1595void XMLElement::SetText( float v )
1596{
1597 char buf[BUF_SIZE];
1598 XMLUtil::ToStr( v, buf, BUF_SIZE );
1599 SetText( buf );
1600}
1601
1602
1603void XMLElement::SetText( double v )
1604{
1605 char buf[BUF_SIZE];
1606 XMLUtil::ToStr( v, buf, BUF_SIZE );
1607 SetText( buf );
1608}
1609
1610
MortenMacFly4ee49f12013-01-14 20:03:14 +01001611XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001612{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001613 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001614 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001615 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001616 return XML_SUCCESS;
1617 }
1618 return XML_CAN_NOT_CONVERT_TEXT;
1619 }
1620 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001621}
1622
1623
MortenMacFly4ee49f12013-01-14 20:03:14 +01001624XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001625{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001626 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001627 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001628 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001629 return XML_SUCCESS;
1630 }
1631 return XML_CAN_NOT_CONVERT_TEXT;
1632 }
1633 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001634}
1635
1636
Lee Thomason51c12712016-06-04 20:18:49 -07001637XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1638{
1639 if (FirstChild() && FirstChild()->ToText()) {
1640 const char* t = FirstChild()->Value();
1641 if (XMLUtil::ToInt64(t, ival)) {
1642 return XML_SUCCESS;
1643 }
1644 return XML_CAN_NOT_CONVERT_TEXT;
1645 }
1646 return XML_NO_TEXT_NODE;
1647}
1648
1649
MortenMacFly4ee49f12013-01-14 20:03:14 +01001650XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001651{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001652 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001653 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001654 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001655 return XML_SUCCESS;
1656 }
1657 return XML_CAN_NOT_CONVERT_TEXT;
1658 }
1659 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001660}
1661
1662
MortenMacFly4ee49f12013-01-14 20:03:14 +01001663XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001664{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001665 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001666 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001667 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001668 return XML_SUCCESS;
1669 }
1670 return XML_CAN_NOT_CONVERT_TEXT;
1671 }
1672 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001673}
1674
1675
MortenMacFly4ee49f12013-01-14 20:03:14 +01001676XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001677{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001678 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001679 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001680 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001681 return XML_SUCCESS;
1682 }
1683 return XML_CAN_NOT_CONVERT_TEXT;
1684 }
1685 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001686}
1687
Josh Wittnercf3dd092016-10-11 18:57:17 -07001688int XMLElement::IntText(int defaultValue) const
1689{
1690 int i = defaultValue;
1691 QueryIntText(&i);
1692 return i;
1693}
1694
1695unsigned XMLElement::UnsignedText(unsigned defaultValue) const
1696{
1697 unsigned i = defaultValue;
1698 QueryUnsignedText(&i);
1699 return i;
1700}
1701
1702int64_t XMLElement::Int64Text(int64_t defaultValue) const
1703{
1704 int64_t i = defaultValue;
1705 QueryInt64Text(&i);
1706 return i;
1707}
1708
1709bool XMLElement::BoolText(bool defaultValue) const
1710{
1711 bool b = defaultValue;
1712 QueryBoolText(&b);
1713 return b;
1714}
1715
1716double XMLElement::DoubleText(double defaultValue) const
1717{
1718 double d = defaultValue;
1719 QueryDoubleText(&d);
1720 return d;
1721}
1722
1723float XMLElement::FloatText(float defaultValue) const
1724{
1725 float f = defaultValue;
1726 QueryFloatText(&f);
1727 return f;
1728}
Lee Thomason21be8822012-07-15 17:27:22 -07001729
1730
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001731XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1732{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001733 XMLAttribute* last = 0;
1734 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001735 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001736 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001737 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001738 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1739 break;
1740 }
1741 }
1742 if ( !attrib ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001743 attrib = CreateAttribute();
1744 TIXMLASSERT( attrib );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001745 if ( last ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001746 TIXMLASSERT( last->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001747 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001748 }
1749 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001750 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001751 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001752 }
1753 attrib->SetName( name );
1754 }
1755 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001756}
1757
1758
U-Stream\Leeae25a442012-02-17 17:48:16 -08001759void XMLElement::DeleteAttribute( const char* name )
1760{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001761 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001762 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001763 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1764 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001765 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001766 }
1767 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001768 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001769 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001770 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001771 break;
1772 }
1773 prev = a;
1774 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001775}
1776
1777
kezenator4f756162016-11-29 19:46:27 +10001778char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001779{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001780 const char* start = p;
1781 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001782
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001783 // Read the attributes.
1784 while( p ) {
kezenator4f756162016-11-29 19:46:27 +10001785 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001786 if ( !(*p) ) {
kezenatorec694152016-11-26 17:21:43 +10001787 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name(), _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001788 return 0;
1789 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001790
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001791 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001792 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001793 XMLAttribute* attrib = CreateAttribute();
1794 TIXMLASSERT( attrib );
kezenatorec694152016-11-26 17:21:43 +10001795 attrib->_parseLineNum = _document->_parseCurLineNum;
Lee Thomasond1983222012-02-06 08:41:24 -08001796
kezenatorec694152016-11-26 17:21:43 +10001797 int attrLineNum = attrib->_parseLineNum;
1798
kezenator4f756162016-11-29 19:46:27 +10001799 p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001800 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001801 DeleteAttribute( attrib );
kezenatorec694152016-11-26 17:21:43 +10001802 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p, attrLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001803 return 0;
1804 }
1805 // There is a minor bug here: if the attribute in the source xml
1806 // document is duplicated, it will not be detected and the
1807 // attribute will be doubly added. However, tracking the 'prevAttribute'
1808 // avoids re-scanning the attribute list. Preferring performance for
1809 // now, may reconsider in the future.
1810 if ( prevAttribute ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001811 TIXMLASSERT( prevAttribute->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001812 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001813 }
1814 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001815 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001816 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001817 }
1818 prevAttribute = attrib;
1819 }
1820 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001821 else if ( *p == '>' ) {
1822 ++p;
1823 break;
1824 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001825 // end of the tag
1826 else if ( *p == '/' && *(p+1) == '>' ) {
1827 _closingType = CLOSED;
1828 return p+2; // done; sealed element.
1829 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001830 else {
kezenatorec694152016-11-26 17:21:43 +10001831 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001832 return 0;
1833 }
1834 }
1835 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001836}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001837
Dmitry-Mee3225b12014-09-03 11:03:11 +04001838void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1839{
1840 if ( attribute == 0 ) {
1841 return;
1842 }
1843 MemPool* pool = attribute->_memPool;
1844 attribute->~XMLAttribute();
1845 pool->Free( attribute );
1846}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001847
Dmitry-Mea60caa22016-11-22 18:28:08 +03001848XMLAttribute* XMLElement::CreateAttribute()
1849{
1850 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
1851 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1852 attrib->_memPool = &_document->_attributePool;
1853 attrib->_memPool->SetTracked();
1854 return attrib;
1855}
1856
Lee Thomason67d61312012-01-24 16:01:51 -08001857//
1858// <ele></ele>
1859// <ele>foo<b>bar</b></ele>
1860//
kezenator4f756162016-11-29 19:46:27 +10001861char* XMLElement::ParseDeep( char* p, StrPair* strPair, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -08001862{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001863 // Read the element name.
kezenator4f756162016-11-29 19:46:27 +10001864 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomason67d61312012-01-24 16:01:51 -08001865
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001866 // The closing element is the </element> form. It is
1867 // parsed just like a regular element then deleted from
1868 // the DOM.
1869 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001870 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001871 ++p;
1872 }
Lee Thomason67d61312012-01-24 16:01:51 -08001873
Lee Thomason624d43f2012-10-12 10:58:48 -07001874 p = _value.ParseName( p );
1875 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001876 return 0;
1877 }
Lee Thomason67d61312012-01-24 16:01:51 -08001878
kezenator4f756162016-11-29 19:46:27 +10001879 p = ParseAttributes( p, curLineNumPtr );
Lee Thomason624d43f2012-10-12 10:58:48 -07001880 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001881 return p;
1882 }
Lee Thomason67d61312012-01-24 16:01:51 -08001883
kezenator4f756162016-11-29 19:46:27 +10001884 p = XMLNode::ParseDeep( p, strPair, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001885 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001886}
1887
1888
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001889
1890XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1891{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001892 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001893 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001894 }
1895 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1896 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1897 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1898 }
1899 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001900}
1901
1902
1903bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1904{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001905 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001906 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001907 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001908
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001909 const XMLAttribute* a=FirstAttribute();
1910 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001911
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001912 while ( a && b ) {
1913 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1914 return false;
1915 }
1916 a = a->Next();
1917 b = b->Next();
1918 }
1919 if ( a || b ) {
1920 // different count
1921 return false;
1922 }
1923 return true;
1924 }
1925 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001926}
1927
1928
Lee Thomason751da522012-02-10 08:50:51 -08001929bool XMLElement::Accept( XMLVisitor* visitor ) const
1930{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001931 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001932 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001933 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1934 if ( !node->Accept( visitor ) ) {
1935 break;
1936 }
1937 }
1938 }
1939 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001940}
Lee Thomason56bdd022012-02-09 18:16:58 -08001941
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001942
Lee Thomason3f57d272012-01-11 15:30:03 -08001943// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001944
1945// Warning: List must match 'enum XMLError'
1946const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1947 "XML_SUCCESS",
1948 "XML_NO_ATTRIBUTE",
1949 "XML_WRONG_ATTRIBUTE_TYPE",
1950 "XML_ERROR_FILE_NOT_FOUND",
1951 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1952 "XML_ERROR_FILE_READ_ERROR",
1953 "XML_ERROR_ELEMENT_MISMATCH",
1954 "XML_ERROR_PARSING_ELEMENT",
1955 "XML_ERROR_PARSING_ATTRIBUTE",
1956 "XML_ERROR_IDENTIFYING_TAG",
1957 "XML_ERROR_PARSING_TEXT",
1958 "XML_ERROR_PARSING_CDATA",
1959 "XML_ERROR_PARSING_COMMENT",
1960 "XML_ERROR_PARSING_DECLARATION",
1961 "XML_ERROR_PARSING_UNKNOWN",
1962 "XML_ERROR_EMPTY_DOCUMENT",
1963 "XML_ERROR_MISMATCHED_ELEMENT",
1964 "XML_ERROR_PARSING",
1965 "XML_CAN_NOT_CONVERT_TEXT",
1966 "XML_NO_TEXT_NODE"
1967};
1968
1969
Lee Thomason624d43f2012-10-12 10:58:48 -07001970XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001971 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001972 _writeBOM( false ),
1973 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07001974 _errorID(XML_SUCCESS),
Lee Thomason624d43f2012-10-12 10:58:48 -07001975 _whitespace( whitespace ),
Dmitry-Mef89bd3e2017-01-18 18:33:55 +03001976 _errorLineNum( 0 ),
1977 _charBuffer( 0 ),
1978 _parseCurLineNum( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001979{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03001980 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
1981 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08001982}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001983
1984
Lee Thomason3f57d272012-01-11 15:30:03 -08001985XMLDocument::~XMLDocument()
1986{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001987 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001988}
1989
1990
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001991void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001992{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001993 DeleteChildren();
1994
Dmitry-Meab37df82014-11-28 12:08:36 +03001995#ifdef DEBUG
1996 const bool hadError = Error();
1997#endif
Dmitry-Me0d2cef02016-11-25 18:39:52 +03001998 ClearError();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001999
Lee Thomason624d43f2012-10-12 10:58:48 -07002000 delete [] _charBuffer;
2001 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07002002
2003#if 0
2004 _textPool.Trace( "text" );
2005 _elementPool.Trace( "element" );
2006 _commentPool.Trace( "comment" );
2007 _attributePool.Trace( "attribute" );
2008#endif
2009
2010#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03002011 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002012 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
2013 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
2014 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
2015 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
2016 }
2017#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08002018}
2019
Lee Thomason3f57d272012-01-11 15:30:03 -08002020
Lee Thomason7085f002017-06-01 18:09:43 -07002021void XMLDocument::DeepCopy(XMLDocument* target)
2022{
2023 TIXMLASSERT(target);
2024 TIXMLASSERT(target != this);
2025
2026 target->Clear();
2027 for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {
2028 target->InsertEndChild(node->DeepClone(target));
2029 }
2030}
2031
Lee Thomason2c85a712012-01-31 08:24:24 -08002032XMLElement* XMLDocument::NewElement( const char* name )
2033{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03002034 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07002035 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
2036 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002037 ele->SetName( name );
2038 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08002039}
2040
2041
Lee Thomason1ff38e02012-02-14 18:18:16 -08002042XMLComment* XMLDocument::NewComment( const char* str )
2043{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03002044 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07002045 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
2046 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002047 comment->SetValue( str );
2048 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002049}
2050
2051
2052XMLText* XMLDocument::NewText( const char* str )
2053{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03002054 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07002055 XMLText* text = new (_textPool.Alloc()) XMLText( this );
2056 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002057 text->SetValue( str );
2058 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002059}
2060
2061
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002062XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2063{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03002064 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07002065 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
2066 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002067 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2068 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002069}
2070
2071
2072XMLUnknown* XMLDocument::NewUnknown( const char* str )
2073{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03002074 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07002075 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
2076 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002077 unk->SetValue( str );
2078 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002079}
2080
Dmitry-Me01578db2014-08-19 10:18:48 +04002081static FILE* callfopen( const char* filepath, const char* mode )
2082{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002083 TIXMLASSERT( filepath );
2084 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002085#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2086 FILE* fp = 0;
2087 errno_t err = fopen_s( &fp, filepath, mode );
2088 if ( err ) {
2089 return 0;
2090 }
2091#else
2092 FILE* fp = fopen( filepath, mode );
2093#endif
2094 return fp;
2095}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08002096
2097void XMLDocument::DeleteNode( XMLNode* node ) {
2098 TIXMLASSERT( node );
2099 TIXMLASSERT(node->_document == this );
2100 if (node->_parent) {
2101 node->_parent->DeleteChild( node );
2102 }
2103 else {
2104 // Isn't in the tree.
2105 // Use the parent delete.
2106 // Also, we need to mark it tracked: we 'know'
2107 // it was never used.
2108 node->_memPool->SetTracked();
2109 // Call the static XMLNode version:
2110 XMLNode::DeleteNode(node);
2111 }
2112}
2113
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002114
Lee Thomason2fa81722012-11-09 12:37:46 -08002115XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002116{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002117 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04002118 FILE* fp = callfopen( filename, "rb" );
2119 if ( !fp ) {
kezenatorec694152016-11-26 17:21:43 +10002120 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002121 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002122 }
2123 LoadFile( fp );
2124 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002125 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002126}
2127
Dmitry-Me901fed52015-09-25 10:29:51 +03002128// This is likely overengineered template art to have a check that unsigned long value incremented
2129// by one still fits into size_t. If size_t type is larger than unsigned long type
2130// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
2131// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
2132// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
2133// types sizes relate to each other.
2134template
2135<bool = (sizeof(unsigned long) >= sizeof(size_t))>
2136struct LongFitsIntoSizeTMinusOne {
2137 static bool Fits( unsigned long value )
2138 {
2139 return value < (size_t)-1;
2140 }
2141};
2142
2143template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02002144struct LongFitsIntoSizeTMinusOne<false> {
2145 static bool Fits( unsigned long )
2146 {
2147 return true;
2148 }
2149};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002150
Lee Thomason2fa81722012-11-09 12:37:46 -08002151XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002152{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002153 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002154
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002155 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002156 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
kezenatorec694152016-11-26 17:21:43 +10002157 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002158 return _errorID;
2159 }
2160
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002161 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002162 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002163 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002164 if ( filelength == -1L ) {
kezenatorec694152016-11-26 17:21:43 +10002165 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002166 return _errorID;
2167 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002168 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002169
Dmitry-Me901fed52015-09-25 10:29:51 +03002170 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002171 // Cannot handle files which won't fit in buffer together with null terminator
kezenatorec694152016-11-26 17:21:43 +10002172 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002173 return _errorID;
2174 }
2175
Dmitry-Me72801b82015-05-07 09:41:39 +03002176 if ( filelength == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10002177 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002178 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002179 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002180
Dmitry-Me72801b82015-05-07 09:41:39 +03002181 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002182 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002183 _charBuffer = new char[size+1];
2184 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002185 if ( read != size ) {
kezenatorec694152016-11-26 17:21:43 +10002186 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002187 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002188 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002189
Lee Thomason624d43f2012-10-12 10:58:48 -07002190 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002191
Dmitry-Me97476b72015-01-01 16:15:57 +03002192 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002193 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002194}
2195
2196
Lee Thomason2fa81722012-11-09 12:37:46 -08002197XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002198{
Dmitry-Me01578db2014-08-19 10:18:48 +04002199 FILE* fp = callfopen( filename, "w" );
2200 if ( !fp ) {
kezenatorec694152016-11-26 17:21:43 +10002201 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002202 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002203 }
2204 SaveFile(fp, compact);
2205 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002206 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002207}
2208
2209
Lee Thomason2fa81722012-11-09 12:37:46 -08002210XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002211{
Ant Mitchell189198f2015-03-24 16:20:36 +00002212 // Clear any error from the last save, otherwise it will get reported
2213 // for *this* call.
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002214 ClearError();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002215 XMLPrinter stream( fp, compact );
2216 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002217 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002218}
2219
Lee Thomason1ff38e02012-02-14 18:18:16 -08002220
Lee Thomason2fa81722012-11-09 12:37:46 -08002221XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002222{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002223 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002224
Lee Thomason82d32002014-02-21 22:47:18 -08002225 if ( len == 0 || !p || !*p ) {
kezenatorec694152016-11-26 17:21:43 +10002226 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002227 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002228 }
2229 if ( len == (size_t)(-1) ) {
2230 len = strlen( p );
2231 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002232 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002233 _charBuffer = new char[ len+1 ];
2234 memcpy( _charBuffer, p, len );
2235 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002236
Dmitry-Me97476b72015-01-01 16:15:57 +03002237 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002238 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002239 // clean up now essentially dangling memory.
2240 // and the parse fail can put objects in the
2241 // pools that are dead and inaccessible.
2242 DeleteChildren();
2243 _elementPool.Clear();
2244 _attributePool.Clear();
2245 _textPool.Clear();
2246 _commentPool.Clear();
2247 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002248 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002249}
2250
2251
PKEuS1c5f99e2013-07-06 11:28:39 +02002252void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002253{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002254 if ( streamer ) {
2255 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002256 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002257 else {
2258 XMLPrinter stdoutStreamer( stdout );
2259 Accept( &stdoutStreamer );
2260 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002261}
2262
2263
kezenatorec694152016-11-26 17:21:43 +10002264void XMLDocument::SetError( XMLError error, const char* str1, const char* str2, int lineNum )
Lee Thomason67d61312012-01-24 16:01:51 -08002265{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002266 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002267 _errorID = error;
Lee Thomason584af572016-09-05 14:14:16 -07002268
2269 _errorStr1.Reset();
2270 _errorStr2.Reset();
kezenatorec694152016-11-26 17:21:43 +10002271 _errorLineNum = lineNum;
Lee Thomason584af572016-09-05 14:14:16 -07002272
2273 if (str1)
2274 _errorStr1.SetStr(str1);
2275 if (str2)
2276 _errorStr2.SetStr(str2);
Lee Thomason67d61312012-01-24 16:01:51 -08002277}
2278
Lee Thomasone90e9012016-12-24 07:34:39 -08002279/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
Lee Thomason331596e2014-09-11 14:56:43 -07002280{
kezenator5a700712016-11-26 13:54:42 +10002281 TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2282 const char* errorName = _errorNames[errorID];
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002283 TIXMLASSERT( errorName && errorName[0] );
2284 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002285}
Lee Thomason5cae8972012-01-24 18:03:07 -08002286
kezenator5a700712016-11-26 13:54:42 +10002287const char* XMLDocument::ErrorName() const
2288{
Lee Thomasone90e9012016-12-24 07:34:39 -08002289 return ErrorIDToName(_errorID);
kezenator5a700712016-11-26 13:54:42 +10002290}
2291
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002292void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002293{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002294 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002295 static const int LEN = 20;
2296 char buf1[LEN] = { 0 };
2297 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002298
Lee Thomason584af572016-09-05 14:14:16 -07002299 if ( !_errorStr1.Empty() ) {
2300 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002301 }
Lee Thomason584af572016-09-05 14:14:16 -07002302 if ( !_errorStr2.Empty() ) {
2303 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002304 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002305
Dmitry-Me2ad43202015-04-16 12:18:58 +03002306 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2307 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2308 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
kezenatorec694152016-11-26 17:21:43 +10002309 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s line=%d\n",
2310 static_cast<int>( _errorID ), ErrorName(), buf1, buf2, _errorLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002311 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002312}
2313
Dmitry-Me97476b72015-01-01 16:15:57 +03002314void XMLDocument::Parse()
2315{
2316 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2317 TIXMLASSERT( _charBuffer );
kezenatorec694152016-11-26 17:21:43 +10002318 _parseCurLineNum = 1;
2319 _parseLineNum = 1;
Lee Thomason3cebdc42015-01-05 17:16:28 -08002320 char* p = _charBuffer;
kezenator4f756162016-11-29 19:46:27 +10002321 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mee28be752015-01-09 14:59:30 +03002322 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002323 if ( !*p ) {
kezenatorec694152016-11-26 17:21:43 +10002324 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002325 return;
2326 }
kezenator4f756162016-11-29 19:46:27 +10002327 ParseDeep(p, 0, &_parseCurLineNum );
Dmitry-Me97476b72015-01-01 16:15:57 +03002328}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002329
PKEuS1bfb9542013-08-04 13:51:17 +02002330XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002331 _elementJustOpened( false ),
2332 _firstElement( true ),
2333 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002334 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002335 _textDepth( -1 ),
2336 _processEntities( true ),
2337 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002338{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002339 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002340 _entityFlag[i] = false;
2341 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002342 }
2343 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002344 const char entityValue = entities[i].value;
Dmitry-Mec5f1e7c2016-10-14 10:33:02 +03002345 TIXMLASSERT( ((unsigned char)entityValue) < ENTITY_RANGE );
Dmitry-Me8b67d742014-12-22 11:35:12 +03002346 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002347 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002348 _restrictedEntityFlag[(unsigned char)'&'] = true;
2349 _restrictedEntityFlag[(unsigned char)'<'] = true;
2350 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002351 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002352}
2353
2354
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002355void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002356{
2357 va_list va;
2358 va_start( va, format );
2359
Lee Thomason624d43f2012-10-12 10:58:48 -07002360 if ( _fp ) {
2361 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002362 }
2363 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002364 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002365 // Close out and re-start the va-args
2366 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002367 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002368 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002369 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002370 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002371 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002372 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002373 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002374}
2375
2376
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002377void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002378{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002379 for( int i=0; i<depth; ++i ) {
2380 Print( " " );
2381 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002382}
2383
2384
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002385void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002386{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002387 // Look for runs of bytes between entities to print.
2388 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002389
Lee Thomason624d43f2012-10-12 10:58:48 -07002390 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002391 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002392 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002393 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002394 // Remember, char is sometimes signed. (How many times has that bitten me?)
2395 if ( *q > 0 && *q < ENTITY_RANGE ) {
2396 // Check for entities. If one is found, flush
2397 // the stream up until the entity, write the
2398 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002399 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002400 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002401 const size_t delta = q - p;
2402 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002403 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002404 Print( "%.*s", toPrint, p );
2405 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002406 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002407 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002408 for( int i=0; i<NUM_ENTITIES; ++i ) {
2409 if ( entities[i].value == *q ) {
2410 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002411 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002412 break;
2413 }
2414 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002415 if ( !entityPatternPrinted ) {
2416 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2417 TIXMLASSERT( false );
2418 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002419 ++p;
2420 }
2421 }
2422 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002423 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002424 }
2425 }
2426 // Flush the remaining string. This will be the entire
2427 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002428 TIXMLASSERT( p <= q );
2429 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002430 Print( "%s", p );
2431 }
Lee Thomason857b8682012-01-25 17:50:25 -08002432}
2433
U-Stream\Leeae25a442012-02-17 17:48:16 -08002434
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002435void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002436{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002437 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002438 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 -07002439 Print( "%s", bom );
2440 }
2441 if ( writeDec ) {
2442 PushDeclaration( "xml version=\"1.0\"" );
2443 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002444}
2445
2446
Uli Kusterer593a33d2014-02-01 12:48:51 +01002447void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002448{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002449 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002450 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002451
Uli Kusterer593a33d2014-02-01 12:48:51 +01002452 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002453 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002454 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002455 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002456 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002457 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002458
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002459 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002460 _elementJustOpened = true;
2461 _firstElement = false;
2462 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002463}
2464
2465
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002466void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002467{
Lee Thomason624d43f2012-10-12 10:58:48 -07002468 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002469 Print( " %s=\"", name );
2470 PrintString( value, false );
2471 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002472}
2473
2474
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002475void XMLPrinter::PushAttribute( const char* name, int v )
2476{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002477 char buf[BUF_SIZE];
2478 XMLUtil::ToStr( v, buf, BUF_SIZE );
2479 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002480}
2481
2482
2483void XMLPrinter::PushAttribute( const char* name, unsigned v )
2484{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002485 char buf[BUF_SIZE];
2486 XMLUtil::ToStr( v, buf, BUF_SIZE );
2487 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002488}
2489
2490
Lee Thomason51c12712016-06-04 20:18:49 -07002491void XMLPrinter::PushAttribute(const char* name, int64_t v)
2492{
2493 char buf[BUF_SIZE];
2494 XMLUtil::ToStr(v, buf, BUF_SIZE);
2495 PushAttribute(name, buf);
2496}
2497
2498
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002499void XMLPrinter::PushAttribute( const char* name, bool 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, double 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
Uli Kustererca412e82014-02-01 13:35:05 +01002515void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002516{
Lee Thomason624d43f2012-10-12 10:58:48 -07002517 --_depth;
2518 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002519
Lee Thomason624d43f2012-10-12 10:58:48 -07002520 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002521 Print( "/>" );
2522 }
2523 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002524 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002525 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002526 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002527 }
2528 Print( "</%s>", name );
2529 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002530
Lee Thomason624d43f2012-10-12 10:58:48 -07002531 if ( _textDepth == _depth ) {
2532 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002533 }
Uli Kustererca412e82014-02-01 13:35:05 +01002534 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002535 Print( "\n" );
2536 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002537 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002538}
2539
2540
Dmitry-Mea092bc12014-12-23 17:57:05 +03002541void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002542{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002543 if ( !_elementJustOpened ) {
2544 return;
2545 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002546 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002547 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002548}
2549
2550
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002551void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002552{
Lee Thomason624d43f2012-10-12 10:58:48 -07002553 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002554
Dmitry-Mea092bc12014-12-23 17:57:05 +03002555 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002556 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002557 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002558 }
2559 else {
2560 PrintString( text, true );
2561 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002562}
2563
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002564void XMLPrinter::PushText( int64_t value )
2565{
2566 char buf[BUF_SIZE];
2567 XMLUtil::ToStr( value, buf, BUF_SIZE );
2568 PushText( buf, false );
2569}
2570
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002571void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002572{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002573 char buf[BUF_SIZE];
2574 XMLUtil::ToStr( value, buf, BUF_SIZE );
2575 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002576}
2577
2578
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002579void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002580{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002581 char buf[BUF_SIZE];
2582 XMLUtil::ToStr( value, buf, BUF_SIZE );
2583 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002584}
2585
2586
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002587void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002588{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002589 char buf[BUF_SIZE];
2590 XMLUtil::ToStr( value, buf, BUF_SIZE );
2591 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002592}
2593
2594
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002595void XMLPrinter::PushText( float 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( double 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
Lee Thomason5cae8972012-01-24 18:03:07 -08002610
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002611void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002612{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002613 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002614 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002615 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002616 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002617 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002618 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002619 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002620}
Lee Thomason751da522012-02-10 08:50:51 -08002621
2622
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002623void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002624{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002625 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002626 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002627 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002628 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002629 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002630 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002631 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002632}
2633
2634
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002635void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -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>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002644}
2645
2646
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002647bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002648{
Lee Thomason624d43f2012-10-12 10:58:48 -07002649 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002650 if ( doc.HasBOM() ) {
2651 PushHeader( true, false );
2652 }
2653 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002654}
2655
2656
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002657bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002658{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002659 const XMLElement* parentElem = 0;
2660 if ( element.Parent() ) {
2661 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002662 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002663 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002664 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002665 while ( attribute ) {
2666 PushAttribute( attribute->Name(), attribute->Value() );
2667 attribute = attribute->Next();
2668 }
2669 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002670}
2671
2672
Uli Kustererca412e82014-02-01 13:35:05 +01002673bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002674{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002675 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002676 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002677}
2678
2679
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002680bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002681{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002682 PushText( text.Value(), text.CData() );
2683 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002684}
2685
2686
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002687bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002688{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002689 PushComment( comment.Value() );
2690 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002691}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002692
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002693bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002694{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002695 PushDeclaration( declaration.Value() );
2696 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002697}
2698
2699
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002700bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002701{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002702 PushUnknown( unknown.Value() );
2703 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002704}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002705
Lee Thomason685b8952012-11-12 13:00:06 -08002706} // namespace tinyxml2
2707