blob: f8983a1f0ad62d7232565d22529f9b2d3ca9c4d4 [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 }
284 *q++ = LF;
285 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700286 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700287 if ( *(p+1) == CR ) {
288 p += 2;
289 }
290 else {
291 ++p;
292 }
293 *q++ = LF;
294 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700295 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700296 // Entities handled by tinyXML2:
297 // - special entities in the entity table [in/out]
298 // - numeric character reference [in]
299 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800300
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700301 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400302 const int buflen = 10;
303 char buf[buflen] = { 0 };
304 int len = 0;
Dmitry-Me6f51c802015-03-14 13:25:03 +0300305 char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
306 if ( adjusted == 0 ) {
307 *q = *p;
308 ++p;
309 ++q;
310 }
311 else {
312 TIXMLASSERT( 0 <= len && len <= buflen );
313 TIXMLASSERT( q + len <= adjusted );
314 p = adjusted;
315 memcpy( q, buf, len );
316 q += len;
317 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700318 }
319 else {
Dmitry-Me764545e2015-05-20 10:29:24 +0300320 bool entityFound = false;
321 for( int i = 0; i < NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400322 const Entity& entity = entities[i];
323 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
324 && *( p + entity.length + 1 ) == ';' ) {
325 // Found an entity - convert.
326 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700327 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400328 p += entity.length + 2;
Dmitry-Me764545e2015-05-20 10:29:24 +0300329 entityFound = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700330 break;
331 }
332 }
Dmitry-Me764545e2015-05-20 10:29:24 +0300333 if ( !entityFound ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700334 // fixme: treat as error?
335 ++p;
336 ++q;
337 }
338 }
339 }
340 else {
341 *q = *p;
342 ++p;
343 ++q;
344 }
345 }
346 *q = 0;
347 }
348 // The loop below has plenty going on, and this
349 // is a less useful mode. Break it out.
Dmitry-Me5420e542015-05-20 10:51:26 +0300350 if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700351 CollapseWhitespace();
352 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700353 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700354 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300355 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700356 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800357}
358
Lee Thomason2c85a712012-01-31 08:24:24 -0800359
Lee Thomasone4422302012-01-20 17:59:50 -0800360
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800361
Lee Thomason56bdd022012-02-09 18:16:58 -0800362// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800363
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800364const char* XMLUtil::ReadBOM( const char* p, bool* bom )
365{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300366 TIXMLASSERT( p );
367 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700368 *bom = false;
369 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
370 // Check for BOM:
371 if ( *(pu+0) == TIXML_UTF_LEAD_0
372 && *(pu+1) == TIXML_UTF_LEAD_1
373 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
374 *bom = true;
375 p += 3;
376 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300377 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700378 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800379}
380
381
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800382void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
383{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700384 const unsigned long BYTE_MASK = 0xBF;
385 const unsigned long BYTE_MARK = 0x80;
386 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800387
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700388 if (input < 0x80) {
389 *length = 1;
390 }
391 else if ( input < 0x800 ) {
392 *length = 2;
393 }
394 else if ( input < 0x10000 ) {
395 *length = 3;
396 }
397 else if ( input < 0x200000 ) {
398 *length = 4;
399 }
400 else {
Dmitry-Me2f465c42015-03-16 11:08:23 +0300401 *length = 0; // This code won't convert this correctly anyway.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700402 return;
403 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800404
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700405 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800406
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700407 // Scary scary fall throughs.
408 switch (*length) {
409 case 4:
410 --output;
411 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
412 input >>= 6;
413 case 3:
414 --output;
415 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
416 input >>= 6;
417 case 2:
418 --output;
419 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
420 input >>= 6;
421 case 1:
422 --output;
423 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100424 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300425 default:
426 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700427 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800428}
429
430
431const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
432{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700433 // Presume an entity, and pull it out.
434 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800435
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700436 if ( *(p+1) == '#' && *(p+2) ) {
437 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300438 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700439 ptrdiff_t delta = 0;
440 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800441 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800442
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700443 if ( *(p+2) == 'x' ) {
444 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300445 const char* q = p+3;
446 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700447 return 0;
448 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800449
Lee Thomason7e67bc82015-01-12 14:05:12 -0800450 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800451
Dmitry-Me9f56e122015-01-12 10:07:54 +0300452 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700453 return 0;
454 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800455 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800456
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700457 delta = q-p;
458 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800459
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700460 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700461 unsigned int digit = 0;
462
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700463 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300464 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700465 }
466 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300467 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700468 }
469 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300470 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700471 }
472 else {
473 return 0;
474 }
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100475 TIXMLASSERT( digit < 16 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300476 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
477 const unsigned int digitScaled = mult * digit;
478 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
479 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300480 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700481 mult *= 16;
482 --q;
483 }
484 }
485 else {
486 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300487 const char* q = p+2;
488 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700489 return 0;
490 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800491
Lee Thomason7e67bc82015-01-12 14:05:12 -0800492 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800493
Dmitry-Me9f56e122015-01-12 10:07:54 +0300494 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700495 return 0;
496 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800497 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800498
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700499 delta = q-p;
500 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800501
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700502 while ( *q != '#' ) {
503 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300504 const unsigned int digit = *q - '0';
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100505 TIXMLASSERT( digit < 10 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300506 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
507 const unsigned int digitScaled = mult * digit;
508 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
509 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700510 }
511 else {
512 return 0;
513 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300514 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700515 mult *= 10;
516 --q;
517 }
518 }
519 // convert the UCS to UTF-8
520 ConvertUTF32ToUTF8( ucs, value, length );
521 return p + delta + 1;
522 }
523 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800524}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800525
526
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700527void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700528{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700529 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700530}
531
532
533void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
534{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700535 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700536}
537
538
539void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
540{
Doruk Turakde45d042016-08-28 20:47:08 +0200541 TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? "true" : "false" );
Lee Thomason21be8822012-07-15 17:27:22 -0700542}
543
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800544/*
545 ToStr() of a number is a very tricky topic.
546 https://github.com/leethomason/tinyxml2/issues/106
547*/
Lee Thomason21be8822012-07-15 17:27:22 -0700548void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
549{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800550 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700551}
552
553
554void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
555{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800556 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700557}
558
559
Lee Thomason51c12712016-06-04 20:18:49 -0700560void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize)
561{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700562 // horrible syntax trick to make the compiler happy about %lld
563 TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v);
Lee Thomason51c12712016-06-04 20:18:49 -0700564}
565
566
Lee Thomason21be8822012-07-15 17:27:22 -0700567bool XMLUtil::ToInt( const char* str, int* value )
568{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700569 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
570 return true;
571 }
572 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700573}
574
575bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
576{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700577 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
578 return true;
579 }
580 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700581}
582
583bool XMLUtil::ToBool( const char* str, bool* value )
584{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700585 int ival = 0;
586 if ( ToInt( str, &ival )) {
587 *value = (ival==0) ? false : true;
588 return true;
589 }
590 if ( StringEqual( str, "true" ) ) {
591 *value = true;
592 return true;
593 }
594 else if ( StringEqual( str, "false" ) ) {
595 *value = false;
596 return true;
597 }
598 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700599}
600
601
602bool XMLUtil::ToFloat( const char* str, float* value )
603{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700604 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
605 return true;
606 }
607 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700608}
609
Lee Thomason51c12712016-06-04 20:18:49 -0700610
Lee Thomason21be8822012-07-15 17:27:22 -0700611bool XMLUtil::ToDouble( const char* str, double* value )
612{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700613 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
614 return true;
615 }
616 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700617}
618
619
Lee Thomason51c12712016-06-04 20:18:49 -0700620bool XMLUtil::ToInt64(const char* str, int64_t* value)
621{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700622 long long v = 0; // horrible syntax trick to make the compiler happy about %lld
623 if (TIXML_SSCANF(str, "%lld", &v) == 1) {
624 *value = (int64_t)v;
Lee Thomason51c12712016-06-04 20:18:49 -0700625 return true;
626 }
627 return false;
628}
629
630
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700631char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800632{
Dmitry-Me02384662015-03-03 16:02:13 +0300633 TIXMLASSERT( node );
634 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400635 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700636 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300637 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300638 *node = 0;
639 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700640 return p;
641 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800642
Dmitry-Me962083b2015-05-26 11:38:30 +0300643 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700644 static const char* xmlHeader = { "<?" };
645 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700646 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300647 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700648 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800649
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700650 static const int xmlHeaderLen = 2;
651 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700652 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300653 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700654 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800655
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700656 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
657 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400658 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700659 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300660 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700661 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
662 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700663 p += xmlHeaderLen;
664 }
665 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300666 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700667 returnNode = new (_commentPool.Alloc()) XMLComment( this );
668 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700669 p += commentHeaderLen;
670 }
671 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300672 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700673 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700674 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700675 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700676 p += cdataHeaderLen;
677 text->SetCData( true );
678 }
679 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300680 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700681 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
682 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700683 p += dtdHeaderLen;
684 }
685 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300686 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700687 returnNode = new (_elementPool.Alloc()) XMLElement( this );
688 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700689 p += elementHeaderLen;
690 }
691 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300692 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700693 returnNode = new (_textPool.Alloc()) XMLText( this );
694 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700695 p = start; // Back it up, all the text counts.
696 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800697
Dmitry-Me02384662015-03-03 16:02:13 +0300698 TIXMLASSERT( returnNode );
699 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700700 *node = returnNode;
701 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800702}
703
704
Lee Thomason751da522012-02-10 08:50:51 -0800705bool XMLDocument::Accept( XMLVisitor* visitor ) const
706{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300707 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700708 if ( visitor->VisitEnter( *this ) ) {
709 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
710 if ( !node->Accept( visitor ) ) {
711 break;
712 }
713 }
714 }
715 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800716}
Lee Thomason56bdd022012-02-09 18:16:58 -0800717
718
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800719// --------- XMLNode ----------- //
720
721XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700722 _document( doc ),
723 _parent( 0 ),
724 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200725 _prev( 0 ), _next( 0 ),
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700726 _userData( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200727 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800728{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800729}
730
731
732XMLNode::~XMLNode()
733{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700734 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700735 if ( _parent ) {
736 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700737 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800738}
739
Michael Daumling21626882013-10-22 17:03:37 +0200740const char* XMLNode::Value() const
741{
Dmitry-Mecaa72a62016-08-10 17:34:34 +0300742 // Edge case: XMLDocuments don't have a Value. Return null.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530743 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530744 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200745 return _value.GetStr();
746}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800747
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800748void XMLNode::SetValue( const char* str, bool staticMem )
749{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700750 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700751 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700752 }
753 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700754 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700755 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800756}
757
758
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800759void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800760{
Lee Thomason624d43f2012-10-12 10:58:48 -0700761 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300762 TIXMLASSERT( _lastChild );
Dmitry-Me9cb4eca2016-08-18 18:10:59 +0300763 DeleteChild( _firstChild );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700764 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700765 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800766}
767
768
769void XMLNode::Unlink( XMLNode* child )
770{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300771 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300772 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300773 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700774 if ( child == _firstChild ) {
775 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700776 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700777 if ( child == _lastChild ) {
778 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700779 }
Lee Thomasond923c672012-01-23 08:44:25 -0800780
Lee Thomason624d43f2012-10-12 10:58:48 -0700781 if ( child->_prev ) {
782 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700783 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700784 if ( child->_next ) {
785 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700786 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700787 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800788}
789
790
U-Stream\Leeae25a442012-02-17 17:48:16 -0800791void XMLNode::DeleteChild( XMLNode* node )
792{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300793 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300794 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700795 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100796 Unlink( node );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400797 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800798}
799
800
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800801XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
802{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300803 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300804 if ( addThis->_document != _document ) {
805 TIXMLASSERT( false );
806 return 0;
807 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800808 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700809
Lee Thomason624d43f2012-10-12 10:58:48 -0700810 if ( _lastChild ) {
811 TIXMLASSERT( _firstChild );
812 TIXMLASSERT( _lastChild->_next == 0 );
813 _lastChild->_next = addThis;
814 addThis->_prev = _lastChild;
815 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800816
Lee Thomason624d43f2012-10-12 10:58:48 -0700817 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700818 }
819 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700820 TIXMLASSERT( _firstChild == 0 );
821 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800822
Lee Thomason624d43f2012-10-12 10:58:48 -0700823 addThis->_prev = 0;
824 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700825 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700826 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700827 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800828}
829
830
Lee Thomason1ff38e02012-02-14 18:18:16 -0800831XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
832{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300833 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300834 if ( addThis->_document != _document ) {
835 TIXMLASSERT( false );
836 return 0;
837 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800838 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700839
Lee Thomason624d43f2012-10-12 10:58:48 -0700840 if ( _firstChild ) {
841 TIXMLASSERT( _lastChild );
842 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800843
Lee Thomason624d43f2012-10-12 10:58:48 -0700844 _firstChild->_prev = addThis;
845 addThis->_next = _firstChild;
846 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800847
Lee Thomason624d43f2012-10-12 10:58:48 -0700848 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700849 }
850 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700851 TIXMLASSERT( _lastChild == 0 );
852 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800853
Lee Thomason624d43f2012-10-12 10:58:48 -0700854 addThis->_prev = 0;
855 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700856 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700857 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400858 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800859}
860
861
862XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
863{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300864 TIXMLASSERT( addThis );
865 if ( addThis->_document != _document ) {
866 TIXMLASSERT( false );
867 return 0;
868 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700869
Dmitry-Meabb2d042014-12-09 12:59:31 +0300870 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700871
Lee Thomason624d43f2012-10-12 10:58:48 -0700872 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300873 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700874 return 0;
875 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800876
Lee Thomason624d43f2012-10-12 10:58:48 -0700877 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700878 // The last node or the only node.
879 return InsertEndChild( addThis );
880 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800881 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700882 addThis->_prev = afterThis;
883 addThis->_next = afterThis->_next;
884 afterThis->_next->_prev = addThis;
885 afterThis->_next = addThis;
886 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700887 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800888}
889
890
891
892
Dmitry-Me886ad972015-07-22 11:00:51 +0300893const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800894{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300895 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
896 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700897 if ( element ) {
Dmitry-Me886ad972015-07-22 11:00:51 +0300898 if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700899 return element;
900 }
901 }
902 }
903 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800904}
905
906
Dmitry-Me886ad972015-07-22 11:00:51 +0300907const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800908{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300909 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
910 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700911 if ( element ) {
Dmitry-Me886ad972015-07-22 11:00:51 +0300912 if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700913 return element;
914 }
915 }
916 }
917 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800918}
919
920
Dmitry-Me886ad972015-07-22 11:00:51 +0300921const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800922{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300923 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400924 const XMLElement* element = node->ToElement();
925 if ( element
Dmitry-Me886ad972015-07-22 11:00:51 +0300926 && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400927 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700928 }
929 }
930 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800931}
932
933
Dmitry-Me886ad972015-07-22 11:00:51 +0300934const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800935{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300936 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400937 const XMLElement* element = node->ToElement();
938 if ( element
Dmitry-Me886ad972015-07-22 11:00:51 +0300939 && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400940 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700941 }
942 }
943 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800944}
945
946
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800947char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800948{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700949 // This is a recursive method, but thinking about it "at the current level"
950 // it is a pretty simple flat list:
951 // <foo/>
952 // <!-- comment -->
953 //
954 // With a special case:
955 // <foo>
956 // </foo>
957 // <!-- comment -->
958 //
959 // Where the closing element (/foo) *must* be the next thing after the opening
960 // element, and the names must match. BUT the tricky bit is that the closing
961 // element will be read by the child.
962 //
963 // 'endTag' is the end tag for this node, it is returned by a call to a child.
964 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800965
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700966 while( p && *p ) {
967 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800968
Lee Thomason624d43f2012-10-12 10:58:48 -0700969 p = _document->Identify( p, &node );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300970 if ( node == 0 ) {
971 break;
972 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800973
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700974 StrPair endTag;
975 p = node->ParseDeep( p, &endTag );
976 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400977 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700978 if ( !_document->Error() ) {
979 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700980 }
981 break;
982 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800983
Sarat Addepalli3df007e2015-05-20 10:43:51 +0530984 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530985 if ( decl ) {
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530986 // A declaration can only be the first child of a document.
987 // Set error, if document already has children.
988 if ( !_document->NoChildren() ) {
989 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0);
Dmitry-Me4de7abb2016-08-10 17:30:02 +0300990 DeleteNode( node );
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530991 break;
992 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530993 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530994
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400995 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700996 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -0500997 // We read the end tag. Return it to the parent.
998 if ( ele->ClosingType() == XMLElement::CLOSING ) {
999 if ( parentEnd ) {
1000 ele->_value.TransferTo( parentEnd );
1001 }
1002 node->_memPool->SetTracked(); // created and then immediately deleted.
1003 DeleteNode( node );
1004 return p;
1005 }
1006
1007 // Handle an end tag returned to this level.
1008 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001009 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001010 if ( endTag.Empty() ) {
1011 if ( ele->ClosingType() == XMLElement::OPEN ) {
1012 mismatch = true;
1013 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001014 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001015 else {
1016 if ( ele->ClosingType() != XMLElement::OPEN ) {
1017 mismatch = true;
1018 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001019 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001020 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001021 }
1022 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001023 if ( mismatch ) {
Dmitry-Me886ad972015-07-22 11:00:51 +03001024 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -05001025 DeleteNode( node );
1026 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001027 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001028 }
JayXondbfdd8f2014-12-12 20:07:14 -05001029 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001030 }
1031 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001032}
1033
Dmitry-Mee3225b12014-09-03 11:03:11 +04001034void XMLNode::DeleteNode( XMLNode* node )
1035{
1036 if ( node == 0 ) {
1037 return;
1038 }
1039 MemPool* pool = node->_memPool;
1040 node->~XMLNode();
1041 pool->Free( node );
1042}
1043
Lee Thomason3cebdc42015-01-05 17:16:28 -08001044void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001045{
1046 TIXMLASSERT( insertThis );
1047 TIXMLASSERT( insertThis->_document == _document );
1048
1049 if ( insertThis->_parent )
1050 insertThis->_parent->Unlink( insertThis );
1051 else
1052 insertThis->_memPool->SetTracked();
1053}
1054
Lee Thomason5492a1c2012-01-23 15:32:10 -08001055// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001056char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001057{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001058 const char* start = p;
1059 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001060 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001061 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001062 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001063 }
1064 return p;
1065 }
1066 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001067 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1068 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001069 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001070 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001071
Lee Thomason624d43f2012-10-12 10:58:48 -07001072 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001073 if ( p && *p ) {
1074 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001075 }
1076 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +03001077 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001078 }
1079 }
1080 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001081}
1082
1083
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001084XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1085{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001086 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001087 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001088 }
1089 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1090 text->SetCData( this->CData() );
1091 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001092}
1093
1094
1095bool XMLText::ShallowEqual( const XMLNode* compare ) const
1096{
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001097 const XMLText* text = compare->ToText();
1098 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001099}
1100
1101
Lee Thomason56bdd022012-02-09 18:16:58 -08001102bool XMLText::Accept( XMLVisitor* visitor ) const
1103{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001104 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001105 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001106}
1107
1108
Lee Thomason3f57d272012-01-11 15:30:03 -08001109// --------- XMLComment ---------- //
1110
Lee Thomasone4422302012-01-20 17:59:50 -08001111XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001112{
1113}
1114
1115
Lee Thomasonce0763e2012-01-11 15:43:54 -08001116XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001117{
Lee Thomason3f57d272012-01-11 15:30:03 -08001118}
1119
1120
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001121char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -08001122{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001123 // Comment parses as text.
1124 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001125 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001126 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001127 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001128 }
1129 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001130}
1131
1132
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001133XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1134{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001135 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001136 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001137 }
1138 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1139 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001140}
1141
1142
1143bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1144{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001145 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001146 const XMLComment* comment = compare->ToComment();
1147 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001148}
1149
1150
Lee Thomason751da522012-02-10 08:50:51 -08001151bool XMLComment::Accept( XMLVisitor* visitor ) const
1152{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001153 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001154 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001155}
Lee Thomason56bdd022012-02-09 18:16:58 -08001156
1157
Lee Thomason50f97b22012-02-11 16:33:40 -08001158// --------- XMLDeclaration ---------- //
1159
1160XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1161{
1162}
1163
1164
1165XMLDeclaration::~XMLDeclaration()
1166{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001167 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001168}
1169
1170
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001171char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001172{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001173 // Declaration parses as text.
1174 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001175 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001176 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001177 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001178 }
1179 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001180}
1181
1182
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001183XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1184{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001185 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001186 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001187 }
1188 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1189 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001190}
1191
1192
1193bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1194{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001195 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001196 const XMLDeclaration* declaration = compare->ToDeclaration();
1197 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001198}
1199
1200
1201
Lee Thomason50f97b22012-02-11 16:33:40 -08001202bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1203{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001204 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001205 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001206}
1207
1208// --------- XMLUnknown ---------- //
1209
1210XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1211{
1212}
1213
1214
1215XMLUnknown::~XMLUnknown()
1216{
1217}
1218
1219
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001220char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001221{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001222 // Unknown parses as text.
1223 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001224
Lee Thomason624d43f2012-10-12 10:58:48 -07001225 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001226 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001227 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001228 }
1229 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001230}
1231
1232
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001233XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1234{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001235 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001236 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001237 }
1238 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1239 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001240}
1241
1242
1243bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1244{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001245 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001246 const XMLUnknown* unknown = compare->ToUnknown();
1247 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001248}
1249
1250
Lee Thomason50f97b22012-02-11 16:33:40 -08001251bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1252{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001253 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001254 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001255}
1256
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001257// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001258
1259const char* XMLAttribute::Name() const
1260{
1261 return _name.GetStr();
1262}
1263
1264const char* XMLAttribute::Value() const
1265{
1266 return _value.GetStr();
1267}
1268
Lee Thomason6f381b72012-03-02 12:59:39 -08001269char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001270{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001271 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001272 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001273 if ( !p || !*p ) {
1274 return 0;
1275 }
Lee Thomason22aead12012-01-23 13:29:35 -08001276
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001277 // Skip white space before =
1278 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001279 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001280 return 0;
1281 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001282
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001283 ++p; // move up to opening quote
1284 p = XMLUtil::SkipWhiteSpace( p );
1285 if ( *p != '\"' && *p != '\'' ) {
1286 return 0;
1287 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001288
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001289 char endTag[2] = { *p, 0 };
1290 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001291
Lee Thomason624d43f2012-10-12 10:58:48 -07001292 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001293 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001294}
1295
1296
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001297void XMLAttribute::SetName( const char* n )
1298{
Lee Thomason624d43f2012-10-12 10:58:48 -07001299 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001300}
1301
1302
Lee Thomason2fa81722012-11-09 12:37:46 -08001303XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001304{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001305 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001306 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001307 }
1308 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001309}
1310
1311
Lee Thomason2fa81722012-11-09 12:37:46 -08001312XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001313{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001314 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001315 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001316 }
1317 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001318}
1319
1320
Lee Thomason51c12712016-06-04 20:18:49 -07001321XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1322{
1323 if (XMLUtil::ToInt64(Value(), value)) {
1324 return XML_SUCCESS;
1325 }
1326 return XML_WRONG_ATTRIBUTE_TYPE;
1327}
1328
1329
Lee Thomason2fa81722012-11-09 12:37:46 -08001330XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001331{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001332 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001333 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001334 }
1335 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001336}
1337
1338
Lee Thomason2fa81722012-11-09 12:37:46 -08001339XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001340{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001341 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001342 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001343 }
1344 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001345}
1346
1347
Lee Thomason2fa81722012-11-09 12:37:46 -08001348XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001349{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001350 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001351 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001352 }
1353 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001354}
1355
1356
1357void XMLAttribute::SetAttribute( const char* v )
1358{
Lee Thomason624d43f2012-10-12 10:58:48 -07001359 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001360}
1361
1362
Lee Thomason1ff38e02012-02-14 18:18:16 -08001363void XMLAttribute::SetAttribute( int v )
1364{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001365 char buf[BUF_SIZE];
1366 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001367 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001368}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001369
1370
1371void XMLAttribute::SetAttribute( unsigned v )
1372{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001373 char buf[BUF_SIZE];
1374 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001375 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001376}
1377
1378
Lee Thomason51c12712016-06-04 20:18:49 -07001379void XMLAttribute::SetAttribute(int64_t v)
1380{
1381 char buf[BUF_SIZE];
1382 XMLUtil::ToStr(v, buf, BUF_SIZE);
1383 _value.SetStr(buf);
1384}
1385
1386
1387
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001388void XMLAttribute::SetAttribute( bool v )
1389{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001390 char buf[BUF_SIZE];
1391 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001392 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001393}
1394
1395void XMLAttribute::SetAttribute( double v )
1396{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001397 char buf[BUF_SIZE];
1398 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001399 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001400}
1401
1402void XMLAttribute::SetAttribute( float v )
1403{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001404 char buf[BUF_SIZE];
1405 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001406 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001407}
1408
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001409
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001410// --------- XMLElement ---------- //
1411XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001412 _closingType( 0 ),
1413 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001414{
1415}
1416
1417
1418XMLElement::~XMLElement()
1419{
Lee Thomason624d43f2012-10-12 10:58:48 -07001420 while( _rootAttribute ) {
1421 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001422 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001423 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001424 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001425}
1426
1427
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001428const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1429{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001430 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001431 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1432 return a;
1433 }
1434 }
1435 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001436}
1437
1438
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001439const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001440{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001441 const XMLAttribute* a = FindAttribute( name );
1442 if ( !a ) {
1443 return 0;
1444 }
1445 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1446 return a->Value();
1447 }
1448 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001449}
1450
Josh Wittnercf3dd092016-10-11 18:57:17 -07001451int XMLElement::IntAttribute(const char* name, int defaultValue) const
1452{
1453 int i = defaultValue;
1454 QueryIntAttribute(name, &i);
1455 return i;
1456}
1457
1458unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
1459{
1460 unsigned i = defaultValue;
1461 QueryUnsignedAttribute(name, &i);
1462 return i;
1463}
1464
1465int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
1466{
1467 int64_t i = defaultValue;
1468 QueryInt64Attribute(name, &i);
1469 return i;
1470}
1471
1472bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
1473{
1474 bool b = defaultValue;
1475 QueryBoolAttribute(name, &b);
1476 return b;
1477}
1478
1479double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
1480{
1481 double d = defaultValue;
1482 QueryDoubleAttribute(name, &d);
1483 return d;
1484}
1485
1486float XMLElement::FloatAttribute(const char* name, float defaultValue) const
1487{
1488 float f = defaultValue;
1489 QueryFloatAttribute(name, &f);
1490 return f;
1491}
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001492
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001493const char* XMLElement::GetText() const
1494{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001495 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001496 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001497 }
1498 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001499}
1500
1501
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001502void XMLElement::SetText( const char* inText )
1503{
Uli Kusterer869bb592014-01-21 01:36:16 +01001504 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001505 FirstChild()->SetValue( inText );
1506 else {
1507 XMLText* theText = GetDocument()->NewText( inText );
1508 InsertFirstChild( theText );
1509 }
1510}
1511
Lee Thomason5bb2d802014-01-24 10:42:57 -08001512
1513void XMLElement::SetText( int v )
1514{
1515 char buf[BUF_SIZE];
1516 XMLUtil::ToStr( v, buf, BUF_SIZE );
1517 SetText( buf );
1518}
1519
1520
1521void XMLElement::SetText( unsigned v )
1522{
1523 char buf[BUF_SIZE];
1524 XMLUtil::ToStr( v, buf, BUF_SIZE );
1525 SetText( buf );
1526}
1527
1528
Lee Thomason51c12712016-06-04 20:18:49 -07001529void XMLElement::SetText(int64_t v)
1530{
1531 char buf[BUF_SIZE];
1532 XMLUtil::ToStr(v, buf, BUF_SIZE);
1533 SetText(buf);
1534}
1535
1536
1537void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001538{
1539 char buf[BUF_SIZE];
1540 XMLUtil::ToStr( v, buf, BUF_SIZE );
1541 SetText( buf );
1542}
1543
1544
1545void XMLElement::SetText( float v )
1546{
1547 char buf[BUF_SIZE];
1548 XMLUtil::ToStr( v, buf, BUF_SIZE );
1549 SetText( buf );
1550}
1551
1552
1553void XMLElement::SetText( double v )
1554{
1555 char buf[BUF_SIZE];
1556 XMLUtil::ToStr( v, buf, BUF_SIZE );
1557 SetText( buf );
1558}
1559
1560
MortenMacFly4ee49f12013-01-14 20:03:14 +01001561XMLError XMLElement::QueryIntText( int* ival ) 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::ToInt( t, ival ) ) {
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::QueryUnsignedText( unsigned* uval ) 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::ToUnsigned( t, uval ) ) {
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
Lee Thomason51c12712016-06-04 20:18:49 -07001587XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1588{
1589 if (FirstChild() && FirstChild()->ToText()) {
1590 const char* t = FirstChild()->Value();
1591 if (XMLUtil::ToInt64(t, ival)) {
1592 return XML_SUCCESS;
1593 }
1594 return XML_CAN_NOT_CONVERT_TEXT;
1595 }
1596 return XML_NO_TEXT_NODE;
1597}
1598
1599
MortenMacFly4ee49f12013-01-14 20:03:14 +01001600XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001601{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001602 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001603 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001604 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001605 return XML_SUCCESS;
1606 }
1607 return XML_CAN_NOT_CONVERT_TEXT;
1608 }
1609 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001610}
1611
1612
MortenMacFly4ee49f12013-01-14 20:03:14 +01001613XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001614{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001615 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001616 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001617 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001618 return XML_SUCCESS;
1619 }
1620 return XML_CAN_NOT_CONVERT_TEXT;
1621 }
1622 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001623}
1624
1625
MortenMacFly4ee49f12013-01-14 20:03:14 +01001626XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001627{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001628 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001629 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001630 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001631 return XML_SUCCESS;
1632 }
1633 return XML_CAN_NOT_CONVERT_TEXT;
1634 }
1635 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001636}
1637
Josh Wittnercf3dd092016-10-11 18:57:17 -07001638int XMLElement::IntText(int defaultValue) const
1639{
1640 int i = defaultValue;
1641 QueryIntText(&i);
1642 return i;
1643}
1644
1645unsigned XMLElement::UnsignedText(unsigned defaultValue) const
1646{
1647 unsigned i = defaultValue;
1648 QueryUnsignedText(&i);
1649 return i;
1650}
1651
1652int64_t XMLElement::Int64Text(int64_t defaultValue) const
1653{
1654 int64_t i = defaultValue;
1655 QueryInt64Text(&i);
1656 return i;
1657}
1658
1659bool XMLElement::BoolText(bool defaultValue) const
1660{
1661 bool b = defaultValue;
1662 QueryBoolText(&b);
1663 return b;
1664}
1665
1666double XMLElement::DoubleText(double defaultValue) const
1667{
1668 double d = defaultValue;
1669 QueryDoubleText(&d);
1670 return d;
1671}
1672
1673float XMLElement::FloatText(float defaultValue) const
1674{
1675 float f = defaultValue;
1676 QueryFloatText(&f);
1677 return f;
1678}
Lee Thomason21be8822012-07-15 17:27:22 -07001679
1680
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001681XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1682{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001683 XMLAttribute* last = 0;
1684 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001685 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001686 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001687 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001688 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1689 break;
1690 }
1691 }
1692 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001693 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001694 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1695 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001696 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001697 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001698 }
1699 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001700 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001701 }
1702 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001703 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001704 }
1705 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001706}
1707
1708
U-Stream\Leeae25a442012-02-17 17:48:16 -08001709void XMLElement::DeleteAttribute( const char* name )
1710{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001711 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001712 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001713 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1714 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001715 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001716 }
1717 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001718 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001719 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001720 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001721 break;
1722 }
1723 prev = a;
1724 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001725}
1726
1727
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001728char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001729{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001730 const char* start = p;
1731 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001732
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001733 // Read the attributes.
1734 while( p ) {
1735 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001736 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001737 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001738 return 0;
1739 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001740
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001741 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001742 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001743 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001744 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1745 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001746 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001747
Lee Thomason624d43f2012-10-12 10:58:48 -07001748 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001749 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001750 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001751 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001752 return 0;
1753 }
1754 // There is a minor bug here: if the attribute in the source xml
1755 // document is duplicated, it will not be detected and the
1756 // attribute will be doubly added. However, tracking the 'prevAttribute'
1757 // avoids re-scanning the attribute list. Preferring performance for
1758 // now, may reconsider in the future.
1759 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001760 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001761 }
1762 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001763 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001764 }
1765 prevAttribute = attrib;
1766 }
1767 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001768 else if ( *p == '>' ) {
1769 ++p;
1770 break;
1771 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001772 // end of the tag
1773 else if ( *p == '/' && *(p+1) == '>' ) {
1774 _closingType = CLOSED;
1775 return p+2; // done; sealed element.
1776 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001777 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001778 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001779 return 0;
1780 }
1781 }
1782 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001783}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001784
Dmitry-Mee3225b12014-09-03 11:03:11 +04001785void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1786{
1787 if ( attribute == 0 ) {
1788 return;
1789 }
1790 MemPool* pool = attribute->_memPool;
1791 attribute->~XMLAttribute();
1792 pool->Free( attribute );
1793}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001794
Lee Thomason67d61312012-01-24 16:01:51 -08001795//
1796// <ele></ele>
1797// <ele>foo<b>bar</b></ele>
1798//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001799char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001800{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001801 // Read the element name.
1802 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001803
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001804 // The closing element is the </element> form. It is
1805 // parsed just like a regular element then deleted from
1806 // the DOM.
1807 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001808 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001809 ++p;
1810 }
Lee Thomason67d61312012-01-24 16:01:51 -08001811
Lee Thomason624d43f2012-10-12 10:58:48 -07001812 p = _value.ParseName( p );
1813 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001814 return 0;
1815 }
Lee Thomason67d61312012-01-24 16:01:51 -08001816
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001817 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001818 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001819 return p;
1820 }
Lee Thomason67d61312012-01-24 16:01:51 -08001821
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001822 p = XMLNode::ParseDeep( p, strPair );
1823 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001824}
1825
1826
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001827
1828XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1829{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001830 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001831 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001832 }
1833 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1834 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1835 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1836 }
1837 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001838}
1839
1840
1841bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1842{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001843 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001844 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001845 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001846
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001847 const XMLAttribute* a=FirstAttribute();
1848 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001849
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001850 while ( a && b ) {
1851 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1852 return false;
1853 }
1854 a = a->Next();
1855 b = b->Next();
1856 }
1857 if ( a || b ) {
1858 // different count
1859 return false;
1860 }
1861 return true;
1862 }
1863 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001864}
1865
1866
Lee Thomason751da522012-02-10 08:50:51 -08001867bool XMLElement::Accept( XMLVisitor* visitor ) const
1868{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001869 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001870 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001871 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1872 if ( !node->Accept( visitor ) ) {
1873 break;
1874 }
1875 }
1876 }
1877 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001878}
Lee Thomason56bdd022012-02-09 18:16:58 -08001879
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001880
Lee Thomason3f57d272012-01-11 15:30:03 -08001881// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001882
1883// Warning: List must match 'enum XMLError'
1884const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1885 "XML_SUCCESS",
1886 "XML_NO_ATTRIBUTE",
1887 "XML_WRONG_ATTRIBUTE_TYPE",
1888 "XML_ERROR_FILE_NOT_FOUND",
1889 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1890 "XML_ERROR_FILE_READ_ERROR",
1891 "XML_ERROR_ELEMENT_MISMATCH",
1892 "XML_ERROR_PARSING_ELEMENT",
1893 "XML_ERROR_PARSING_ATTRIBUTE",
1894 "XML_ERROR_IDENTIFYING_TAG",
1895 "XML_ERROR_PARSING_TEXT",
1896 "XML_ERROR_PARSING_CDATA",
1897 "XML_ERROR_PARSING_COMMENT",
1898 "XML_ERROR_PARSING_DECLARATION",
1899 "XML_ERROR_PARSING_UNKNOWN",
1900 "XML_ERROR_EMPTY_DOCUMENT",
1901 "XML_ERROR_MISMATCHED_ELEMENT",
1902 "XML_ERROR_PARSING",
1903 "XML_CAN_NOT_CONVERT_TEXT",
1904 "XML_NO_TEXT_NODE"
1905};
1906
1907
Lee Thomason624d43f2012-10-12 10:58:48 -07001908XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001909 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001910 _writeBOM( false ),
1911 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07001912 _errorID(XML_SUCCESS),
Lee Thomason624d43f2012-10-12 10:58:48 -07001913 _whitespace( whitespace ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001914 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001915{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03001916 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
1917 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08001918}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001919
1920
Lee Thomason3f57d272012-01-11 15:30:03 -08001921XMLDocument::~XMLDocument()
1922{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001923 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001924}
1925
1926
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001927void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001928{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001929 DeleteChildren();
1930
Dmitry-Meab37df82014-11-28 12:08:36 +03001931#ifdef DEBUG
1932 const bool hadError = Error();
1933#endif
Lee Thomason85536252016-06-04 19:10:53 -07001934 _errorID = XML_SUCCESS;
Lee Thomason584af572016-09-05 14:14:16 -07001935 _errorStr1.Reset();
1936 _errorStr2.Reset();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001937
Lee Thomason624d43f2012-10-12 10:58:48 -07001938 delete [] _charBuffer;
1939 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001940
1941#if 0
1942 _textPool.Trace( "text" );
1943 _elementPool.Trace( "element" );
1944 _commentPool.Trace( "comment" );
1945 _attributePool.Trace( "attribute" );
1946#endif
1947
1948#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001949 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001950 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1951 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1952 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1953 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1954 }
1955#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001956}
1957
Lee Thomason3f57d272012-01-11 15:30:03 -08001958
Lee Thomason2c85a712012-01-31 08:24:24 -08001959XMLElement* XMLDocument::NewElement( const char* name )
1960{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001961 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001962 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1963 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001964 ele->SetName( name );
1965 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001966}
1967
1968
Lee Thomason1ff38e02012-02-14 18:18:16 -08001969XMLComment* XMLDocument::NewComment( const char* str )
1970{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001971 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001972 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1973 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001974 comment->SetValue( str );
1975 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001976}
1977
1978
1979XMLText* XMLDocument::NewText( const char* str )
1980{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001981 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001982 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1983 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001984 text->SetValue( str );
1985 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001986}
1987
1988
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001989XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1990{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001991 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001992 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1993 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001994 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1995 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001996}
1997
1998
1999XMLUnknown* XMLDocument::NewUnknown( const char* str )
2000{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03002001 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07002002 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
2003 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002004 unk->SetValue( str );
2005 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002006}
2007
Dmitry-Me01578db2014-08-19 10:18:48 +04002008static FILE* callfopen( const char* filepath, const char* mode )
2009{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002010 TIXMLASSERT( filepath );
2011 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002012#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2013 FILE* fp = 0;
2014 errno_t err = fopen_s( &fp, filepath, mode );
2015 if ( err ) {
2016 return 0;
2017 }
2018#else
2019 FILE* fp = fopen( filepath, mode );
2020#endif
2021 return fp;
2022}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08002023
2024void XMLDocument::DeleteNode( XMLNode* node ) {
2025 TIXMLASSERT( node );
2026 TIXMLASSERT(node->_document == this );
2027 if (node->_parent) {
2028 node->_parent->DeleteChild( node );
2029 }
2030 else {
2031 // Isn't in the tree.
2032 // Use the parent delete.
2033 // Also, we need to mark it tracked: we 'know'
2034 // it was never used.
2035 node->_memPool->SetTracked();
2036 // Call the static XMLNode version:
2037 XMLNode::DeleteNode(node);
2038 }
2039}
2040
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002041
Lee Thomason2fa81722012-11-09 12:37:46 -08002042XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002043{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002044 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04002045 FILE* fp = callfopen( filename, "rb" );
2046 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002047 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002048 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002049 }
2050 LoadFile( fp );
2051 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002052 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002053}
2054
Dmitry-Me901fed52015-09-25 10:29:51 +03002055// This is likely overengineered template art to have a check that unsigned long value incremented
2056// by one still fits into size_t. If size_t type is larger than unsigned long type
2057// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
2058// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
2059// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
2060// types sizes relate to each other.
2061template
2062<bool = (sizeof(unsigned long) >= sizeof(size_t))>
2063struct LongFitsIntoSizeTMinusOne {
2064 static bool Fits( unsigned long value )
2065 {
2066 return value < (size_t)-1;
2067 }
2068};
2069
2070template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02002071struct LongFitsIntoSizeTMinusOne<false> {
2072 static bool Fits( unsigned long )
2073 {
2074 return true;
2075 }
2076};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002077
Lee Thomason2fa81722012-11-09 12:37:46 -08002078XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002079{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002080 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002081
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002082 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002083 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002084 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2085 return _errorID;
2086 }
2087
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002088 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002089 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002090 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002091 if ( filelength == -1L ) {
2092 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2093 return _errorID;
2094 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002095 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002096
Dmitry-Me901fed52015-09-25 10:29:51 +03002097 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002098 // Cannot handle files which won't fit in buffer together with null terminator
2099 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2100 return _errorID;
2101 }
2102
Dmitry-Me72801b82015-05-07 09:41:39 +03002103 if ( filelength == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06002104 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002105 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002106 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002107
Dmitry-Me72801b82015-05-07 09:41:39 +03002108 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002109 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002110 _charBuffer = new char[size+1];
2111 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002112 if ( read != size ) {
2113 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002114 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002115 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002116
Lee Thomason624d43f2012-10-12 10:58:48 -07002117 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002118
Dmitry-Me97476b72015-01-01 16:15:57 +03002119 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002120 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002121}
2122
2123
Lee Thomason2fa81722012-11-09 12:37:46 -08002124XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002125{
Dmitry-Me01578db2014-08-19 10:18:48 +04002126 FILE* fp = callfopen( filename, "w" );
2127 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002128 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002129 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002130 }
2131 SaveFile(fp, compact);
2132 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002133 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002134}
2135
2136
Lee Thomason2fa81722012-11-09 12:37:46 -08002137XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002138{
Ant Mitchell189198f2015-03-24 16:20:36 +00002139 // Clear any error from the last save, otherwise it will get reported
2140 // for *this* call.
Lee Thomason85536252016-06-04 19:10:53 -07002141 SetError(XML_SUCCESS, 0, 0);
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002142 XMLPrinter stream( fp, compact );
2143 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002144 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002145}
2146
Lee Thomason1ff38e02012-02-14 18:18:16 -08002147
Lee Thomason2fa81722012-11-09 12:37:46 -08002148XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002149{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002150 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002151
Lee Thomason82d32002014-02-21 22:47:18 -08002152 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002153 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002154 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002155 }
2156 if ( len == (size_t)(-1) ) {
2157 len = strlen( p );
2158 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002159 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002160 _charBuffer = new char[ len+1 ];
2161 memcpy( _charBuffer, p, len );
2162 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002163
Dmitry-Me97476b72015-01-01 16:15:57 +03002164 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002165 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002166 // clean up now essentially dangling memory.
2167 // and the parse fail can put objects in the
2168 // pools that are dead and inaccessible.
2169 DeleteChildren();
2170 _elementPool.Clear();
2171 _attributePool.Clear();
2172 _textPool.Clear();
2173 _commentPool.Clear();
2174 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002175 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002176}
2177
2178
PKEuS1c5f99e2013-07-06 11:28:39 +02002179void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002180{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002181 if ( streamer ) {
2182 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002183 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002184 else {
2185 XMLPrinter stdoutStreamer( stdout );
2186 Accept( &stdoutStreamer );
2187 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002188}
2189
2190
Lee Thomason2fa81722012-11-09 12:37:46 -08002191void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08002192{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002193 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002194 _errorID = error;
Lee Thomason584af572016-09-05 14:14:16 -07002195
2196 _errorStr1.Reset();
2197 _errorStr2.Reset();
2198
2199 if (str1)
2200 _errorStr1.SetStr(str1);
2201 if (str2)
2202 _errorStr2.SetStr(str2);
Lee Thomason67d61312012-01-24 16:01:51 -08002203}
2204
Lee Thomason331596e2014-09-11 14:56:43 -07002205const char* XMLDocument::ErrorName() const
2206{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002207 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002208 const char* errorName = _errorNames[_errorID];
2209 TIXMLASSERT( errorName && errorName[0] );
2210 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002211}
Lee Thomason5cae8972012-01-24 18:03:07 -08002212
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002213void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002214{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002215 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002216 static const int LEN = 20;
2217 char buf1[LEN] = { 0 };
2218 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002219
Lee Thomason584af572016-09-05 14:14:16 -07002220 if ( !_errorStr1.Empty() ) {
2221 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002222 }
Lee Thomason584af572016-09-05 14:14:16 -07002223 if ( !_errorStr2.Empty() ) {
2224 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002225 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002226
Dmitry-Me2ad43202015-04-16 12:18:58 +03002227 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2228 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2229 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
Lee Thomason331596e2014-09-11 14:56:43 -07002230 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
Dmitry-Me400f1192015-04-07 11:51:21 +03002231 static_cast<int>( _errorID ), ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002232 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002233}
2234
Dmitry-Me97476b72015-01-01 16:15:57 +03002235void XMLDocument::Parse()
2236{
2237 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2238 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08002239 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03002240 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03002241 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002242 if ( !*p ) {
2243 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2244 return;
2245 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08002246 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002247}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002248
PKEuS1bfb9542013-08-04 13:51:17 +02002249XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002250 _elementJustOpened( false ),
2251 _firstElement( true ),
2252 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002253 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002254 _textDepth( -1 ),
2255 _processEntities( true ),
2256 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002257{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002258 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002259 _entityFlag[i] = false;
2260 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002261 }
2262 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002263 const char entityValue = entities[i].value;
2264 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
2265 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002266 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002267 _restrictedEntityFlag[(unsigned char)'&'] = true;
2268 _restrictedEntityFlag[(unsigned char)'<'] = true;
2269 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002270 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002271}
2272
2273
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002274void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002275{
2276 va_list va;
2277 va_start( va, format );
2278
Lee Thomason624d43f2012-10-12 10:58:48 -07002279 if ( _fp ) {
2280 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002281 }
2282 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002283 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002284 // Close out and re-start the va-args
2285 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002286 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002287 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002288 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002289 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002290 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002291 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002292 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002293}
2294
2295
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002296void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002297{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002298 for( int i=0; i<depth; ++i ) {
2299 Print( " " );
2300 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002301}
2302
2303
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002304void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002305{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002306 // Look for runs of bytes between entities to print.
2307 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002308
Lee Thomason624d43f2012-10-12 10:58:48 -07002309 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002310 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002311 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002312 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002313 // Remember, char is sometimes signed. (How many times has that bitten me?)
2314 if ( *q > 0 && *q < ENTITY_RANGE ) {
2315 // Check for entities. If one is found, flush
2316 // the stream up until the entity, write the
2317 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002318 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002319 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002320 const size_t delta = q - p;
2321 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002322 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002323 Print( "%.*s", toPrint, p );
2324 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002325 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002326 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002327 for( int i=0; i<NUM_ENTITIES; ++i ) {
2328 if ( entities[i].value == *q ) {
2329 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002330 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002331 break;
2332 }
2333 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002334 if ( !entityPatternPrinted ) {
2335 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2336 TIXMLASSERT( false );
2337 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002338 ++p;
2339 }
2340 }
2341 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002342 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002343 }
2344 }
2345 // Flush the remaining string. This will be the entire
2346 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002347 TIXMLASSERT( p <= q );
2348 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002349 Print( "%s", p );
2350 }
Lee Thomason857b8682012-01-25 17:50:25 -08002351}
2352
U-Stream\Leeae25a442012-02-17 17:48:16 -08002353
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002354void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002355{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002356 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002357 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 -07002358 Print( "%s", bom );
2359 }
2360 if ( writeDec ) {
2361 PushDeclaration( "xml version=\"1.0\"" );
2362 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002363}
2364
2365
Uli Kusterer593a33d2014-02-01 12:48:51 +01002366void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002367{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002368 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002369 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002370
Uli Kusterer593a33d2014-02-01 12:48:51 +01002371 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002372 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002373 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002374 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002375 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002376 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002377
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002378 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002379 _elementJustOpened = true;
2380 _firstElement = false;
2381 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002382}
2383
2384
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002385void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002386{
Lee Thomason624d43f2012-10-12 10:58:48 -07002387 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002388 Print( " %s=\"", name );
2389 PrintString( value, false );
2390 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002391}
2392
2393
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002394void XMLPrinter::PushAttribute( const char* name, int v )
2395{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002396 char buf[BUF_SIZE];
2397 XMLUtil::ToStr( v, buf, BUF_SIZE );
2398 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002399}
2400
2401
2402void XMLPrinter::PushAttribute( const char* name, unsigned v )
2403{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002404 char buf[BUF_SIZE];
2405 XMLUtil::ToStr( v, buf, BUF_SIZE );
2406 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002407}
2408
2409
Lee Thomason51c12712016-06-04 20:18:49 -07002410void XMLPrinter::PushAttribute(const char* name, int64_t v)
2411{
2412 char buf[BUF_SIZE];
2413 XMLUtil::ToStr(v, buf, BUF_SIZE);
2414 PushAttribute(name, buf);
2415}
2416
2417
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002418void XMLPrinter::PushAttribute( const char* name, bool v )
2419{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002420 char buf[BUF_SIZE];
2421 XMLUtil::ToStr( v, buf, BUF_SIZE );
2422 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002423}
2424
2425
2426void XMLPrinter::PushAttribute( const char* name, double v )
2427{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002428 char buf[BUF_SIZE];
2429 XMLUtil::ToStr( v, buf, BUF_SIZE );
2430 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002431}
2432
2433
Uli Kustererca412e82014-02-01 13:35:05 +01002434void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002435{
Lee Thomason624d43f2012-10-12 10:58:48 -07002436 --_depth;
2437 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002438
Lee Thomason624d43f2012-10-12 10:58:48 -07002439 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002440 Print( "/>" );
2441 }
2442 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002443 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002444 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002445 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002446 }
2447 Print( "</%s>", name );
2448 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002449
Lee Thomason624d43f2012-10-12 10:58:48 -07002450 if ( _textDepth == _depth ) {
2451 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002452 }
Uli Kustererca412e82014-02-01 13:35:05 +01002453 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002454 Print( "\n" );
2455 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002456 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002457}
2458
2459
Dmitry-Mea092bc12014-12-23 17:57:05 +03002460void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002461{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002462 if ( !_elementJustOpened ) {
2463 return;
2464 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002465 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002466 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002467}
2468
2469
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002470void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002471{
Lee Thomason624d43f2012-10-12 10:58:48 -07002472 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002473
Dmitry-Mea092bc12014-12-23 17:57:05 +03002474 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002475 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002476 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002477 }
2478 else {
2479 PrintString( text, true );
2480 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002481}
2482
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002483void XMLPrinter::PushText( int64_t value )
2484{
2485 char buf[BUF_SIZE];
2486 XMLUtil::ToStr( value, buf, BUF_SIZE );
2487 PushText( buf, false );
2488}
2489
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002490void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002491{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002492 char buf[BUF_SIZE];
2493 XMLUtil::ToStr( value, buf, BUF_SIZE );
2494 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002495}
2496
2497
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002498void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002499{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002500 char buf[BUF_SIZE];
2501 XMLUtil::ToStr( value, buf, BUF_SIZE );
2502 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002503}
2504
2505
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002506void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002507{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002508 char buf[BUF_SIZE];
2509 XMLUtil::ToStr( value, buf, BUF_SIZE );
2510 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002511}
2512
2513
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002514void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002515{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002516 char buf[BUF_SIZE];
2517 XMLUtil::ToStr( value, buf, BUF_SIZE );
2518 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002519}
2520
2521
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002522void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002523{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002524 char buf[BUF_SIZE];
2525 XMLUtil::ToStr( value, buf, BUF_SIZE );
2526 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002527}
2528
Lee Thomason5cae8972012-01-24 18:03:07 -08002529
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002530void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002531{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002532 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002533 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002534 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002535 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002536 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002537 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002538 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002539}
Lee Thomason751da522012-02-10 08:50:51 -08002540
2541
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002542void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002543{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002544 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002545 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002546 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002547 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002548 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002549 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002550 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002551}
2552
2553
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002554void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002555{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002556 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002557 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002558 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002559 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002560 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002561 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002562 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002563}
2564
2565
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002566bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002567{
Lee Thomason624d43f2012-10-12 10:58:48 -07002568 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002569 if ( doc.HasBOM() ) {
2570 PushHeader( true, false );
2571 }
2572 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002573}
2574
2575
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002576bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002577{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002578 const XMLElement* parentElem = 0;
2579 if ( element.Parent() ) {
2580 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002581 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002582 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002583 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002584 while ( attribute ) {
2585 PushAttribute( attribute->Name(), attribute->Value() );
2586 attribute = attribute->Next();
2587 }
2588 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002589}
2590
2591
Uli Kustererca412e82014-02-01 13:35:05 +01002592bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002593{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002594 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002595 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002596}
2597
2598
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002599bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002600{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002601 PushText( text.Value(), text.CData() );
2602 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002603}
2604
2605
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002606bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002607{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002608 PushComment( comment.Value() );
2609 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002610}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002611
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002612bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002613{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002614 PushDeclaration( declaration.Value() );
2615 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002616}
2617
2618
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002619bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002620{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002621 PushUnknown( unknown.Value() );
2622 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002623}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002624
Lee Thomason685b8952012-11-12 13:00:06 -08002625} // namespace tinyxml2
2626