blob: 9d74681a423fbc3f260418d34f26b9f8576b44c4 [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
192char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
193{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700194 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800195
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400196 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700197 char endChar = *endTag;
198 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800199
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700200 // Inner loop of text parsing.
201 while ( *p ) {
202 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
203 Set( start, p, strFlags );
204 return p + length;
205 }
206 ++p;
207 }
208 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800209}
210
211
212char* StrPair::ParseName( char* p )
213{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400214 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700215 return 0;
216 }
JayXonee525db2014-12-24 04:01:42 -0500217 if ( !XMLUtil::IsNameStartChar( *p ) ) {
218 return 0;
219 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800220
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400221 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500222 ++p;
223 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700224 ++p;
225 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800226
JayXonee525db2014-12-24 04:01:42 -0500227 Set( start, p, 0 );
228 return p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800229}
230
231
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700232void StrPair::CollapseWhitespace()
233{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400234 // Adjusting _start would cause undefined behavior on delete[]
235 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700236 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700237 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700238
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300239 if ( *_start ) {
Dmitry-Me24495822016-09-02 16:53:32 +0300240 const char* p = _start; // the read pointer
Lee Thomason120b3a62012-10-12 10:06:59 -0700241 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700242
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700243 while( *p ) {
244 if ( XMLUtil::IsWhiteSpace( *p )) {
245 p = XMLUtil::SkipWhiteSpace( p );
246 if ( *p == 0 ) {
247 break; // don't write to q; this trims the trailing space.
248 }
249 *q = ' ';
250 ++q;
251 }
252 *q = *p;
253 ++q;
254 ++p;
255 }
256 *q = 0;
257 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700258}
259
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800260
Lee Thomasone4422302012-01-20 17:59:50 -0800261const char* StrPair::GetStr()
262{
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300263 TIXMLASSERT( _start );
264 TIXMLASSERT( _end );
Lee Thomason120b3a62012-10-12 10:06:59 -0700265 if ( _flags & NEEDS_FLUSH ) {
266 *_end = 0;
267 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800268
Lee Thomason120b3a62012-10-12 10:06:59 -0700269 if ( _flags ) {
Dmitry-Me24495822016-09-02 16:53:32 +0300270 const char* p = _start; // the read pointer
Lee Thomason120b3a62012-10-12 10:06:59 -0700271 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800272
Lee Thomason120b3a62012-10-12 10:06:59 -0700273 while( p < _end ) {
274 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700275 // CR-LF pair becomes LF
276 // CR alone becomes LF
277 // LF-CR becomes LF
278 if ( *(p+1) == LF ) {
279 p += 2;
280 }
281 else {
282 ++p;
283 }
Dmitry-Mefed51122016-09-06 18:08:55 +0300284 *q = LF;
285 ++q;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700286 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700287 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700288 if ( *(p+1) == CR ) {
289 p += 2;
290 }
291 else {
292 ++p;
293 }
Dmitry-Mefed51122016-09-06 18:08:55 +0300294 *q = LF;
295 ++q;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700296 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700297 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700298 // Entities handled by tinyXML2:
299 // - special entities in the entity table [in/out]
300 // - numeric character reference [in]
301 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800302
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700303 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400304 const int buflen = 10;
305 char buf[buflen] = { 0 };
306 int len = 0;
Dmitry-Me6f51c802015-03-14 13:25:03 +0300307 char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
308 if ( adjusted == 0 ) {
309 *q = *p;
310 ++p;
311 ++q;
312 }
313 else {
314 TIXMLASSERT( 0 <= len && len <= buflen );
315 TIXMLASSERT( q + len <= adjusted );
316 p = adjusted;
317 memcpy( q, buf, len );
318 q += len;
319 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700320 }
321 else {
Dmitry-Me764545e2015-05-20 10:29:24 +0300322 bool entityFound = false;
323 for( int i = 0; i < NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400324 const Entity& entity = entities[i];
325 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
326 && *( p + entity.length + 1 ) == ';' ) {
327 // Found an entity - convert.
328 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700329 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400330 p += entity.length + 2;
Dmitry-Me764545e2015-05-20 10:29:24 +0300331 entityFound = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700332 break;
333 }
334 }
Dmitry-Me764545e2015-05-20 10:29:24 +0300335 if ( !entityFound ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700336 // fixme: treat as error?
337 ++p;
338 ++q;
339 }
340 }
341 }
342 else {
343 *q = *p;
344 ++p;
345 ++q;
346 }
347 }
348 *q = 0;
349 }
350 // The loop below has plenty going on, and this
351 // is a less useful mode. Break it out.
Dmitry-Me5420e542015-05-20 10:51:26 +0300352 if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700353 CollapseWhitespace();
354 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700355 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700356 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300357 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700358 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800359}
360
Lee Thomason2c85a712012-01-31 08:24:24 -0800361
Lee Thomasone4422302012-01-20 17:59:50 -0800362
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800363
Lee Thomason56bdd022012-02-09 18:16:58 -0800364// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800365
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800366const char* XMLUtil::ReadBOM( const char* p, bool* bom )
367{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300368 TIXMLASSERT( p );
369 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700370 *bom = false;
371 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
372 // Check for BOM:
373 if ( *(pu+0) == TIXML_UTF_LEAD_0
374 && *(pu+1) == TIXML_UTF_LEAD_1
375 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
376 *bom = true;
377 p += 3;
378 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300379 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700380 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800381}
382
383
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800384void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
385{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700386 const unsigned long BYTE_MASK = 0xBF;
387 const unsigned long BYTE_MARK = 0x80;
388 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800389
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700390 if (input < 0x80) {
391 *length = 1;
392 }
393 else if ( input < 0x800 ) {
394 *length = 2;
395 }
396 else if ( input < 0x10000 ) {
397 *length = 3;
398 }
399 else if ( input < 0x200000 ) {
400 *length = 4;
401 }
402 else {
Dmitry-Me2f465c42015-03-16 11:08:23 +0300403 *length = 0; // This code won't convert this correctly anyway.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700404 return;
405 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800406
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700407 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800408
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700409 // Scary scary fall throughs.
410 switch (*length) {
411 case 4:
412 --output;
413 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
414 input >>= 6;
415 case 3:
416 --output;
417 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
418 input >>= 6;
419 case 2:
420 --output;
421 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
422 input >>= 6;
423 case 1:
424 --output;
425 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100426 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300427 default:
428 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700429 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800430}
431
432
433const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
434{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700435 // Presume an entity, and pull it out.
436 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800437
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700438 if ( *(p+1) == '#' && *(p+2) ) {
439 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300440 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700441 ptrdiff_t delta = 0;
442 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800443 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800444
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700445 if ( *(p+2) == 'x' ) {
446 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300447 const char* q = p+3;
448 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700449 return 0;
450 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800451
Lee Thomason7e67bc82015-01-12 14:05:12 -0800452 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800453
Dmitry-Me9f56e122015-01-12 10:07:54 +0300454 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700455 return 0;
456 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800457 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800458
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700459 delta = q-p;
460 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800461
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700462 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700463 unsigned int digit = 0;
464
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700465 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300466 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700467 }
468 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300469 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700470 }
471 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300472 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700473 }
474 else {
475 return 0;
476 }
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100477 TIXMLASSERT( digit < 16 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300478 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
479 const unsigned int digitScaled = mult * digit;
480 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
481 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300482 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700483 mult *= 16;
484 --q;
485 }
486 }
487 else {
488 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300489 const char* q = p+2;
490 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700491 return 0;
492 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800493
Lee Thomason7e67bc82015-01-12 14:05:12 -0800494 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800495
Dmitry-Me9f56e122015-01-12 10:07:54 +0300496 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700497 return 0;
498 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800499 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800500
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700501 delta = q-p;
502 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800503
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700504 while ( *q != '#' ) {
505 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300506 const unsigned int digit = *q - '0';
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100507 TIXMLASSERT( digit < 10 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300508 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
509 const unsigned int digitScaled = mult * digit;
510 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
511 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700512 }
513 else {
514 return 0;
515 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300516 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700517 mult *= 10;
518 --q;
519 }
520 }
521 // convert the UCS to UTF-8
522 ConvertUTF32ToUTF8( ucs, value, length );
523 return p + delta + 1;
524 }
525 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800526}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800527
528
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700529void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700530{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700531 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700532}
533
534
535void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
536{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700537 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700538}
539
540
541void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
542{
Doruk Turakde45d042016-08-28 20:47:08 +0200543 TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? "true" : "false" );
Lee Thomason21be8822012-07-15 17:27:22 -0700544}
545
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800546/*
547 ToStr() of a number is a very tricky topic.
548 https://github.com/leethomason/tinyxml2/issues/106
549*/
Lee Thomason21be8822012-07-15 17:27:22 -0700550void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
551{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800552 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700553}
554
555
556void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
557{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800558 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700559}
560
561
Lee Thomason51c12712016-06-04 20:18:49 -0700562void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize)
563{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700564 // horrible syntax trick to make the compiler happy about %lld
565 TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v);
Lee Thomason51c12712016-06-04 20:18:49 -0700566}
567
568
Lee Thomason21be8822012-07-15 17:27:22 -0700569bool XMLUtil::ToInt( const char* str, int* value )
570{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700571 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
572 return true;
573 }
574 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700575}
576
577bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
578{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700579 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
580 return true;
581 }
582 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700583}
584
585bool XMLUtil::ToBool( const char* str, bool* value )
586{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700587 int ival = 0;
588 if ( ToInt( str, &ival )) {
589 *value = (ival==0) ? false : true;
590 return true;
591 }
592 if ( StringEqual( str, "true" ) ) {
593 *value = true;
594 return true;
595 }
596 else if ( StringEqual( str, "false" ) ) {
597 *value = false;
598 return true;
599 }
600 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700601}
602
603
604bool XMLUtil::ToFloat( const char* str, float* value )
605{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700606 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
607 return true;
608 }
609 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700610}
611
Lee Thomason51c12712016-06-04 20:18:49 -0700612
Lee Thomason21be8822012-07-15 17:27:22 -0700613bool XMLUtil::ToDouble( const char* str, double* value )
614{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700615 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
616 return true;
617 }
618 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700619}
620
621
Lee Thomason51c12712016-06-04 20:18:49 -0700622bool XMLUtil::ToInt64(const char* str, int64_t* value)
623{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700624 long long v = 0; // horrible syntax trick to make the compiler happy about %lld
625 if (TIXML_SSCANF(str, "%lld", &v) == 1) {
626 *value = (int64_t)v;
Lee Thomason51c12712016-06-04 20:18:49 -0700627 return true;
628 }
629 return false;
630}
631
632
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700633char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800634{
Dmitry-Me02384662015-03-03 16:02:13 +0300635 TIXMLASSERT( node );
636 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400637 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700638 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300639 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300640 *node = 0;
641 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700642 return p;
643 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800644
Dmitry-Me962083b2015-05-26 11:38:30 +0300645 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700646 static const char* xmlHeader = { "<?" };
647 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700648 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300649 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700650 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800651
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700652 static const int xmlHeaderLen = 2;
653 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700654 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300655 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700656 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800657
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700658 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
659 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400660 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700661 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300662 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700663 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
664 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700665 p += xmlHeaderLen;
666 }
667 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300668 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700669 returnNode = new (_commentPool.Alloc()) XMLComment( this );
670 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700671 p += commentHeaderLen;
672 }
673 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300674 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700675 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700676 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700677 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700678 p += cdataHeaderLen;
679 text->SetCData( true );
680 }
681 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300682 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700683 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
684 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700685 p += dtdHeaderLen;
686 }
687 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300688 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700689 returnNode = new (_elementPool.Alloc()) XMLElement( this );
690 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700691 p += elementHeaderLen;
692 }
693 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300694 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700695 returnNode = new (_textPool.Alloc()) XMLText( this );
696 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700697 p = start; // Back it up, all the text counts.
698 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800699
Dmitry-Me02384662015-03-03 16:02:13 +0300700 TIXMLASSERT( returnNode );
701 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700702 *node = returnNode;
703 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800704}
705
706
Lee Thomason751da522012-02-10 08:50:51 -0800707bool XMLDocument::Accept( XMLVisitor* visitor ) const
708{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300709 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700710 if ( visitor->VisitEnter( *this ) ) {
711 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
712 if ( !node->Accept( visitor ) ) {
713 break;
714 }
715 }
716 }
717 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800718}
Lee Thomason56bdd022012-02-09 18:16:58 -0800719
720
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800721// --------- XMLNode ----------- //
722
723XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700724 _document( doc ),
725 _parent( 0 ),
726 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200727 _prev( 0 ), _next( 0 ),
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700728 _userData( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200729 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800730{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800731}
732
733
734XMLNode::~XMLNode()
735{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700736 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700737 if ( _parent ) {
738 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700739 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800740}
741
Michael Daumling21626882013-10-22 17:03:37 +0200742const char* XMLNode::Value() const
743{
Dmitry-Mecaa72a62016-08-10 17:34:34 +0300744 // Edge case: XMLDocuments don't have a Value. Return null.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530745 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530746 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200747 return _value.GetStr();
748}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800749
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800750void XMLNode::SetValue( const char* str, bool staticMem )
751{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700752 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700753 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700754 }
755 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700756 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700757 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800758}
759
760
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800761void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800762{
Lee Thomason624d43f2012-10-12 10:58:48 -0700763 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300764 TIXMLASSERT( _lastChild );
Dmitry-Me9cb4eca2016-08-18 18:10:59 +0300765 DeleteChild( _firstChild );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700766 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700767 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800768}
769
770
771void XMLNode::Unlink( XMLNode* child )
772{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300773 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300774 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300775 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700776 if ( child == _firstChild ) {
777 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700778 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700779 if ( child == _lastChild ) {
780 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700781 }
Lee Thomasond923c672012-01-23 08:44:25 -0800782
Lee Thomason624d43f2012-10-12 10:58:48 -0700783 if ( child->_prev ) {
784 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700785 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700786 if ( child->_next ) {
787 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700788 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700789 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800790}
791
792
U-Stream\Leeae25a442012-02-17 17:48:16 -0800793void XMLNode::DeleteChild( XMLNode* node )
794{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300795 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300796 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700797 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100798 Unlink( node );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400799 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800800}
801
802
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800803XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
804{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300805 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300806 if ( addThis->_document != _document ) {
807 TIXMLASSERT( false );
808 return 0;
809 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800810 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700811
Lee Thomason624d43f2012-10-12 10:58:48 -0700812 if ( _lastChild ) {
813 TIXMLASSERT( _firstChild );
814 TIXMLASSERT( _lastChild->_next == 0 );
815 _lastChild->_next = addThis;
816 addThis->_prev = _lastChild;
817 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800818
Lee Thomason624d43f2012-10-12 10:58:48 -0700819 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700820 }
821 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700822 TIXMLASSERT( _firstChild == 0 );
823 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800824
Lee Thomason624d43f2012-10-12 10:58:48 -0700825 addThis->_prev = 0;
826 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700827 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700828 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700829 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800830}
831
832
Lee Thomason1ff38e02012-02-14 18:18:16 -0800833XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
834{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300835 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300836 if ( addThis->_document != _document ) {
837 TIXMLASSERT( false );
838 return 0;
839 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800840 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700841
Lee Thomason624d43f2012-10-12 10:58:48 -0700842 if ( _firstChild ) {
843 TIXMLASSERT( _lastChild );
844 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800845
Lee Thomason624d43f2012-10-12 10:58:48 -0700846 _firstChild->_prev = addThis;
847 addThis->_next = _firstChild;
848 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800849
Lee Thomason624d43f2012-10-12 10:58:48 -0700850 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700851 }
852 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700853 TIXMLASSERT( _lastChild == 0 );
854 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800855
Lee Thomason624d43f2012-10-12 10:58:48 -0700856 addThis->_prev = 0;
857 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700858 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700859 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400860 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800861}
862
863
864XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
865{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300866 TIXMLASSERT( addThis );
867 if ( addThis->_document != _document ) {
868 TIXMLASSERT( false );
869 return 0;
870 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700871
Dmitry-Meabb2d042014-12-09 12:59:31 +0300872 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700873
Lee Thomason624d43f2012-10-12 10:58:48 -0700874 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300875 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700876 return 0;
877 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800878
Lee Thomason624d43f2012-10-12 10:58:48 -0700879 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700880 // The last node or the only node.
881 return InsertEndChild( addThis );
882 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800883 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700884 addThis->_prev = afterThis;
885 addThis->_next = afterThis->_next;
886 afterThis->_next->_prev = addThis;
887 afterThis->_next = addThis;
888 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700889 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800890}
891
892
893
894
Dmitry-Me886ad972015-07-22 11:00:51 +0300895const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800896{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300897 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
898 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700899 if ( element ) {
Dmitry-Me886ad972015-07-22 11:00:51 +0300900 if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700901 return element;
902 }
903 }
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 ) {
912 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700913 if ( element ) {
Dmitry-Me886ad972015-07-22 11:00:51 +0300914 if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700915 return element;
916 }
917 }
918 }
919 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800920}
921
922
Dmitry-Me886ad972015-07-22 11:00:51 +0300923const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800924{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300925 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400926 const XMLElement* element = node->ToElement();
927 if ( element
Dmitry-Me886ad972015-07-22 11:00:51 +0300928 && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400929 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700930 }
931 }
932 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800933}
934
935
Dmitry-Me886ad972015-07-22 11:00:51 +0300936const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800937{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300938 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400939 const XMLElement* element = node->ToElement();
940 if ( element
Dmitry-Me886ad972015-07-22 11:00:51 +0300941 && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400942 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700943 }
944 }
945 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800946}
947
948
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800949char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800950{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700951 // This is a recursive method, but thinking about it "at the current level"
952 // it is a pretty simple flat list:
953 // <foo/>
954 // <!-- comment -->
955 //
956 // With a special case:
957 // <foo>
958 // </foo>
959 // <!-- comment -->
960 //
961 // Where the closing element (/foo) *must* be the next thing after the opening
962 // element, and the names must match. BUT the tricky bit is that the closing
963 // element will be read by the child.
964 //
965 // 'endTag' is the end tag for this node, it is returned by a call to a child.
966 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800967
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700968 while( p && *p ) {
969 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800970
Lee Thomason624d43f2012-10-12 10:58:48 -0700971 p = _document->Identify( p, &node );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300972 if ( node == 0 ) {
973 break;
974 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800975
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700976 StrPair endTag;
977 p = node->ParseDeep( p, &endTag );
978 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400979 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700980 if ( !_document->Error() ) {
981 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700982 }
983 break;
984 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800985
Sarat Addepalli3df007e2015-05-20 10:43:51 +0530986 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530987 if ( decl ) {
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530988 // A declaration can only be the first child of a document.
989 // Set error, if document already has children.
990 if ( !_document->NoChildren() ) {
991 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0);
Dmitry-Me4de7abb2016-08-10 17:30:02 +0300992 DeleteNode( node );
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530993 break;
994 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530995 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530996
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400997 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700998 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -0500999 // We read the end tag. Return it to the parent.
1000 if ( ele->ClosingType() == XMLElement::CLOSING ) {
1001 if ( parentEnd ) {
1002 ele->_value.TransferTo( parentEnd );
1003 }
1004 node->_memPool->SetTracked(); // created and then immediately deleted.
1005 DeleteNode( node );
1006 return p;
1007 }
1008
1009 // Handle an end tag returned to this level.
1010 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001011 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001012 if ( endTag.Empty() ) {
1013 if ( ele->ClosingType() == XMLElement::OPEN ) {
1014 mismatch = true;
1015 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001016 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001017 else {
1018 if ( ele->ClosingType() != XMLElement::OPEN ) {
1019 mismatch = true;
1020 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001021 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001022 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001023 }
1024 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001025 if ( mismatch ) {
Dmitry-Me886ad972015-07-22 11:00:51 +03001026 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -05001027 DeleteNode( node );
1028 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001029 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001030 }
JayXondbfdd8f2014-12-12 20:07:14 -05001031 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001032 }
1033 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001034}
1035
Dmitry-Mee3225b12014-09-03 11:03:11 +04001036void XMLNode::DeleteNode( XMLNode* node )
1037{
1038 if ( node == 0 ) {
1039 return;
1040 }
1041 MemPool* pool = node->_memPool;
1042 node->~XMLNode();
1043 pool->Free( node );
1044}
1045
Lee Thomason3cebdc42015-01-05 17:16:28 -08001046void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001047{
1048 TIXMLASSERT( insertThis );
1049 TIXMLASSERT( insertThis->_document == _document );
1050
1051 if ( insertThis->_parent )
1052 insertThis->_parent->Unlink( insertThis );
1053 else
1054 insertThis->_memPool->SetTracked();
1055}
1056
Lee Thomason5492a1c2012-01-23 15:32:10 -08001057// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001058char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001059{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001060 const char* start = p;
1061 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001062 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001063 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001064 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001065 }
1066 return p;
1067 }
1068 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001069 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1070 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001071 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001072 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001073
Lee Thomason624d43f2012-10-12 10:58:48 -07001074 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001075 if ( p && *p ) {
1076 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001077 }
1078 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +03001079 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001080 }
1081 }
1082 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001083}
1084
1085
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001086XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1087{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001088 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001089 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001090 }
1091 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1092 text->SetCData( this->CData() );
1093 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001094}
1095
1096
1097bool XMLText::ShallowEqual( const XMLNode* compare ) const
1098{
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001099 const XMLText* text = compare->ToText();
1100 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001101}
1102
1103
Lee Thomason56bdd022012-02-09 18:16:58 -08001104bool XMLText::Accept( XMLVisitor* visitor ) const
1105{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001106 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001107 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001108}
1109
1110
Lee Thomason3f57d272012-01-11 15:30:03 -08001111// --------- XMLComment ---------- //
1112
Lee Thomasone4422302012-01-20 17:59:50 -08001113XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001114{
1115}
1116
1117
Lee Thomasonce0763e2012-01-11 15:43:54 -08001118XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001119{
Lee Thomason3f57d272012-01-11 15:30:03 -08001120}
1121
1122
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001123char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -08001124{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001125 // Comment parses as text.
1126 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001127 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001128 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001129 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001130 }
1131 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001132}
1133
1134
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001135XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1136{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001137 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001138 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001139 }
1140 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1141 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001142}
1143
1144
1145bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1146{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001147 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001148 const XMLComment* comment = compare->ToComment();
1149 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001150}
1151
1152
Lee Thomason751da522012-02-10 08:50:51 -08001153bool XMLComment::Accept( XMLVisitor* visitor ) const
1154{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001155 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001156 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001157}
Lee Thomason56bdd022012-02-09 18:16:58 -08001158
1159
Lee Thomason50f97b22012-02-11 16:33:40 -08001160// --------- XMLDeclaration ---------- //
1161
1162XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1163{
1164}
1165
1166
1167XMLDeclaration::~XMLDeclaration()
1168{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001169 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001170}
1171
1172
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001173char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001174{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001175 // Declaration parses as text.
1176 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001177 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001178 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001179 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001180 }
1181 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001182}
1183
1184
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001185XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1186{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001187 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001188 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001189 }
1190 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1191 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001192}
1193
1194
1195bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1196{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001197 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001198 const XMLDeclaration* declaration = compare->ToDeclaration();
1199 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001200}
1201
1202
1203
Lee Thomason50f97b22012-02-11 16:33:40 -08001204bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1205{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001206 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001207 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001208}
1209
1210// --------- XMLUnknown ---------- //
1211
1212XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1213{
1214}
1215
1216
1217XMLUnknown::~XMLUnknown()
1218{
1219}
1220
1221
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001222char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001223{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001224 // Unknown parses as text.
1225 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001226
Lee Thomason624d43f2012-10-12 10:58:48 -07001227 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001228 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001229 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001230 }
1231 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001232}
1233
1234
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001235XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1236{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001237 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001238 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001239 }
1240 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1241 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001242}
1243
1244
1245bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1246{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001247 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001248 const XMLUnknown* unknown = compare->ToUnknown();
1249 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001250}
1251
1252
Lee Thomason50f97b22012-02-11 16:33:40 -08001253bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1254{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001255 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001256 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001257}
1258
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001259// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001260
1261const char* XMLAttribute::Name() const
1262{
1263 return _name.GetStr();
1264}
1265
1266const char* XMLAttribute::Value() const
1267{
1268 return _value.GetStr();
1269}
1270
Lee Thomason6f381b72012-03-02 12:59:39 -08001271char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001272{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001273 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001274 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001275 if ( !p || !*p ) {
1276 return 0;
1277 }
Lee Thomason22aead12012-01-23 13:29:35 -08001278
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001279 // Skip white space before =
1280 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001281 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001282 return 0;
1283 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001284
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001285 ++p; // move up to opening quote
1286 p = XMLUtil::SkipWhiteSpace( p );
1287 if ( *p != '\"' && *p != '\'' ) {
1288 return 0;
1289 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001290
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001291 char endTag[2] = { *p, 0 };
1292 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001293
Lee Thomason624d43f2012-10-12 10:58:48 -07001294 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001295 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001296}
1297
1298
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001299void XMLAttribute::SetName( const char* n )
1300{
Lee Thomason624d43f2012-10-12 10:58:48 -07001301 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001302}
1303
1304
Lee Thomason2fa81722012-11-09 12:37:46 -08001305XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001306{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001307 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001308 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001309 }
1310 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001311}
1312
1313
Lee Thomason2fa81722012-11-09 12:37:46 -08001314XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001315{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001316 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001317 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001318 }
1319 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001320}
1321
1322
Lee Thomason51c12712016-06-04 20:18:49 -07001323XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1324{
1325 if (XMLUtil::ToInt64(Value(), value)) {
1326 return XML_SUCCESS;
1327 }
1328 return XML_WRONG_ATTRIBUTE_TYPE;
1329}
1330
1331
Lee Thomason2fa81722012-11-09 12:37:46 -08001332XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001333{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001334 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001335 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001336 }
1337 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001338}
1339
1340
Lee Thomason2fa81722012-11-09 12:37:46 -08001341XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001342{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001343 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001344 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001345 }
1346 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001347}
1348
1349
Lee Thomason2fa81722012-11-09 12:37:46 -08001350XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001351{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001352 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001353 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001354 }
1355 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001356}
1357
1358
1359void XMLAttribute::SetAttribute( const char* v )
1360{
Lee Thomason624d43f2012-10-12 10:58:48 -07001361 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001362}
1363
1364
Lee Thomason1ff38e02012-02-14 18:18:16 -08001365void XMLAttribute::SetAttribute( int v )
1366{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001367 char buf[BUF_SIZE];
1368 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001369 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001370}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001371
1372
1373void XMLAttribute::SetAttribute( unsigned v )
1374{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001375 char buf[BUF_SIZE];
1376 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001377 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001378}
1379
1380
Lee Thomason51c12712016-06-04 20:18:49 -07001381void XMLAttribute::SetAttribute(int64_t v)
1382{
1383 char buf[BUF_SIZE];
1384 XMLUtil::ToStr(v, buf, BUF_SIZE);
1385 _value.SetStr(buf);
1386}
1387
1388
1389
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001390void XMLAttribute::SetAttribute( bool v )
1391{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001392 char buf[BUF_SIZE];
1393 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001394 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001395}
1396
1397void XMLAttribute::SetAttribute( double 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
1404void XMLAttribute::SetAttribute( float v )
1405{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001406 char buf[BUF_SIZE];
1407 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001408 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001409}
1410
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001411
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001412// --------- XMLElement ---------- //
1413XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001414 _closingType( 0 ),
1415 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001416{
1417}
1418
1419
1420XMLElement::~XMLElement()
1421{
Lee Thomason624d43f2012-10-12 10:58:48 -07001422 while( _rootAttribute ) {
1423 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001424 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001425 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001426 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001427}
1428
1429
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001430const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1431{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001432 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001433 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1434 return a;
1435 }
1436 }
1437 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001438}
1439
1440
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001441const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001442{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001443 const XMLAttribute* a = FindAttribute( name );
1444 if ( !a ) {
1445 return 0;
1446 }
1447 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1448 return a->Value();
1449 }
1450 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001451}
1452
1453
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001454const char* XMLElement::GetText() const
1455{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001456 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001457 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001458 }
1459 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001460}
1461
1462
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001463void XMLElement::SetText( const char* inText )
1464{
Uli Kusterer869bb592014-01-21 01:36:16 +01001465 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001466 FirstChild()->SetValue( inText );
1467 else {
1468 XMLText* theText = GetDocument()->NewText( inText );
1469 InsertFirstChild( theText );
1470 }
1471}
1472
Lee Thomason5bb2d802014-01-24 10:42:57 -08001473
1474void XMLElement::SetText( int v )
1475{
1476 char buf[BUF_SIZE];
1477 XMLUtil::ToStr( v, buf, BUF_SIZE );
1478 SetText( buf );
1479}
1480
1481
1482void XMLElement::SetText( unsigned v )
1483{
1484 char buf[BUF_SIZE];
1485 XMLUtil::ToStr( v, buf, BUF_SIZE );
1486 SetText( buf );
1487}
1488
1489
Lee Thomason51c12712016-06-04 20:18:49 -07001490void XMLElement::SetText(int64_t v)
1491{
1492 char buf[BUF_SIZE];
1493 XMLUtil::ToStr(v, buf, BUF_SIZE);
1494 SetText(buf);
1495}
1496
1497
1498void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001499{
1500 char buf[BUF_SIZE];
1501 XMLUtil::ToStr( v, buf, BUF_SIZE );
1502 SetText( buf );
1503}
1504
1505
1506void XMLElement::SetText( float v )
1507{
1508 char buf[BUF_SIZE];
1509 XMLUtil::ToStr( v, buf, BUF_SIZE );
1510 SetText( buf );
1511}
1512
1513
1514void XMLElement::SetText( double v )
1515{
1516 char buf[BUF_SIZE];
1517 XMLUtil::ToStr( v, buf, BUF_SIZE );
1518 SetText( buf );
1519}
1520
1521
MortenMacFly4ee49f12013-01-14 20:03:14 +01001522XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001523{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001524 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001525 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001526 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001527 return XML_SUCCESS;
1528 }
1529 return XML_CAN_NOT_CONVERT_TEXT;
1530 }
1531 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001532}
1533
1534
MortenMacFly4ee49f12013-01-14 20:03:14 +01001535XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001536{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001537 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001538 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001539 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001540 return XML_SUCCESS;
1541 }
1542 return XML_CAN_NOT_CONVERT_TEXT;
1543 }
1544 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001545}
1546
1547
Lee Thomason51c12712016-06-04 20:18:49 -07001548XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1549{
1550 if (FirstChild() && FirstChild()->ToText()) {
1551 const char* t = FirstChild()->Value();
1552 if (XMLUtil::ToInt64(t, ival)) {
1553 return XML_SUCCESS;
1554 }
1555 return XML_CAN_NOT_CONVERT_TEXT;
1556 }
1557 return XML_NO_TEXT_NODE;
1558}
1559
1560
MortenMacFly4ee49f12013-01-14 20:03:14 +01001561XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001562{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001563 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001564 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001565 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001566 return XML_SUCCESS;
1567 }
1568 return XML_CAN_NOT_CONVERT_TEXT;
1569 }
1570 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001571}
1572
1573
MortenMacFly4ee49f12013-01-14 20:03:14 +01001574XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001575{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001576 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001577 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001578 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001579 return XML_SUCCESS;
1580 }
1581 return XML_CAN_NOT_CONVERT_TEXT;
1582 }
1583 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001584}
1585
1586
MortenMacFly4ee49f12013-01-14 20:03:14 +01001587XMLError XMLElement::QueryFloatText( float* fval ) 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::ToFloat( t, fval ) ) {
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
1600
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001601XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1602{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001603 XMLAttribute* last = 0;
1604 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001605 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001606 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001607 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001608 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1609 break;
1610 }
1611 }
1612 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001613 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001614 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1615 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001616 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001617 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001618 }
1619 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001620 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001621 }
1622 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001623 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001624 }
1625 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001626}
1627
1628
U-Stream\Leeae25a442012-02-17 17:48:16 -08001629void XMLElement::DeleteAttribute( const char* name )
1630{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001631 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001632 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001633 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1634 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001635 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001636 }
1637 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001638 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001639 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001640 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001641 break;
1642 }
1643 prev = a;
1644 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001645}
1646
1647
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001648char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001649{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001650 const char* start = p;
1651 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001652
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001653 // Read the attributes.
1654 while( p ) {
1655 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001656 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001657 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001658 return 0;
1659 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001660
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001661 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001662 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001663 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001664 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1665 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001666 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001667
Lee Thomason624d43f2012-10-12 10:58:48 -07001668 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001669 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001670 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001671 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001672 return 0;
1673 }
1674 // There is a minor bug here: if the attribute in the source xml
1675 // document is duplicated, it will not be detected and the
1676 // attribute will be doubly added. However, tracking the 'prevAttribute'
1677 // avoids re-scanning the attribute list. Preferring performance for
1678 // now, may reconsider in the future.
1679 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001680 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001681 }
1682 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001683 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001684 }
1685 prevAttribute = attrib;
1686 }
1687 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001688 else if ( *p == '>' ) {
1689 ++p;
1690 break;
1691 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001692 // end of the tag
1693 else if ( *p == '/' && *(p+1) == '>' ) {
1694 _closingType = CLOSED;
1695 return p+2; // done; sealed element.
1696 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001697 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001698 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001699 return 0;
1700 }
1701 }
1702 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001703}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001704
Dmitry-Mee3225b12014-09-03 11:03:11 +04001705void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1706{
1707 if ( attribute == 0 ) {
1708 return;
1709 }
1710 MemPool* pool = attribute->_memPool;
1711 attribute->~XMLAttribute();
1712 pool->Free( attribute );
1713}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001714
Lee Thomason67d61312012-01-24 16:01:51 -08001715//
1716// <ele></ele>
1717// <ele>foo<b>bar</b></ele>
1718//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001719char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001720{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001721 // Read the element name.
1722 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001723
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001724 // The closing element is the </element> form. It is
1725 // parsed just like a regular element then deleted from
1726 // the DOM.
1727 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001728 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001729 ++p;
1730 }
Lee Thomason67d61312012-01-24 16:01:51 -08001731
Lee Thomason624d43f2012-10-12 10:58:48 -07001732 p = _value.ParseName( p );
1733 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001734 return 0;
1735 }
Lee Thomason67d61312012-01-24 16:01:51 -08001736
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001737 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001738 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001739 return p;
1740 }
Lee Thomason67d61312012-01-24 16:01:51 -08001741
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001742 p = XMLNode::ParseDeep( p, strPair );
1743 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001744}
1745
1746
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001747
1748XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1749{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001750 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001751 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001752 }
1753 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1754 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1755 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1756 }
1757 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001758}
1759
1760
1761bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1762{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001763 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001764 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001765 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001766
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001767 const XMLAttribute* a=FirstAttribute();
1768 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001769
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001770 while ( a && b ) {
1771 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1772 return false;
1773 }
1774 a = a->Next();
1775 b = b->Next();
1776 }
1777 if ( a || b ) {
1778 // different count
1779 return false;
1780 }
1781 return true;
1782 }
1783 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001784}
1785
1786
Lee Thomason751da522012-02-10 08:50:51 -08001787bool XMLElement::Accept( XMLVisitor* visitor ) const
1788{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001789 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001790 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001791 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1792 if ( !node->Accept( visitor ) ) {
1793 break;
1794 }
1795 }
1796 }
1797 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001798}
Lee Thomason56bdd022012-02-09 18:16:58 -08001799
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001800
Lee Thomason3f57d272012-01-11 15:30:03 -08001801// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001802
1803// Warning: List must match 'enum XMLError'
1804const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1805 "XML_SUCCESS",
1806 "XML_NO_ATTRIBUTE",
1807 "XML_WRONG_ATTRIBUTE_TYPE",
1808 "XML_ERROR_FILE_NOT_FOUND",
1809 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1810 "XML_ERROR_FILE_READ_ERROR",
1811 "XML_ERROR_ELEMENT_MISMATCH",
1812 "XML_ERROR_PARSING_ELEMENT",
1813 "XML_ERROR_PARSING_ATTRIBUTE",
1814 "XML_ERROR_IDENTIFYING_TAG",
1815 "XML_ERROR_PARSING_TEXT",
1816 "XML_ERROR_PARSING_CDATA",
1817 "XML_ERROR_PARSING_COMMENT",
1818 "XML_ERROR_PARSING_DECLARATION",
1819 "XML_ERROR_PARSING_UNKNOWN",
1820 "XML_ERROR_EMPTY_DOCUMENT",
1821 "XML_ERROR_MISMATCHED_ELEMENT",
1822 "XML_ERROR_PARSING",
1823 "XML_CAN_NOT_CONVERT_TEXT",
1824 "XML_NO_TEXT_NODE"
1825};
1826
1827
Lee Thomason624d43f2012-10-12 10:58:48 -07001828XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001829 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001830 _writeBOM( false ),
1831 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07001832 _errorID(XML_SUCCESS),
Lee Thomason624d43f2012-10-12 10:58:48 -07001833 _whitespace( whitespace ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001834 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001835{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03001836 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
1837 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08001838}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001839
1840
Lee Thomason3f57d272012-01-11 15:30:03 -08001841XMLDocument::~XMLDocument()
1842{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001843 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001844}
1845
1846
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001847void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001848{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001849 DeleteChildren();
1850
Dmitry-Meab37df82014-11-28 12:08:36 +03001851#ifdef DEBUG
1852 const bool hadError = Error();
1853#endif
Lee Thomason85536252016-06-04 19:10:53 -07001854 _errorID = XML_SUCCESS;
Lee Thomason584af572016-09-05 14:14:16 -07001855 _errorStr1.Reset();
1856 _errorStr2.Reset();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001857
Lee Thomason624d43f2012-10-12 10:58:48 -07001858 delete [] _charBuffer;
1859 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001860
1861#if 0
1862 _textPool.Trace( "text" );
1863 _elementPool.Trace( "element" );
1864 _commentPool.Trace( "comment" );
1865 _attributePool.Trace( "attribute" );
1866#endif
1867
1868#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001869 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001870 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1871 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1872 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1873 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1874 }
1875#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001876}
1877
Lee Thomason3f57d272012-01-11 15:30:03 -08001878
Lee Thomason2c85a712012-01-31 08:24:24 -08001879XMLElement* XMLDocument::NewElement( const char* name )
1880{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001881 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001882 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1883 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001884 ele->SetName( name );
1885 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001886}
1887
1888
Lee Thomason1ff38e02012-02-14 18:18:16 -08001889XMLComment* XMLDocument::NewComment( const char* str )
1890{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001891 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001892 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1893 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001894 comment->SetValue( str );
1895 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001896}
1897
1898
1899XMLText* XMLDocument::NewText( const char* str )
1900{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001901 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001902 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1903 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001904 text->SetValue( str );
1905 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001906}
1907
1908
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001909XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1910{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001911 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001912 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1913 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001914 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1915 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001916}
1917
1918
1919XMLUnknown* XMLDocument::NewUnknown( const char* str )
1920{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001921 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001922 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1923 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001924 unk->SetValue( str );
1925 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001926}
1927
Dmitry-Me01578db2014-08-19 10:18:48 +04001928static FILE* callfopen( const char* filepath, const char* mode )
1929{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001930 TIXMLASSERT( filepath );
1931 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001932#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1933 FILE* fp = 0;
1934 errno_t err = fopen_s( &fp, filepath, mode );
1935 if ( err ) {
1936 return 0;
1937 }
1938#else
1939 FILE* fp = fopen( filepath, mode );
1940#endif
1941 return fp;
1942}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001943
1944void XMLDocument::DeleteNode( XMLNode* node ) {
1945 TIXMLASSERT( node );
1946 TIXMLASSERT(node->_document == this );
1947 if (node->_parent) {
1948 node->_parent->DeleteChild( node );
1949 }
1950 else {
1951 // Isn't in the tree.
1952 // Use the parent delete.
1953 // Also, we need to mark it tracked: we 'know'
1954 // it was never used.
1955 node->_memPool->SetTracked();
1956 // Call the static XMLNode version:
1957 XMLNode::DeleteNode(node);
1958 }
1959}
1960
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001961
Lee Thomason2fa81722012-11-09 12:37:46 -08001962XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001963{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001964 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001965 FILE* fp = callfopen( filename, "rb" );
1966 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001967 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001968 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001969 }
1970 LoadFile( fp );
1971 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001972 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001973}
1974
Dmitry-Me901fed52015-09-25 10:29:51 +03001975// This is likely overengineered template art to have a check that unsigned long value incremented
1976// by one still fits into size_t. If size_t type is larger than unsigned long type
1977// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
1978// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
1979// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
1980// types sizes relate to each other.
1981template
1982<bool = (sizeof(unsigned long) >= sizeof(size_t))>
1983struct LongFitsIntoSizeTMinusOne {
1984 static bool Fits( unsigned long value )
1985 {
1986 return value < (size_t)-1;
1987 }
1988};
1989
1990template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02001991struct LongFitsIntoSizeTMinusOne<false> {
1992 static bool Fits( unsigned long )
1993 {
1994 return true;
1995 }
1996};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001997
Lee Thomason2fa81722012-11-09 12:37:46 -08001998XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001999{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002000 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002001
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002002 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002003 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002004 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2005 return _errorID;
2006 }
2007
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002008 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002009 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002010 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002011 if ( filelength == -1L ) {
2012 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2013 return _errorID;
2014 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002015 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002016
Dmitry-Me901fed52015-09-25 10:29:51 +03002017 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002018 // Cannot handle files which won't fit in buffer together with null terminator
2019 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2020 return _errorID;
2021 }
2022
Dmitry-Me72801b82015-05-07 09:41:39 +03002023 if ( filelength == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06002024 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002025 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002026 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002027
Dmitry-Me72801b82015-05-07 09:41:39 +03002028 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002029 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002030 _charBuffer = new char[size+1];
2031 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002032 if ( read != size ) {
2033 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002034 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002035 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002036
Lee Thomason624d43f2012-10-12 10:58:48 -07002037 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002038
Dmitry-Me97476b72015-01-01 16:15:57 +03002039 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002040 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002041}
2042
2043
Lee Thomason2fa81722012-11-09 12:37:46 -08002044XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002045{
Dmitry-Me01578db2014-08-19 10:18:48 +04002046 FILE* fp = callfopen( filename, "w" );
2047 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002048 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002049 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002050 }
2051 SaveFile(fp, compact);
2052 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002053 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002054}
2055
2056
Lee Thomason2fa81722012-11-09 12:37:46 -08002057XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002058{
Ant Mitchell189198f2015-03-24 16:20:36 +00002059 // Clear any error from the last save, otherwise it will get reported
2060 // for *this* call.
Lee Thomason85536252016-06-04 19:10:53 -07002061 SetError(XML_SUCCESS, 0, 0);
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002062 XMLPrinter stream( fp, compact );
2063 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002064 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002065}
2066
Lee Thomason1ff38e02012-02-14 18:18:16 -08002067
Lee Thomason2fa81722012-11-09 12:37:46 -08002068XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002069{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002070 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002071
Lee Thomason82d32002014-02-21 22:47:18 -08002072 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002073 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002074 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002075 }
2076 if ( len == (size_t)(-1) ) {
2077 len = strlen( p );
2078 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002079 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002080 _charBuffer = new char[ len+1 ];
2081 memcpy( _charBuffer, p, len );
2082 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002083
Dmitry-Me97476b72015-01-01 16:15:57 +03002084 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002085 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002086 // clean up now essentially dangling memory.
2087 // and the parse fail can put objects in the
2088 // pools that are dead and inaccessible.
2089 DeleteChildren();
2090 _elementPool.Clear();
2091 _attributePool.Clear();
2092 _textPool.Clear();
2093 _commentPool.Clear();
2094 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002095 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002096}
2097
2098
PKEuS1c5f99e2013-07-06 11:28:39 +02002099void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002100{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002101 if ( streamer ) {
2102 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002103 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002104 else {
2105 XMLPrinter stdoutStreamer( stdout );
2106 Accept( &stdoutStreamer );
2107 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002108}
2109
2110
Lee Thomason2fa81722012-11-09 12:37:46 -08002111void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08002112{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002113 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002114 _errorID = error;
Lee Thomason584af572016-09-05 14:14:16 -07002115
2116 _errorStr1.Reset();
2117 _errorStr2.Reset();
2118
2119 if (str1)
2120 _errorStr1.SetStr(str1);
2121 if (str2)
2122 _errorStr2.SetStr(str2);
Lee Thomason67d61312012-01-24 16:01:51 -08002123}
2124
Lee Thomason331596e2014-09-11 14:56:43 -07002125const char* XMLDocument::ErrorName() const
2126{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002127 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002128 const char* errorName = _errorNames[_errorID];
2129 TIXMLASSERT( errorName && errorName[0] );
2130 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002131}
Lee Thomason5cae8972012-01-24 18:03:07 -08002132
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002133void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002134{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002135 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002136 static const int LEN = 20;
2137 char buf1[LEN] = { 0 };
2138 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002139
Lee Thomason584af572016-09-05 14:14:16 -07002140 if ( !_errorStr1.Empty() ) {
2141 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002142 }
Lee Thomason584af572016-09-05 14:14:16 -07002143 if ( !_errorStr2.Empty() ) {
2144 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002145 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002146
Dmitry-Me2ad43202015-04-16 12:18:58 +03002147 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2148 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2149 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
Lee Thomason331596e2014-09-11 14:56:43 -07002150 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
Dmitry-Me400f1192015-04-07 11:51:21 +03002151 static_cast<int>( _errorID ), ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002152 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002153}
2154
Dmitry-Me97476b72015-01-01 16:15:57 +03002155void XMLDocument::Parse()
2156{
2157 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2158 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08002159 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03002160 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03002161 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002162 if ( !*p ) {
2163 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2164 return;
2165 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08002166 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002167}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002168
PKEuS1bfb9542013-08-04 13:51:17 +02002169XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002170 _elementJustOpened( false ),
2171 _firstElement( true ),
2172 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002173 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002174 _textDepth( -1 ),
2175 _processEntities( true ),
2176 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002177{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002178 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002179 _entityFlag[i] = false;
2180 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002181 }
2182 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002183 const char entityValue = entities[i].value;
2184 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
2185 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002186 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002187 _restrictedEntityFlag[(unsigned char)'&'] = true;
2188 _restrictedEntityFlag[(unsigned char)'<'] = true;
2189 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002190 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002191}
2192
2193
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002194void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002195{
2196 va_list va;
2197 va_start( va, format );
2198
Lee Thomason624d43f2012-10-12 10:58:48 -07002199 if ( _fp ) {
2200 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002201 }
2202 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002203 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002204 // Close out and re-start the va-args
2205 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002206 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002207 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002208 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002209 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002210 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002211 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002212 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002213}
2214
2215
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002216void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002217{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002218 for( int i=0; i<depth; ++i ) {
2219 Print( " " );
2220 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002221}
2222
2223
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002224void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002225{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002226 // Look for runs of bytes between entities to print.
2227 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002228
Lee Thomason624d43f2012-10-12 10:58:48 -07002229 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002230 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002231 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002232 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002233 // Remember, char is sometimes signed. (How many times has that bitten me?)
2234 if ( *q > 0 && *q < ENTITY_RANGE ) {
2235 // Check for entities. If one is found, flush
2236 // the stream up until the entity, write the
2237 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002238 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002239 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002240 const size_t delta = q - p;
2241 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002242 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002243 Print( "%.*s", toPrint, p );
2244 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002245 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002246 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002247 for( int i=0; i<NUM_ENTITIES; ++i ) {
2248 if ( entities[i].value == *q ) {
2249 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002250 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002251 break;
2252 }
2253 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002254 if ( !entityPatternPrinted ) {
2255 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2256 TIXMLASSERT( false );
2257 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002258 ++p;
2259 }
2260 }
2261 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002262 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002263 }
2264 }
2265 // Flush the remaining string. This will be the entire
2266 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002267 TIXMLASSERT( p <= q );
2268 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002269 Print( "%s", p );
2270 }
Lee Thomason857b8682012-01-25 17:50:25 -08002271}
2272
U-Stream\Leeae25a442012-02-17 17:48:16 -08002273
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002274void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002275{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002276 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002277 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 -07002278 Print( "%s", bom );
2279 }
2280 if ( writeDec ) {
2281 PushDeclaration( "xml version=\"1.0\"" );
2282 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002283}
2284
2285
Uli Kusterer593a33d2014-02-01 12:48:51 +01002286void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002287{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002288 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002289 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002290
Uli Kusterer593a33d2014-02-01 12:48:51 +01002291 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002292 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002293 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002294 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002295 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002296 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002297
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002298 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002299 _elementJustOpened = true;
2300 _firstElement = false;
2301 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002302}
2303
2304
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002305void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002306{
Lee Thomason624d43f2012-10-12 10:58:48 -07002307 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002308 Print( " %s=\"", name );
2309 PrintString( value, false );
2310 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002311}
2312
2313
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002314void XMLPrinter::PushAttribute( const char* name, int v )
2315{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002316 char buf[BUF_SIZE];
2317 XMLUtil::ToStr( v, buf, BUF_SIZE );
2318 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002319}
2320
2321
2322void XMLPrinter::PushAttribute( const char* name, unsigned v )
2323{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002324 char buf[BUF_SIZE];
2325 XMLUtil::ToStr( v, buf, BUF_SIZE );
2326 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002327}
2328
2329
Lee Thomason51c12712016-06-04 20:18:49 -07002330void XMLPrinter::PushAttribute(const char* name, int64_t v)
2331{
2332 char buf[BUF_SIZE];
2333 XMLUtil::ToStr(v, buf, BUF_SIZE);
2334 PushAttribute(name, buf);
2335}
2336
2337
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002338void XMLPrinter::PushAttribute( const char* name, bool v )
2339{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002340 char buf[BUF_SIZE];
2341 XMLUtil::ToStr( v, buf, BUF_SIZE );
2342 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002343}
2344
2345
2346void XMLPrinter::PushAttribute( const char* name, double v )
2347{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002348 char buf[BUF_SIZE];
2349 XMLUtil::ToStr( v, buf, BUF_SIZE );
2350 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002351}
2352
2353
Uli Kustererca412e82014-02-01 13:35:05 +01002354void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002355{
Lee Thomason624d43f2012-10-12 10:58:48 -07002356 --_depth;
2357 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002358
Lee Thomason624d43f2012-10-12 10:58:48 -07002359 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002360 Print( "/>" );
2361 }
2362 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002363 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002364 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002365 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002366 }
2367 Print( "</%s>", name );
2368 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002369
Lee Thomason624d43f2012-10-12 10:58:48 -07002370 if ( _textDepth == _depth ) {
2371 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002372 }
Uli Kustererca412e82014-02-01 13:35:05 +01002373 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002374 Print( "\n" );
2375 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002376 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002377}
2378
2379
Dmitry-Mea092bc12014-12-23 17:57:05 +03002380void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002381{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002382 if ( !_elementJustOpened ) {
2383 return;
2384 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002385 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002386 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002387}
2388
2389
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002390void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002391{
Lee Thomason624d43f2012-10-12 10:58:48 -07002392 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002393
Dmitry-Mea092bc12014-12-23 17:57:05 +03002394 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002395 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002396 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002397 }
2398 else {
2399 PrintString( text, true );
2400 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002401}
2402
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002403void XMLPrinter::PushText( int64_t value )
2404{
2405 char buf[BUF_SIZE];
2406 XMLUtil::ToStr( value, buf, BUF_SIZE );
2407 PushText( buf, false );
2408}
2409
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002410void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002411{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002412 char buf[BUF_SIZE];
2413 XMLUtil::ToStr( value, buf, BUF_SIZE );
2414 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002415}
2416
2417
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002418void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002419{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002420 char buf[BUF_SIZE];
2421 XMLUtil::ToStr( value, buf, BUF_SIZE );
2422 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002423}
2424
2425
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002426void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002427{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002428 char buf[BUF_SIZE];
2429 XMLUtil::ToStr( value, buf, BUF_SIZE );
2430 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002431}
2432
2433
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002434void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002435{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002436 char buf[BUF_SIZE];
2437 XMLUtil::ToStr( value, buf, BUF_SIZE );
2438 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002439}
2440
2441
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002442void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002443{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002444 char buf[BUF_SIZE];
2445 XMLUtil::ToStr( value, buf, BUF_SIZE );
2446 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002447}
2448
Lee Thomason5cae8972012-01-24 18:03:07 -08002449
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002450void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002451{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002452 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002453 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002454 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002455 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002456 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002457 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002458 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002459}
Lee Thomason751da522012-02-10 08:50:51 -08002460
2461
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002462void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002463{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002464 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002465 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002466 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002467 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002468 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002469 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002470 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002471}
2472
2473
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002474void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002475{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002476 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002477 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002478 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002479 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002480 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002481 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002482 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002483}
2484
2485
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002486bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002487{
Lee Thomason624d43f2012-10-12 10:58:48 -07002488 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002489 if ( doc.HasBOM() ) {
2490 PushHeader( true, false );
2491 }
2492 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002493}
2494
2495
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002496bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002497{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002498 const XMLElement* parentElem = 0;
2499 if ( element.Parent() ) {
2500 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002501 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002502 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002503 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002504 while ( attribute ) {
2505 PushAttribute( attribute->Name(), attribute->Value() );
2506 attribute = attribute->Next();
2507 }
2508 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002509}
2510
2511
Uli Kustererca412e82014-02-01 13:35:05 +01002512bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002513{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002514 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002515 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002516}
2517
2518
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002519bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002520{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002521 PushText( text.Value(), text.CData() );
2522 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002523}
2524
2525
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002526bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002527{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002528 PushComment( comment.Value() );
2529 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002530}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002531
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002532bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002533{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002534 PushDeclaration( declaration.Value() );
2535 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002536}
2537
2538
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002539bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002540{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002541 PushUnknown( unknown.Value() );
2542 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002543}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002544
Lee Thomason685b8952012-11-12 13:00:06 -08002545} // namespace tinyxml2
2546