blob: e54940f276ba24b9306ed410fd12cc7af0d2bc0a [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-Me2aebfb72017-02-27 15:53:40 +0300668 returnNode = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000669 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700670 p += xmlHeaderLen;
671 }
672 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300673 returnNode = CreateUnlinkedNode<XMLComment>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000674 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700675 p += commentHeaderLen;
676 }
677 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300678 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700679 returnNode = text;
kezenatorec694152016-11-26 17:21:43 +1000680 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700681 p += cdataHeaderLen;
682 text->SetCData( true );
683 }
684 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300685 returnNode = CreateUnlinkedNode<XMLUnknown>( _commentPool );
kezenatorec694152016-11-26 17:21:43 +1000686 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700687 p += dtdHeaderLen;
688 }
689 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300690 returnNode = CreateUnlinkedNode<XMLElement>( _elementPool );
kezenatorec694152016-11-26 17:21:43 +1000691 returnNode->_parseLineNum = _parseCurLineNum;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700692 p += elementHeaderLen;
693 }
694 else {
Dmitry-Me2aebfb72017-02-27 15:53:40 +0300695 returnNode = CreateUnlinkedNode<XMLText>( _textPool );
kezenatorec694152016-11-26 17:21:43 +1000696 returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700697 p = start; // Back it up, all the text counts.
kezenatorec694152016-11-26 17:21:43 +1000698 _parseCurLineNum = startLine;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700699 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800700
Dmitry-Me02384662015-03-03 16:02:13 +0300701 TIXMLASSERT( returnNode );
702 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700703 *node = returnNode;
704 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800705}
706
707
Lee Thomason751da522012-02-10 08:50:51 -0800708bool XMLDocument::Accept( XMLVisitor* visitor ) const
709{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300710 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700711 if ( visitor->VisitEnter( *this ) ) {
712 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
713 if ( !node->Accept( visitor ) ) {
714 break;
715 }
716 }
717 }
718 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800719}
Lee Thomason56bdd022012-02-09 18:16:58 -0800720
721
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800722// --------- XMLNode ----------- //
723
724XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700725 _document( doc ),
726 _parent( 0 ),
kezenatorec694152016-11-26 17:21:43 +1000727 _parseLineNum( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -0700728 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200729 _prev( 0 ), _next( 0 ),
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700730 _userData( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200731 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800732{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800733}
734
735
736XMLNode::~XMLNode()
737{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700738 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700739 if ( _parent ) {
740 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700741 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800742}
743
Michael Daumling21626882013-10-22 17:03:37 +0200744const char* XMLNode::Value() const
745{
Dmitry-Mecaa72a62016-08-10 17:34:34 +0300746 // Edge case: XMLDocuments don't have a Value. Return null.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530747 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530748 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200749 return _value.GetStr();
750}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800751
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800752void XMLNode::SetValue( const char* str, bool staticMem )
753{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700754 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700755 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700756 }
757 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700758 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700759 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800760}
761
762
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800763void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800764{
Lee Thomason624d43f2012-10-12 10:58:48 -0700765 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300766 TIXMLASSERT( _lastChild );
Dmitry-Me9cb4eca2016-08-18 18:10:59 +0300767 DeleteChild( _firstChild );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700768 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700769 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800770}
771
772
773void XMLNode::Unlink( XMLNode* child )
774{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300775 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300776 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300777 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700778 if ( child == _firstChild ) {
779 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700780 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700781 if ( child == _lastChild ) {
782 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700783 }
Lee Thomasond923c672012-01-23 08:44:25 -0800784
Lee Thomason624d43f2012-10-12 10:58:48 -0700785 if ( child->_prev ) {
786 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700787 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700788 if ( child->_next ) {
789 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700790 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700791 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800792}
793
794
U-Stream\Leeae25a442012-02-17 17:48:16 -0800795void XMLNode::DeleteChild( XMLNode* node )
796{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300797 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300798 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700799 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100800 Unlink( node );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400801 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800802}
803
804
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800805XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
806{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300807 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300808 if ( addThis->_document != _document ) {
809 TIXMLASSERT( false );
810 return 0;
811 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800812 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700813
Lee Thomason624d43f2012-10-12 10:58:48 -0700814 if ( _lastChild ) {
815 TIXMLASSERT( _firstChild );
816 TIXMLASSERT( _lastChild->_next == 0 );
817 _lastChild->_next = addThis;
818 addThis->_prev = _lastChild;
819 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800820
Lee Thomason624d43f2012-10-12 10:58:48 -0700821 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700822 }
823 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700824 TIXMLASSERT( _firstChild == 0 );
825 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800826
Lee Thomason624d43f2012-10-12 10:58:48 -0700827 addThis->_prev = 0;
828 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700829 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700830 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700831 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800832}
833
834
Lee Thomason1ff38e02012-02-14 18:18:16 -0800835XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
836{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300837 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300838 if ( addThis->_document != _document ) {
839 TIXMLASSERT( false );
840 return 0;
841 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800842 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700843
Lee Thomason624d43f2012-10-12 10:58:48 -0700844 if ( _firstChild ) {
845 TIXMLASSERT( _lastChild );
846 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800847
Lee Thomason624d43f2012-10-12 10:58:48 -0700848 _firstChild->_prev = addThis;
849 addThis->_next = _firstChild;
850 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800851
Lee Thomason624d43f2012-10-12 10:58:48 -0700852 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700853 }
854 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700855 TIXMLASSERT( _lastChild == 0 );
856 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800857
Lee Thomason624d43f2012-10-12 10:58:48 -0700858 addThis->_prev = 0;
859 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700860 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700861 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400862 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800863}
864
865
866XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
867{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300868 TIXMLASSERT( addThis );
869 if ( addThis->_document != _document ) {
870 TIXMLASSERT( false );
871 return 0;
872 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700873
Dmitry-Meabb2d042014-12-09 12:59:31 +0300874 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700875
Lee Thomason624d43f2012-10-12 10:58:48 -0700876 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300877 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700878 return 0;
879 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800880
Lee Thomason624d43f2012-10-12 10:58:48 -0700881 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700882 // The last node or the only node.
883 return InsertEndChild( addThis );
884 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800885 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700886 addThis->_prev = afterThis;
887 addThis->_next = afterThis->_next;
888 afterThis->_next->_prev = addThis;
889 afterThis->_next = addThis;
890 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700891 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800892}
893
894
895
896
Dmitry-Me886ad972015-07-22 11:00:51 +0300897const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800898{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300899 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300900 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700901 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300902 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700903 }
904 }
905 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800906}
907
908
Dmitry-Me886ad972015-07-22 11:00:51 +0300909const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800910{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300911 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300912 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700913 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300914 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700915 }
916 }
917 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800918}
919
920
Dmitry-Me886ad972015-07-22 11:00:51 +0300921const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800922{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300923 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300924 const XMLElement* element = node->ToElementWithName( name );
925 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400926 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700927 }
928 }
929 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800930}
931
932
Dmitry-Me886ad972015-07-22 11:00:51 +0300933const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800934{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300935 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300936 const XMLElement* element = node->ToElementWithName( name );
937 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400938 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700939 }
940 }
941 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800942}
943
944
kezenator4f756162016-11-29 19:46:27 +1000945char* XMLNode::ParseDeep( char* p, StrPair* parentEnd, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -0800946{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700947 // This is a recursive method, but thinking about it "at the current level"
948 // it is a pretty simple flat list:
949 // <foo/>
950 // <!-- comment -->
951 //
952 // With a special case:
953 // <foo>
954 // </foo>
955 // <!-- comment -->
956 //
957 // Where the closing element (/foo) *must* be the next thing after the opening
958 // element, and the names must match. BUT the tricky bit is that the closing
959 // element will be read by the child.
960 //
961 // 'endTag' is the end tag for this node, it is returned by a call to a child.
962 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800963
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700964 while( p && *p ) {
965 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800966
Lee Thomason624d43f2012-10-12 10:58:48 -0700967 p = _document->Identify( p, &node );
Dmitry-Me43364312016-11-07 18:48:50 +0300968 TIXMLASSERT( p );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300969 if ( node == 0 ) {
970 break;
971 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800972
kezenatore3531812016-11-29 19:49:07 +1000973 int initialLineNum = node->_parseLineNum;
kezenatorec694152016-11-26 17:21:43 +1000974
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700975 StrPair endTag;
kezenator4f756162016-11-29 19:46:27 +1000976 p = node->ParseDeep( p, &endTag, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700977 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400978 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700979 if ( !_document->Error() ) {
kezenatore3531812016-11-29 19:49:07 +1000980 _document->SetError( XML_ERROR_PARSING, 0, 0, initialLineNum);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700981 }
982 break;
983 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800984
Sarat Addepalli3df007e2015-05-20 10:43:51 +0530985 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530986 if ( decl ) {
Dmitry-Me446c3bc2016-11-11 10:34:56 +0300987 // Declarations are only allowed at document level
988 bool wellLocated = ( ToDocument() != 0 );
989 if ( wellLocated ) {
990 // Multiple declarations are allowed but all declarations
991 // must occur before anything else
992 for ( const XMLNode* existingNode = _document->FirstChild(); existingNode; existingNode = existingNode->NextSibling() ) {
993 if ( !existingNode->ToDeclaration() ) {
994 wellLocated = false;
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530995 break;
Dmitry-Me446c3bc2016-11-11 10:34:56 +0300996 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530997 }
Dmitry-Me446c3bc2016-11-11 10:34:56 +0300998 }
999 if ( !wellLocated ) {
kezenatore3531812016-11-29 19:49:07 +10001000 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0, initialLineNum);
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001001 DeleteNode( node );
1002 break;
1003 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301004 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301005
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001006 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001007 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -05001008 // We read the end tag. Return it to the parent.
1009 if ( ele->ClosingType() == XMLElement::CLOSING ) {
1010 if ( parentEnd ) {
1011 ele->_value.TransferTo( parentEnd );
1012 }
1013 node->_memPool->SetTracked(); // created and then immediately deleted.
1014 DeleteNode( node );
1015 return p;
1016 }
1017
1018 // Handle an end tag returned to this level.
1019 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001020 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001021 if ( endTag.Empty() ) {
1022 if ( ele->ClosingType() == XMLElement::OPEN ) {
1023 mismatch = true;
1024 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001025 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001026 else {
1027 if ( ele->ClosingType() != XMLElement::OPEN ) {
1028 mismatch = true;
1029 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001030 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001031 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001032 }
1033 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001034 if ( mismatch ) {
kezenatore3531812016-11-29 19:49:07 +10001035 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0, initialLineNum);
JayXondbfdd8f2014-12-12 20:07:14 -05001036 DeleteNode( node );
1037 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001038 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001039 }
JayXondbfdd8f2014-12-12 20:07:14 -05001040 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001041 }
1042 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001043}
1044
Dmitry-Mee3225b12014-09-03 11:03:11 +04001045void XMLNode::DeleteNode( XMLNode* node )
1046{
1047 if ( node == 0 ) {
1048 return;
1049 }
1050 MemPool* pool = node->_memPool;
1051 node->~XMLNode();
1052 pool->Free( node );
1053}
1054
Lee Thomason3cebdc42015-01-05 17:16:28 -08001055void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001056{
1057 TIXMLASSERT( insertThis );
1058 TIXMLASSERT( insertThis->_document == _document );
1059
1060 if ( insertThis->_parent )
1061 insertThis->_parent->Unlink( insertThis );
1062 else
1063 insertThis->_memPool->SetTracked();
1064}
1065
Dmitry-Meecb9b072016-10-12 16:44:59 +03001066const XMLElement* XMLNode::ToElementWithName( const char* name ) const
1067{
1068 const XMLElement* element = this->ToElement();
1069 if ( element == 0 ) {
1070 return 0;
1071 }
1072 if ( name == 0 ) {
1073 return element;
1074 }
1075 if ( XMLUtil::StringEqual( element->Name(), name ) ) {
1076 return element;
1077 }
1078 return 0;
1079}
1080
Lee Thomason5492a1c2012-01-23 15:32:10 -08001081// --------- XMLText ---------- //
kezenator4f756162016-11-29 19:46:27 +10001082char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001083{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001084 const char* start = p;
1085 if ( this->CData() ) {
kezenator4f756162016-11-29 19:46:27 +10001086 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001087 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001088 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001089 }
1090 return p;
1091 }
1092 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001093 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1094 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001095 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001096 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001097
kezenator4f756162016-11-29 19:46:27 +10001098 p = _value.ParseText( p, "<", flags, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001099 if ( p && *p ) {
1100 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001101 }
1102 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001103 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001104 }
1105 }
1106 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001107}
1108
1109
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001110XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1111{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001112 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001113 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001114 }
1115 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1116 text->SetCData( this->CData() );
1117 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001118}
1119
1120
1121bool XMLText::ShallowEqual( const XMLNode* compare ) const
1122{
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001123 const XMLText* text = compare->ToText();
1124 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001125}
1126
1127
Lee Thomason56bdd022012-02-09 18:16:58 -08001128bool XMLText::Accept( XMLVisitor* visitor ) const
1129{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001130 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001131 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001132}
1133
1134
Lee Thomason3f57d272012-01-11 15:30:03 -08001135// --------- XMLComment ---------- //
1136
Lee Thomasone4422302012-01-20 17:59:50 -08001137XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001138{
1139}
1140
1141
Lee Thomasonce0763e2012-01-11 15:43:54 -08001142XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001143{
Lee Thomason3f57d272012-01-11 15:30:03 -08001144}
1145
1146
kezenator4f756162016-11-29 19:46:27 +10001147char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason3f57d272012-01-11 15:30:03 -08001148{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001149 // Comment parses as text.
1150 const char* start = p;
kezenator4f756162016-11-29 19:46:27 +10001151 p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001152 if ( p == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10001153 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001154 }
1155 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001156}
1157
1158
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001159XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1160{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001161 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001162 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001163 }
1164 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1165 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001166}
1167
1168
1169bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1170{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001171 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001172 const XMLComment* comment = compare->ToComment();
1173 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001174}
1175
1176
Lee Thomason751da522012-02-10 08:50:51 -08001177bool XMLComment::Accept( XMLVisitor* visitor ) const
1178{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001179 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001180 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001181}
Lee Thomason56bdd022012-02-09 18:16:58 -08001182
1183
Lee Thomason50f97b22012-02-11 16:33:40 -08001184// --------- XMLDeclaration ---------- //
1185
1186XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1187{
1188}
1189
1190
1191XMLDeclaration::~XMLDeclaration()
1192{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001193 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001194}
1195
1196
kezenator4f756162016-11-29 19:46:27 +10001197char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001198{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001199 // Declaration parses as text.
1200 const char* start = p;
kezenator4f756162016-11-29 19:46:27 +10001201 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001202 if ( p == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10001203 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001204 }
1205 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001206}
1207
1208
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001209XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1210{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001211 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001212 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001213 }
1214 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1215 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001216}
1217
1218
1219bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1220{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001221 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001222 const XMLDeclaration* declaration = compare->ToDeclaration();
1223 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001224}
1225
1226
1227
Lee Thomason50f97b22012-02-11 16:33:40 -08001228bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1229{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001230 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001231 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001232}
1233
1234// --------- XMLUnknown ---------- //
1235
1236XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1237{
1238}
1239
1240
1241XMLUnknown::~XMLUnknown()
1242{
1243}
1244
1245
kezenator4f756162016-11-29 19:46:27 +10001246char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
Lee Thomason50f97b22012-02-11 16:33:40 -08001247{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001248 // Unknown parses as text.
1249 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001250
kezenator4f756162016-11-29 19:46:27 +10001251 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001252 if ( !p ) {
kezenatorec694152016-11-26 17:21:43 +10001253 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001254 }
1255 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001256}
1257
1258
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001259XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1260{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001261 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001262 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001263 }
1264 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1265 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001266}
1267
1268
1269bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1270{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001271 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001272 const XMLUnknown* unknown = compare->ToUnknown();
1273 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001274}
1275
1276
Lee Thomason50f97b22012-02-11 16:33:40 -08001277bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1278{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001279 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001280 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001281}
1282
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001283// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001284
1285const char* XMLAttribute::Name() const
1286{
1287 return _name.GetStr();
1288}
1289
1290const char* XMLAttribute::Value() const
1291{
1292 return _value.GetStr();
1293}
1294
kezenator4f756162016-11-29 19:46:27 +10001295char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001296{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001297 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001298 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001299 if ( !p || !*p ) {
1300 return 0;
1301 }
Lee Thomason22aead12012-01-23 13:29:35 -08001302
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001303 // Skip white space before =
kezenator4f756162016-11-29 19:46:27 +10001304 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001305 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001306 return 0;
1307 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001308
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001309 ++p; // move up to opening quote
kezenator4f756162016-11-29 19:46:27 +10001310 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001311 if ( *p != '\"' && *p != '\'' ) {
1312 return 0;
1313 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001314
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001315 char endTag[2] = { *p, 0 };
1316 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001317
kezenator4f756162016-11-29 19:46:27 +10001318 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001319 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001320}
1321
1322
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001323void XMLAttribute::SetName( const char* n )
1324{
Lee Thomason624d43f2012-10-12 10:58:48 -07001325 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001326}
1327
1328
Lee Thomason2fa81722012-11-09 12:37:46 -08001329XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001330{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001331 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001332 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001333 }
1334 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001335}
1336
1337
Lee Thomason2fa81722012-11-09 12:37:46 -08001338XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001339{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001340 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001341 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001342 }
1343 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001344}
1345
1346
Lee Thomason51c12712016-06-04 20:18:49 -07001347XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1348{
1349 if (XMLUtil::ToInt64(Value(), value)) {
1350 return XML_SUCCESS;
1351 }
1352 return XML_WRONG_ATTRIBUTE_TYPE;
1353}
1354
1355
Lee Thomason2fa81722012-11-09 12:37:46 -08001356XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001357{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001358 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001359 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001360 }
1361 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001362}
1363
1364
Lee Thomason2fa81722012-11-09 12:37:46 -08001365XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001366{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001367 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001368 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001369 }
1370 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001371}
1372
1373
Lee Thomason2fa81722012-11-09 12:37:46 -08001374XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001375{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001376 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001377 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001378 }
1379 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001380}
1381
1382
1383void XMLAttribute::SetAttribute( const char* v )
1384{
Lee Thomason624d43f2012-10-12 10:58:48 -07001385 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001386}
1387
1388
Lee Thomason1ff38e02012-02-14 18:18:16 -08001389void XMLAttribute::SetAttribute( int v )
1390{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001391 char buf[BUF_SIZE];
1392 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001393 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001394}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001395
1396
1397void XMLAttribute::SetAttribute( unsigned v )
1398{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001399 char buf[BUF_SIZE];
1400 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001401 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001402}
1403
1404
Lee Thomason51c12712016-06-04 20:18:49 -07001405void XMLAttribute::SetAttribute(int64_t v)
1406{
1407 char buf[BUF_SIZE];
1408 XMLUtil::ToStr(v, buf, BUF_SIZE);
1409 _value.SetStr(buf);
1410}
1411
1412
1413
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001414void XMLAttribute::SetAttribute( bool v )
1415{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001416 char buf[BUF_SIZE];
1417 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001418 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001419}
1420
1421void XMLAttribute::SetAttribute( double 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
1428void XMLAttribute::SetAttribute( float v )
1429{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001430 char buf[BUF_SIZE];
1431 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001432 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001433}
1434
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001435
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001436// --------- XMLElement ---------- //
1437XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001438 _closingType( 0 ),
1439 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001440{
1441}
1442
1443
1444XMLElement::~XMLElement()
1445{
Lee Thomason624d43f2012-10-12 10:58:48 -07001446 while( _rootAttribute ) {
1447 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001448 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001449 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001450 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001451}
1452
1453
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001454const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1455{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001456 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001457 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1458 return a;
1459 }
1460 }
1461 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001462}
1463
1464
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001465const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001466{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001467 const XMLAttribute* a = FindAttribute( name );
1468 if ( !a ) {
1469 return 0;
1470 }
1471 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1472 return a->Value();
1473 }
1474 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001475}
1476
Josh Wittnercf3dd092016-10-11 18:57:17 -07001477int XMLElement::IntAttribute(const char* name, int defaultValue) const
1478{
1479 int i = defaultValue;
1480 QueryIntAttribute(name, &i);
1481 return i;
1482}
1483
1484unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
1485{
1486 unsigned i = defaultValue;
1487 QueryUnsignedAttribute(name, &i);
1488 return i;
1489}
1490
1491int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
1492{
1493 int64_t i = defaultValue;
1494 QueryInt64Attribute(name, &i);
1495 return i;
1496}
1497
1498bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
1499{
1500 bool b = defaultValue;
1501 QueryBoolAttribute(name, &b);
1502 return b;
1503}
1504
1505double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
1506{
1507 double d = defaultValue;
1508 QueryDoubleAttribute(name, &d);
1509 return d;
1510}
1511
1512float XMLElement::FloatAttribute(const char* name, float defaultValue) const
1513{
1514 float f = defaultValue;
1515 QueryFloatAttribute(name, &f);
1516 return f;
1517}
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001518
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001519const char* XMLElement::GetText() const
1520{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001521 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001522 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001523 }
1524 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001525}
1526
1527
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001528void XMLElement::SetText( const char* inText )
1529{
Uli Kusterer869bb592014-01-21 01:36:16 +01001530 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001531 FirstChild()->SetValue( inText );
1532 else {
1533 XMLText* theText = GetDocument()->NewText( inText );
1534 InsertFirstChild( theText );
1535 }
1536}
1537
Lee Thomason5bb2d802014-01-24 10:42:57 -08001538
1539void XMLElement::SetText( int v )
1540{
1541 char buf[BUF_SIZE];
1542 XMLUtil::ToStr( v, buf, BUF_SIZE );
1543 SetText( buf );
1544}
1545
1546
1547void XMLElement::SetText( unsigned v )
1548{
1549 char buf[BUF_SIZE];
1550 XMLUtil::ToStr( v, buf, BUF_SIZE );
1551 SetText( buf );
1552}
1553
1554
Lee Thomason51c12712016-06-04 20:18:49 -07001555void XMLElement::SetText(int64_t v)
1556{
1557 char buf[BUF_SIZE];
1558 XMLUtil::ToStr(v, buf, BUF_SIZE);
1559 SetText(buf);
1560}
1561
1562
1563void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001564{
1565 char buf[BUF_SIZE];
1566 XMLUtil::ToStr( v, buf, BUF_SIZE );
1567 SetText( buf );
1568}
1569
1570
1571void XMLElement::SetText( float v )
1572{
1573 char buf[BUF_SIZE];
1574 XMLUtil::ToStr( v, buf, BUF_SIZE );
1575 SetText( buf );
1576}
1577
1578
1579void XMLElement::SetText( double v )
1580{
1581 char buf[BUF_SIZE];
1582 XMLUtil::ToStr( v, buf, BUF_SIZE );
1583 SetText( buf );
1584}
1585
1586
MortenMacFly4ee49f12013-01-14 20:03:14 +01001587XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001588{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001589 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001590 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001591 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001592 return XML_SUCCESS;
1593 }
1594 return XML_CAN_NOT_CONVERT_TEXT;
1595 }
1596 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001597}
1598
1599
MortenMacFly4ee49f12013-01-14 20:03:14 +01001600XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001601{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001602 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001603 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001604 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001605 return XML_SUCCESS;
1606 }
1607 return XML_CAN_NOT_CONVERT_TEXT;
1608 }
1609 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001610}
1611
1612
Lee Thomason51c12712016-06-04 20:18:49 -07001613XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1614{
1615 if (FirstChild() && FirstChild()->ToText()) {
1616 const char* t = FirstChild()->Value();
1617 if (XMLUtil::ToInt64(t, ival)) {
1618 return XML_SUCCESS;
1619 }
1620 return XML_CAN_NOT_CONVERT_TEXT;
1621 }
1622 return XML_NO_TEXT_NODE;
1623}
1624
1625
MortenMacFly4ee49f12013-01-14 20:03:14 +01001626XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001627{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001628 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001629 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001630 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001631 return XML_SUCCESS;
1632 }
1633 return XML_CAN_NOT_CONVERT_TEXT;
1634 }
1635 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001636}
1637
1638
MortenMacFly4ee49f12013-01-14 20:03:14 +01001639XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001640{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001641 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001642 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001643 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001644 return XML_SUCCESS;
1645 }
1646 return XML_CAN_NOT_CONVERT_TEXT;
1647 }
1648 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001649}
1650
1651
MortenMacFly4ee49f12013-01-14 20:03:14 +01001652XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001653{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001654 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001655 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001656 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001657 return XML_SUCCESS;
1658 }
1659 return XML_CAN_NOT_CONVERT_TEXT;
1660 }
1661 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001662}
1663
Josh Wittnercf3dd092016-10-11 18:57:17 -07001664int XMLElement::IntText(int defaultValue) const
1665{
1666 int i = defaultValue;
1667 QueryIntText(&i);
1668 return i;
1669}
1670
1671unsigned XMLElement::UnsignedText(unsigned defaultValue) const
1672{
1673 unsigned i = defaultValue;
1674 QueryUnsignedText(&i);
1675 return i;
1676}
1677
1678int64_t XMLElement::Int64Text(int64_t defaultValue) const
1679{
1680 int64_t i = defaultValue;
1681 QueryInt64Text(&i);
1682 return i;
1683}
1684
1685bool XMLElement::BoolText(bool defaultValue) const
1686{
1687 bool b = defaultValue;
1688 QueryBoolText(&b);
1689 return b;
1690}
1691
1692double XMLElement::DoubleText(double defaultValue) const
1693{
1694 double d = defaultValue;
1695 QueryDoubleText(&d);
1696 return d;
1697}
1698
1699float XMLElement::FloatText(float defaultValue) const
1700{
1701 float f = defaultValue;
1702 QueryFloatText(&f);
1703 return f;
1704}
Lee Thomason21be8822012-07-15 17:27:22 -07001705
1706
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001707XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1708{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001709 XMLAttribute* last = 0;
1710 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001711 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001712 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001713 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001714 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1715 break;
1716 }
1717 }
1718 if ( !attrib ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001719 attrib = CreateAttribute();
1720 TIXMLASSERT( attrib );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001721 if ( last ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001722 TIXMLASSERT( last->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001723 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001724 }
1725 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001726 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001727 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001728 }
1729 attrib->SetName( name );
1730 }
1731 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001732}
1733
1734
U-Stream\Leeae25a442012-02-17 17:48:16 -08001735void XMLElement::DeleteAttribute( const char* name )
1736{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001737 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001738 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001739 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1740 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001741 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001742 }
1743 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001744 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001745 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001746 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001747 break;
1748 }
1749 prev = a;
1750 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001751}
1752
1753
kezenator4f756162016-11-29 19:46:27 +10001754char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001755{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001756 const char* start = p;
1757 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001758
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001759 // Read the attributes.
1760 while( p ) {
kezenator4f756162016-11-29 19:46:27 +10001761 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001762 if ( !(*p) ) {
kezenatorec694152016-11-26 17:21:43 +10001763 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name(), _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001764 return 0;
1765 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001766
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001767 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001768 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mea60caa22016-11-22 18:28:08 +03001769 XMLAttribute* attrib = CreateAttribute();
1770 TIXMLASSERT( attrib );
kezenatorec694152016-11-26 17:21:43 +10001771 attrib->_parseLineNum = _document->_parseCurLineNum;
Lee Thomasond1983222012-02-06 08:41:24 -08001772
kezenatorec694152016-11-26 17:21:43 +10001773 int attrLineNum = attrib->_parseLineNum;
1774
kezenator4f756162016-11-29 19:46:27 +10001775 p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001776 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001777 DeleteAttribute( attrib );
kezenatorec694152016-11-26 17:21:43 +10001778 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p, attrLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001779 return 0;
1780 }
1781 // There is a minor bug here: if the attribute in the source xml
1782 // document is duplicated, it will not be detected and the
1783 // attribute will be doubly added. However, tracking the 'prevAttribute'
1784 // avoids re-scanning the attribute list. Preferring performance for
1785 // now, may reconsider in the future.
1786 if ( prevAttribute ) {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001787 TIXMLASSERT( prevAttribute->_next == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001788 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001789 }
1790 else {
Dmitry-Me34a3f8e2016-12-19 12:05:21 +03001791 TIXMLASSERT( _rootAttribute == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001792 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001793 }
1794 prevAttribute = attrib;
1795 }
1796 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001797 else if ( *p == '>' ) {
1798 ++p;
1799 break;
1800 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001801 // end of the tag
1802 else if ( *p == '/' && *(p+1) == '>' ) {
1803 _closingType = CLOSED;
1804 return p+2; // done; sealed element.
1805 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001806 else {
kezenatorec694152016-11-26 17:21:43 +10001807 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p, _parseLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001808 return 0;
1809 }
1810 }
1811 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001812}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001813
Dmitry-Mee3225b12014-09-03 11:03:11 +04001814void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1815{
1816 if ( attribute == 0 ) {
1817 return;
1818 }
1819 MemPool* pool = attribute->_memPool;
1820 attribute->~XMLAttribute();
1821 pool->Free( attribute );
1822}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001823
Dmitry-Mea60caa22016-11-22 18:28:08 +03001824XMLAttribute* XMLElement::CreateAttribute()
1825{
1826 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
1827 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1828 attrib->_memPool = &_document->_attributePool;
1829 attrib->_memPool->SetTracked();
1830 return attrib;
1831}
1832
Lee Thomason67d61312012-01-24 16:01:51 -08001833//
1834// <ele></ele>
1835// <ele>foo<b>bar</b></ele>
1836//
kezenator4f756162016-11-29 19:46:27 +10001837char* XMLElement::ParseDeep( char* p, StrPair* strPair, int* curLineNumPtr )
Lee Thomason67d61312012-01-24 16:01:51 -08001838{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001839 // Read the element name.
kezenator4f756162016-11-29 19:46:27 +10001840 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
Lee Thomason67d61312012-01-24 16:01:51 -08001841
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001842 // The closing element is the </element> form. It is
1843 // parsed just like a regular element then deleted from
1844 // the DOM.
1845 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001846 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001847 ++p;
1848 }
Lee Thomason67d61312012-01-24 16:01:51 -08001849
Lee Thomason624d43f2012-10-12 10:58:48 -07001850 p = _value.ParseName( p );
1851 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001852 return 0;
1853 }
Lee Thomason67d61312012-01-24 16:01:51 -08001854
kezenator4f756162016-11-29 19:46:27 +10001855 p = ParseAttributes( p, curLineNumPtr );
Lee Thomason624d43f2012-10-12 10:58:48 -07001856 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001857 return p;
1858 }
Lee Thomason67d61312012-01-24 16:01:51 -08001859
kezenator4f756162016-11-29 19:46:27 +10001860 p = XMLNode::ParseDeep( p, strPair, curLineNumPtr );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001861 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001862}
1863
1864
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001865
1866XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1867{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001868 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001869 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001870 }
1871 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1872 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1873 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1874 }
1875 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001876}
1877
1878
1879bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1880{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001881 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001882 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001883 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001884
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001885 const XMLAttribute* a=FirstAttribute();
1886 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001887
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001888 while ( a && b ) {
1889 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1890 return false;
1891 }
1892 a = a->Next();
1893 b = b->Next();
1894 }
1895 if ( a || b ) {
1896 // different count
1897 return false;
1898 }
1899 return true;
1900 }
1901 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001902}
1903
1904
Lee Thomason751da522012-02-10 08:50:51 -08001905bool XMLElement::Accept( XMLVisitor* visitor ) const
1906{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001907 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001908 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001909 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1910 if ( !node->Accept( visitor ) ) {
1911 break;
1912 }
1913 }
1914 }
1915 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001916}
Lee Thomason56bdd022012-02-09 18:16:58 -08001917
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001918
Lee Thomason3f57d272012-01-11 15:30:03 -08001919// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001920
1921// Warning: List must match 'enum XMLError'
1922const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1923 "XML_SUCCESS",
1924 "XML_NO_ATTRIBUTE",
1925 "XML_WRONG_ATTRIBUTE_TYPE",
1926 "XML_ERROR_FILE_NOT_FOUND",
1927 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1928 "XML_ERROR_FILE_READ_ERROR",
1929 "XML_ERROR_ELEMENT_MISMATCH",
1930 "XML_ERROR_PARSING_ELEMENT",
1931 "XML_ERROR_PARSING_ATTRIBUTE",
1932 "XML_ERROR_IDENTIFYING_TAG",
1933 "XML_ERROR_PARSING_TEXT",
1934 "XML_ERROR_PARSING_CDATA",
1935 "XML_ERROR_PARSING_COMMENT",
1936 "XML_ERROR_PARSING_DECLARATION",
1937 "XML_ERROR_PARSING_UNKNOWN",
1938 "XML_ERROR_EMPTY_DOCUMENT",
1939 "XML_ERROR_MISMATCHED_ELEMENT",
1940 "XML_ERROR_PARSING",
1941 "XML_CAN_NOT_CONVERT_TEXT",
1942 "XML_NO_TEXT_NODE"
1943};
1944
1945
Lee Thomason624d43f2012-10-12 10:58:48 -07001946XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001947 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001948 _writeBOM( false ),
1949 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07001950 _errorID(XML_SUCCESS),
Lee Thomason624d43f2012-10-12 10:58:48 -07001951 _whitespace( whitespace ),
Dmitry-Mef89bd3e2017-01-18 18:33:55 +03001952 _errorLineNum( 0 ),
1953 _charBuffer( 0 ),
1954 _parseCurLineNum( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001955{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03001956 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
1957 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08001958}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001959
1960
Lee Thomason3f57d272012-01-11 15:30:03 -08001961XMLDocument::~XMLDocument()
1962{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001963 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001964}
1965
1966
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001967void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001968{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001969 DeleteChildren();
1970
Dmitry-Meab37df82014-11-28 12:08:36 +03001971#ifdef DEBUG
1972 const bool hadError = Error();
1973#endif
Dmitry-Me0d2cef02016-11-25 18:39:52 +03001974 ClearError();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001975
Lee Thomason624d43f2012-10-12 10:58:48 -07001976 delete [] _charBuffer;
1977 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001978
1979#if 0
1980 _textPool.Trace( "text" );
1981 _elementPool.Trace( "element" );
1982 _commentPool.Trace( "comment" );
1983 _attributePool.Trace( "attribute" );
1984#endif
1985
1986#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001987 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001988 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1989 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1990 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1991 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1992 }
1993#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001994}
1995
Lee Thomason3f57d272012-01-11 15:30:03 -08001996
Lee Thomason2c85a712012-01-31 08:24:24 -08001997XMLElement* XMLDocument::NewElement( const char* name )
1998{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03001999 XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002000 ele->SetName( name );
2001 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08002002}
2003
2004
Lee Thomason1ff38e02012-02-14 18:18:16 -08002005XMLComment* XMLDocument::NewComment( const char* str )
2006{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002007 XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002008 comment->SetValue( str );
2009 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002010}
2011
2012
2013XMLText* XMLDocument::NewText( const char* str )
2014{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002015 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002016 text->SetValue( str );
2017 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002018}
2019
2020
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002021XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2022{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002023 XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002024 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2025 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002026}
2027
2028
2029XMLUnknown* XMLDocument::NewUnknown( const char* str )
2030{
Dmitry-Me2aebfb72017-02-27 15:53:40 +03002031 XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002032 unk->SetValue( str );
2033 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002034}
2035
Dmitry-Me01578db2014-08-19 10:18:48 +04002036static FILE* callfopen( const char* filepath, const char* mode )
2037{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002038 TIXMLASSERT( filepath );
2039 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002040#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2041 FILE* fp = 0;
2042 errno_t err = fopen_s( &fp, filepath, mode );
2043 if ( err ) {
2044 return 0;
2045 }
2046#else
2047 FILE* fp = fopen( filepath, mode );
2048#endif
2049 return fp;
2050}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08002051
2052void XMLDocument::DeleteNode( XMLNode* node ) {
2053 TIXMLASSERT( node );
2054 TIXMLASSERT(node->_document == this );
2055 if (node->_parent) {
2056 node->_parent->DeleteChild( node );
2057 }
2058 else {
2059 // Isn't in the tree.
2060 // Use the parent delete.
2061 // Also, we need to mark it tracked: we 'know'
2062 // it was never used.
2063 node->_memPool->SetTracked();
2064 // Call the static XMLNode version:
2065 XMLNode::DeleteNode(node);
2066 }
2067}
2068
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002069
Lee Thomason2fa81722012-11-09 12:37:46 -08002070XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002071{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002072 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04002073 FILE* fp = callfopen( filename, "rb" );
2074 if ( !fp ) {
kezenatorec694152016-11-26 17:21:43 +10002075 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002076 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002077 }
2078 LoadFile( fp );
2079 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002080 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002081}
2082
Dmitry-Me901fed52015-09-25 10:29:51 +03002083// This is likely overengineered template art to have a check that unsigned long value incremented
2084// by one still fits into size_t. If size_t type is larger than unsigned long type
2085// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
2086// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
2087// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
2088// types sizes relate to each other.
2089template
2090<bool = (sizeof(unsigned long) >= sizeof(size_t))>
2091struct LongFitsIntoSizeTMinusOne {
2092 static bool Fits( unsigned long value )
2093 {
2094 return value < (size_t)-1;
2095 }
2096};
2097
2098template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02002099struct LongFitsIntoSizeTMinusOne<false> {
2100 static bool Fits( unsigned long )
2101 {
2102 return true;
2103 }
2104};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002105
Lee Thomason2fa81722012-11-09 12:37:46 -08002106XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002107{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002108 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002109
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002110 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002111 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
kezenatorec694152016-11-26 17:21:43 +10002112 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002113 return _errorID;
2114 }
2115
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002116 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002117 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002118 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002119 if ( filelength == -1L ) {
kezenatorec694152016-11-26 17:21:43 +10002120 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002121 return _errorID;
2122 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002123 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002124
Dmitry-Me901fed52015-09-25 10:29:51 +03002125 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002126 // Cannot handle files which won't fit in buffer together with null terminator
kezenatorec694152016-11-26 17:21:43 +10002127 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002128 return _errorID;
2129 }
2130
Dmitry-Me72801b82015-05-07 09:41:39 +03002131 if ( filelength == 0 ) {
kezenatorec694152016-11-26 17:21:43 +10002132 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002133 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002134 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002135
Dmitry-Me72801b82015-05-07 09:41:39 +03002136 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002137 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002138 _charBuffer = new char[size+1];
2139 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002140 if ( read != size ) {
kezenatorec694152016-11-26 17:21:43 +10002141 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002142 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002143 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002144
Lee Thomason624d43f2012-10-12 10:58:48 -07002145 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002146
Dmitry-Me97476b72015-01-01 16:15:57 +03002147 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002148 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002149}
2150
2151
Lee Thomason2fa81722012-11-09 12:37:46 -08002152XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002153{
Dmitry-Me01578db2014-08-19 10:18:48 +04002154 FILE* fp = callfopen( filename, "w" );
2155 if ( !fp ) {
kezenatorec694152016-11-26 17:21:43 +10002156 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002157 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002158 }
2159 SaveFile(fp, compact);
2160 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002161 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002162}
2163
2164
Lee Thomason2fa81722012-11-09 12:37:46 -08002165XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002166{
Ant Mitchell189198f2015-03-24 16:20:36 +00002167 // Clear any error from the last save, otherwise it will get reported
2168 // for *this* call.
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002169 ClearError();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002170 XMLPrinter stream( fp, compact );
2171 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002172 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002173}
2174
Lee Thomason1ff38e02012-02-14 18:18:16 -08002175
Lee Thomason2fa81722012-11-09 12:37:46 -08002176XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002177{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002178 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002179
Lee Thomason82d32002014-02-21 22:47:18 -08002180 if ( len == 0 || !p || !*p ) {
kezenatorec694152016-11-26 17:21:43 +10002181 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002182 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002183 }
2184 if ( len == (size_t)(-1) ) {
2185 len = strlen( p );
2186 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002187 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002188 _charBuffer = new char[ len+1 ];
2189 memcpy( _charBuffer, p, len );
2190 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002191
Dmitry-Me97476b72015-01-01 16:15:57 +03002192 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002193 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002194 // clean up now essentially dangling memory.
2195 // and the parse fail can put objects in the
2196 // pools that are dead and inaccessible.
2197 DeleteChildren();
2198 _elementPool.Clear();
2199 _attributePool.Clear();
2200 _textPool.Clear();
2201 _commentPool.Clear();
2202 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002203 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002204}
2205
2206
PKEuS1c5f99e2013-07-06 11:28:39 +02002207void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002208{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002209 if ( streamer ) {
2210 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002211 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002212 else {
2213 XMLPrinter stdoutStreamer( stdout );
2214 Accept( &stdoutStreamer );
2215 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002216}
2217
2218
kezenatorec694152016-11-26 17:21:43 +10002219void XMLDocument::SetError( XMLError error, const char* str1, const char* str2, int lineNum )
Lee Thomason67d61312012-01-24 16:01:51 -08002220{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002221 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002222 _errorID = error;
Lee Thomason584af572016-09-05 14:14:16 -07002223
2224 _errorStr1.Reset();
2225 _errorStr2.Reset();
kezenatorec694152016-11-26 17:21:43 +10002226 _errorLineNum = lineNum;
Lee Thomason584af572016-09-05 14:14:16 -07002227
2228 if (str1)
2229 _errorStr1.SetStr(str1);
2230 if (str2)
2231 _errorStr2.SetStr(str2);
Lee Thomason67d61312012-01-24 16:01:51 -08002232}
2233
Lee Thomasone90e9012016-12-24 07:34:39 -08002234/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
Lee Thomason331596e2014-09-11 14:56:43 -07002235{
kezenator5a700712016-11-26 13:54:42 +10002236 TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2237 const char* errorName = _errorNames[errorID];
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002238 TIXMLASSERT( errorName && errorName[0] );
2239 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002240}
Lee Thomason5cae8972012-01-24 18:03:07 -08002241
kezenator5a700712016-11-26 13:54:42 +10002242const char* XMLDocument::ErrorName() const
2243{
Lee Thomasone90e9012016-12-24 07:34:39 -08002244 return ErrorIDToName(_errorID);
kezenator5a700712016-11-26 13:54:42 +10002245}
2246
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002247void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002248{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002249 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002250 static const int LEN = 20;
2251 char buf1[LEN] = { 0 };
2252 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002253
Lee Thomason584af572016-09-05 14:14:16 -07002254 if ( !_errorStr1.Empty() ) {
2255 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002256 }
Lee Thomason584af572016-09-05 14:14:16 -07002257 if ( !_errorStr2.Empty() ) {
2258 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002259 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002260
Dmitry-Me2ad43202015-04-16 12:18:58 +03002261 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2262 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2263 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
kezenatorec694152016-11-26 17:21:43 +10002264 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s line=%d\n",
2265 static_cast<int>( _errorID ), ErrorName(), buf1, buf2, _errorLineNum );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002266 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002267}
2268
Dmitry-Me97476b72015-01-01 16:15:57 +03002269void XMLDocument::Parse()
2270{
2271 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2272 TIXMLASSERT( _charBuffer );
kezenatorec694152016-11-26 17:21:43 +10002273 _parseCurLineNum = 1;
2274 _parseLineNum = 1;
Lee Thomason3cebdc42015-01-05 17:16:28 -08002275 char* p = _charBuffer;
kezenator4f756162016-11-29 19:46:27 +10002276 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
Dmitry-Mee28be752015-01-09 14:59:30 +03002277 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002278 if ( !*p ) {
kezenatorec694152016-11-26 17:21:43 +10002279 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002280 return;
2281 }
kezenator4f756162016-11-29 19:46:27 +10002282 ParseDeep(p, 0, &_parseCurLineNum );
Dmitry-Me97476b72015-01-01 16:15:57 +03002283}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002284
PKEuS1bfb9542013-08-04 13:51:17 +02002285XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002286 _elementJustOpened( false ),
2287 _firstElement( true ),
2288 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002289 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002290 _textDepth( -1 ),
2291 _processEntities( true ),
2292 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002293{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002294 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002295 _entityFlag[i] = false;
2296 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002297 }
2298 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002299 const char entityValue = entities[i].value;
Dmitry-Mec5f1e7c2016-10-14 10:33:02 +03002300 TIXMLASSERT( ((unsigned char)entityValue) < ENTITY_RANGE );
Dmitry-Me8b67d742014-12-22 11:35:12 +03002301 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002302 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002303 _restrictedEntityFlag[(unsigned char)'&'] = true;
2304 _restrictedEntityFlag[(unsigned char)'<'] = true;
2305 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002306 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002307}
2308
2309
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002310void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002311{
2312 va_list va;
2313 va_start( va, format );
2314
Lee Thomason624d43f2012-10-12 10:58:48 -07002315 if ( _fp ) {
2316 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002317 }
2318 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002319 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002320 // Close out and re-start the va-args
2321 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002322 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002323 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002324 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002325 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002326 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002327 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002328 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002329}
2330
2331
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002332void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002333{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002334 for( int i=0; i<depth; ++i ) {
2335 Print( " " );
2336 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002337}
2338
2339
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002340void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002341{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002342 // Look for runs of bytes between entities to print.
2343 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002344
Lee Thomason624d43f2012-10-12 10:58:48 -07002345 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002346 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002347 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002348 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002349 // Remember, char is sometimes signed. (How many times has that bitten me?)
2350 if ( *q > 0 && *q < ENTITY_RANGE ) {
2351 // Check for entities. If one is found, flush
2352 // the stream up until the entity, write the
2353 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002354 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002355 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002356 const size_t delta = q - p;
2357 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002358 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002359 Print( "%.*s", toPrint, p );
2360 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002361 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002362 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002363 for( int i=0; i<NUM_ENTITIES; ++i ) {
2364 if ( entities[i].value == *q ) {
2365 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002366 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002367 break;
2368 }
2369 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002370 if ( !entityPatternPrinted ) {
2371 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2372 TIXMLASSERT( false );
2373 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002374 ++p;
2375 }
2376 }
2377 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002378 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002379 }
2380 }
2381 // Flush the remaining string. This will be the entire
2382 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002383 TIXMLASSERT( p <= q );
2384 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002385 Print( "%s", p );
2386 }
Lee Thomason857b8682012-01-25 17:50:25 -08002387}
2388
U-Stream\Leeae25a442012-02-17 17:48:16 -08002389
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002390void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002391{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002392 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002393 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 -07002394 Print( "%s", bom );
2395 }
2396 if ( writeDec ) {
2397 PushDeclaration( "xml version=\"1.0\"" );
2398 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002399}
2400
2401
Uli Kusterer593a33d2014-02-01 12:48:51 +01002402void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002403{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002404 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002405 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002406
Uli Kusterer593a33d2014-02-01 12:48:51 +01002407 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002408 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002409 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002410 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002411 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002412 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002413
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002414 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002415 _elementJustOpened = true;
2416 _firstElement = false;
2417 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002418}
2419
2420
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002421void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002422{
Lee Thomason624d43f2012-10-12 10:58:48 -07002423 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002424 Print( " %s=\"", name );
2425 PrintString( value, false );
2426 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002427}
2428
2429
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002430void XMLPrinter::PushAttribute( const char* name, int v )
2431{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002432 char buf[BUF_SIZE];
2433 XMLUtil::ToStr( v, buf, BUF_SIZE );
2434 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002435}
2436
2437
2438void XMLPrinter::PushAttribute( const char* name, unsigned v )
2439{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002440 char buf[BUF_SIZE];
2441 XMLUtil::ToStr( v, buf, BUF_SIZE );
2442 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002443}
2444
2445
Lee Thomason51c12712016-06-04 20:18:49 -07002446void XMLPrinter::PushAttribute(const char* name, int64_t v)
2447{
2448 char buf[BUF_SIZE];
2449 XMLUtil::ToStr(v, buf, BUF_SIZE);
2450 PushAttribute(name, buf);
2451}
2452
2453
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002454void XMLPrinter::PushAttribute( const char* name, bool v )
2455{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002456 char buf[BUF_SIZE];
2457 XMLUtil::ToStr( v, buf, BUF_SIZE );
2458 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002459}
2460
2461
2462void XMLPrinter::PushAttribute( const char* name, double v )
2463{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002464 char buf[BUF_SIZE];
2465 XMLUtil::ToStr( v, buf, BUF_SIZE );
2466 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002467}
2468
2469
Uli Kustererca412e82014-02-01 13:35:05 +01002470void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002471{
Lee Thomason624d43f2012-10-12 10:58:48 -07002472 --_depth;
2473 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002474
Lee Thomason624d43f2012-10-12 10:58:48 -07002475 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002476 Print( "/>" );
2477 }
2478 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002479 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002480 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002481 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002482 }
2483 Print( "</%s>", name );
2484 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002485
Lee Thomason624d43f2012-10-12 10:58:48 -07002486 if ( _textDepth == _depth ) {
2487 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002488 }
Uli Kustererca412e82014-02-01 13:35:05 +01002489 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002490 Print( "\n" );
2491 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002492 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002493}
2494
2495
Dmitry-Mea092bc12014-12-23 17:57:05 +03002496void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002497{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002498 if ( !_elementJustOpened ) {
2499 return;
2500 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002501 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002502 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002503}
2504
2505
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002506void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002507{
Lee Thomason624d43f2012-10-12 10:58:48 -07002508 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002509
Dmitry-Mea092bc12014-12-23 17:57:05 +03002510 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002511 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002512 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002513 }
2514 else {
2515 PrintString( text, true );
2516 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002517}
2518
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002519void XMLPrinter::PushText( int64_t value )
2520{
2521 char buf[BUF_SIZE];
2522 XMLUtil::ToStr( value, buf, BUF_SIZE );
2523 PushText( buf, false );
2524}
2525
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002526void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002527{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002528 char buf[BUF_SIZE];
2529 XMLUtil::ToStr( value, buf, BUF_SIZE );
2530 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002531}
2532
2533
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002534void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002535{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002536 char buf[BUF_SIZE];
2537 XMLUtil::ToStr( value, buf, BUF_SIZE );
2538 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002539}
2540
2541
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002542void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002543{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002544 char buf[BUF_SIZE];
2545 XMLUtil::ToStr( value, buf, BUF_SIZE );
2546 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002547}
2548
2549
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002550void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002551{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002552 char buf[BUF_SIZE];
2553 XMLUtil::ToStr( value, buf, BUF_SIZE );
2554 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002555}
2556
2557
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002558void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002559{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002560 char buf[BUF_SIZE];
2561 XMLUtil::ToStr( value, buf, BUF_SIZE );
2562 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002563}
2564
Lee Thomason5cae8972012-01-24 18:03:07 -08002565
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002566void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002567{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002568 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002569 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002570 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002571 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002572 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002573 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002574 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002575}
Lee Thomason751da522012-02-10 08:50:51 -08002576
2577
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002578void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002579{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002580 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002581 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002582 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002583 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002584 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002585 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002586 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002587}
2588
2589
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002590void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002591{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002592 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002593 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002594 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002595 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002596 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002597 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002598 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002599}
2600
2601
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002602bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002603{
Lee Thomason624d43f2012-10-12 10:58:48 -07002604 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002605 if ( doc.HasBOM() ) {
2606 PushHeader( true, false );
2607 }
2608 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002609}
2610
2611
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002612bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002613{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002614 const XMLElement* parentElem = 0;
2615 if ( element.Parent() ) {
2616 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002617 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002618 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002619 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002620 while ( attribute ) {
2621 PushAttribute( attribute->Name(), attribute->Value() );
2622 attribute = attribute->Next();
2623 }
2624 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002625}
2626
2627
Uli Kustererca412e82014-02-01 13:35:05 +01002628bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002629{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002630 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002631 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002632}
2633
2634
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002635bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002636{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002637 PushText( text.Value(), text.CData() );
2638 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002639}
2640
2641
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002642bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002643{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002644 PushComment( comment.Value() );
2645 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002646}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002647
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002648bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002649{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002650 PushDeclaration( declaration.Value() );
2651 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002652}
2653
2654
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002655bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002656{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002657 PushUnknown( unknown.Value() );
2658 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002659}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002660
Lee Thomason685b8952012-11-12 13:00:06 -08002661} // namespace tinyxml2
2662