blob: 1717e0a21c9e3e5f57aa8ab9eef1cfbffb3c0d88 [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 ) {
Lee Thomason120b3a62012-10-12 10:06:59 -0700240 char* p = _start; // the read pointer
241 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 ) {
270 char* p = _start; // the read pointer
271 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{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700541 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
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{
Lee Thomason85492022015-05-22 11:07:45 -0700742 // Catch an edge case: XMLDocuments don't have a a Value. Carefully return nullptr.
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-Meabb2d042014-12-09 12:59:31 +0300763 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700764 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700765 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700766
Dmitry-Mee3225b12014-09-03 11:03:11 +0400767 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700768 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700769 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800770}
771
772
773void XMLNode::Unlink( XMLNode* child )
774{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300775 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300776 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300777 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700778 if ( child == _firstChild ) {
779 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700780 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700781 if ( child == _lastChild ) {
782 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700783 }
Lee Thomasond923c672012-01-23 08:44:25 -0800784
Lee Thomason624d43f2012-10-12 10:58:48 -0700785 if ( child->_prev ) {
786 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700787 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700788 if ( child->_next ) {
789 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700790 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700791 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800792}
793
794
U-Stream\Leeae25a442012-02-17 17:48:16 -0800795void XMLNode::DeleteChild( XMLNode* node )
796{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300797 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300798 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700799 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100800 Unlink( node );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400801 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800802}
803
804
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800805XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
806{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300807 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300808 if ( addThis->_document != _document ) {
809 TIXMLASSERT( false );
810 return 0;
811 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800812 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700813
Lee Thomason624d43f2012-10-12 10:58:48 -0700814 if ( _lastChild ) {
815 TIXMLASSERT( _firstChild );
816 TIXMLASSERT( _lastChild->_next == 0 );
817 _lastChild->_next = addThis;
818 addThis->_prev = _lastChild;
819 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800820
Lee Thomason624d43f2012-10-12 10:58:48 -0700821 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700822 }
823 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700824 TIXMLASSERT( _firstChild == 0 );
825 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800826
Lee Thomason624d43f2012-10-12 10:58:48 -0700827 addThis->_prev = 0;
828 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700829 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700830 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700831 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800832}
833
834
Lee Thomason1ff38e02012-02-14 18:18:16 -0800835XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
836{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300837 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300838 if ( addThis->_document != _document ) {
839 TIXMLASSERT( false );
840 return 0;
841 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800842 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700843
Lee Thomason624d43f2012-10-12 10:58:48 -0700844 if ( _firstChild ) {
845 TIXMLASSERT( _lastChild );
846 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800847
Lee Thomason624d43f2012-10-12 10:58:48 -0700848 _firstChild->_prev = addThis;
849 addThis->_next = _firstChild;
850 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800851
Lee Thomason624d43f2012-10-12 10:58:48 -0700852 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700853 }
854 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700855 TIXMLASSERT( _lastChild == 0 );
856 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800857
Lee Thomason624d43f2012-10-12 10:58:48 -0700858 addThis->_prev = 0;
859 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700860 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700861 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400862 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800863}
864
865
866XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
867{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300868 TIXMLASSERT( addThis );
869 if ( addThis->_document != _document ) {
870 TIXMLASSERT( false );
871 return 0;
872 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700873
Dmitry-Meabb2d042014-12-09 12:59:31 +0300874 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700875
Lee Thomason624d43f2012-10-12 10:58:48 -0700876 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300877 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700878 return 0;
879 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800880
Lee Thomason624d43f2012-10-12 10:58:48 -0700881 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700882 // The last node or the only node.
883 return InsertEndChild( addThis );
884 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800885 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700886 addThis->_prev = afterThis;
887 addThis->_next = afterThis->_next;
888 afterThis->_next->_prev = addThis;
889 afterThis->_next = addThis;
890 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700891 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800892}
893
894
895
896
Dmitry-Me886ad972015-07-22 11:00:51 +0300897const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800898{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300899 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
900 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700901 if ( element ) {
Dmitry-Me886ad972015-07-22 11:00:51 +0300902 if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700903 return element;
904 }
905 }
906 }
907 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800908}
909
910
Dmitry-Me886ad972015-07-22 11:00:51 +0300911const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800912{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300913 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
914 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700915 if ( element ) {
Dmitry-Me886ad972015-07-22 11:00:51 +0300916 if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700917 return element;
918 }
919 }
920 }
921 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800922}
923
924
Dmitry-Me886ad972015-07-22 11:00:51 +0300925const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800926{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300927 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400928 const XMLElement* element = node->ToElement();
929 if ( element
Dmitry-Me886ad972015-07-22 11:00:51 +0300930 && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400931 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700932 }
933 }
934 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800935}
936
937
Dmitry-Me886ad972015-07-22 11:00:51 +0300938const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800939{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300940 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400941 const XMLElement* element = node->ToElement();
942 if ( element
Dmitry-Me886ad972015-07-22 11:00:51 +0300943 && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400944 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700945 }
946 }
947 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800948}
949
950
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800951char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800952{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700953 // This is a recursive method, but thinking about it "at the current level"
954 // it is a pretty simple flat list:
955 // <foo/>
956 // <!-- comment -->
957 //
958 // With a special case:
959 // <foo>
960 // </foo>
961 // <!-- comment -->
962 //
963 // Where the closing element (/foo) *must* be the next thing after the opening
964 // element, and the names must match. BUT the tricky bit is that the closing
965 // element will be read by the child.
966 //
967 // 'endTag' is the end tag for this node, it is returned by a call to a child.
968 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800969
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700970 while( p && *p ) {
971 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800972
Lee Thomason624d43f2012-10-12 10:58:48 -0700973 p = _document->Identify( p, &node );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300974 if ( node == 0 ) {
975 break;
976 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800977
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700978 StrPair endTag;
979 p = node->ParseDeep( p, &endTag );
980 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400981 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700982 if ( !_document->Error() ) {
983 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700984 }
985 break;
986 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800987
Sarat Addepalli3df007e2015-05-20 10:43:51 +0530988 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530989 if ( decl ) {
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530990 // A declaration can only be the first child of a document.
991 // Set error, if document already has children.
992 if ( !_document->NoChildren() ) {
993 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0);
994 DeleteNode( decl );
995 break;
996 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530997 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530998
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400999 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001000 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -05001001 // We read the end tag. Return it to the parent.
1002 if ( ele->ClosingType() == XMLElement::CLOSING ) {
1003 if ( parentEnd ) {
1004 ele->_value.TransferTo( parentEnd );
1005 }
1006 node->_memPool->SetTracked(); // created and then immediately deleted.
1007 DeleteNode( node );
1008 return p;
1009 }
1010
1011 // Handle an end tag returned to this level.
1012 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001013 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001014 if ( endTag.Empty() ) {
1015 if ( ele->ClosingType() == XMLElement::OPEN ) {
1016 mismatch = true;
1017 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001018 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001019 else {
1020 if ( ele->ClosingType() != XMLElement::OPEN ) {
1021 mismatch = true;
1022 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001023 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001024 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001025 }
1026 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001027 if ( mismatch ) {
Dmitry-Me886ad972015-07-22 11:00:51 +03001028 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -05001029 DeleteNode( node );
1030 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001031 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001032 }
JayXondbfdd8f2014-12-12 20:07:14 -05001033 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001034 }
1035 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001036}
1037
Dmitry-Mee3225b12014-09-03 11:03:11 +04001038void XMLNode::DeleteNode( XMLNode* node )
1039{
1040 if ( node == 0 ) {
1041 return;
1042 }
1043 MemPool* pool = node->_memPool;
1044 node->~XMLNode();
1045 pool->Free( node );
1046}
1047
Lee Thomason3cebdc42015-01-05 17:16:28 -08001048void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001049{
1050 TIXMLASSERT( insertThis );
1051 TIXMLASSERT( insertThis->_document == _document );
1052
1053 if ( insertThis->_parent )
1054 insertThis->_parent->Unlink( insertThis );
1055 else
1056 insertThis->_memPool->SetTracked();
1057}
1058
Lee Thomason5492a1c2012-01-23 15:32:10 -08001059// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001060char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001061{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001062 const char* start = p;
1063 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001064 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001065 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001066 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001067 }
1068 return p;
1069 }
1070 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001071 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1072 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001073 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001074 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001075
Lee Thomason624d43f2012-10-12 10:58:48 -07001076 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001077 if ( p && *p ) {
1078 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001079 }
1080 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +03001081 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001082 }
1083 }
1084 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001085}
1086
1087
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001088XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1089{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001090 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001091 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001092 }
1093 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1094 text->SetCData( this->CData() );
1095 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001096}
1097
1098
1099bool XMLText::ShallowEqual( const XMLNode* compare ) const
1100{
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001101 const XMLText* text = compare->ToText();
1102 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001103}
1104
1105
Lee Thomason56bdd022012-02-09 18:16:58 -08001106bool XMLText::Accept( XMLVisitor* visitor ) const
1107{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001108 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001109 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001110}
1111
1112
Lee Thomason3f57d272012-01-11 15:30:03 -08001113// --------- XMLComment ---------- //
1114
Lee Thomasone4422302012-01-20 17:59:50 -08001115XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001116{
1117}
1118
1119
Lee Thomasonce0763e2012-01-11 15:43:54 -08001120XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001121{
Lee Thomason3f57d272012-01-11 15:30:03 -08001122}
1123
1124
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001125char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -08001126{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001127 // Comment parses as text.
1128 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001129 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001130 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001131 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001132 }
1133 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001134}
1135
1136
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001137XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1138{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001139 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001140 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001141 }
1142 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1143 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001144}
1145
1146
1147bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1148{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001149 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001150 const XMLComment* comment = compare->ToComment();
1151 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001152}
1153
1154
Lee Thomason751da522012-02-10 08:50:51 -08001155bool XMLComment::Accept( XMLVisitor* visitor ) const
1156{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001157 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001158 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001159}
Lee Thomason56bdd022012-02-09 18:16:58 -08001160
1161
Lee Thomason50f97b22012-02-11 16:33:40 -08001162// --------- XMLDeclaration ---------- //
1163
1164XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1165{
1166}
1167
1168
1169XMLDeclaration::~XMLDeclaration()
1170{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001171 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001172}
1173
1174
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001175char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001176{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001177 // Declaration parses as text.
1178 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001179 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001180 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001181 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001182 }
1183 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001184}
1185
1186
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001187XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1188{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001189 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001190 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001191 }
1192 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1193 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001194}
1195
1196
1197bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1198{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001199 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001200 const XMLDeclaration* declaration = compare->ToDeclaration();
1201 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001202}
1203
1204
1205
Lee Thomason50f97b22012-02-11 16:33:40 -08001206bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1207{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001208 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001209 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001210}
1211
1212// --------- XMLUnknown ---------- //
1213
1214XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1215{
1216}
1217
1218
1219XMLUnknown::~XMLUnknown()
1220{
1221}
1222
1223
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001224char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001225{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001226 // Unknown parses as text.
1227 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001228
Lee Thomason624d43f2012-10-12 10:58:48 -07001229 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001230 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001231 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001232 }
1233 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001234}
1235
1236
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001237XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1238{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001239 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001240 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001241 }
1242 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1243 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001244}
1245
1246
1247bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1248{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001249 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001250 const XMLUnknown* unknown = compare->ToUnknown();
1251 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001252}
1253
1254
Lee Thomason50f97b22012-02-11 16:33:40 -08001255bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1256{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001257 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001258 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001259}
1260
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001261// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001262
1263const char* XMLAttribute::Name() const
1264{
1265 return _name.GetStr();
1266}
1267
1268const char* XMLAttribute::Value() const
1269{
1270 return _value.GetStr();
1271}
1272
Lee Thomason6f381b72012-03-02 12:59:39 -08001273char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001274{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001275 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001276 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001277 if ( !p || !*p ) {
1278 return 0;
1279 }
Lee Thomason22aead12012-01-23 13:29:35 -08001280
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001281 // Skip white space before =
1282 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001283 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001284 return 0;
1285 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001286
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001287 ++p; // move up to opening quote
1288 p = XMLUtil::SkipWhiteSpace( p );
1289 if ( *p != '\"' && *p != '\'' ) {
1290 return 0;
1291 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001292
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001293 char endTag[2] = { *p, 0 };
1294 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001295
Lee Thomason624d43f2012-10-12 10:58:48 -07001296 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001297 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001298}
1299
1300
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001301void XMLAttribute::SetName( const char* n )
1302{
Lee Thomason624d43f2012-10-12 10:58:48 -07001303 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001304}
1305
1306
Lee Thomason2fa81722012-11-09 12:37:46 -08001307XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001308{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001309 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001310 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001311 }
1312 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001313}
1314
1315
Lee Thomason2fa81722012-11-09 12:37:46 -08001316XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001317{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001318 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001319 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001320 }
1321 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001322}
1323
1324
Lee Thomason51c12712016-06-04 20:18:49 -07001325XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1326{
1327 if (XMLUtil::ToInt64(Value(), value)) {
1328 return XML_SUCCESS;
1329 }
1330 return XML_WRONG_ATTRIBUTE_TYPE;
1331}
1332
1333
Lee Thomason2fa81722012-11-09 12:37:46 -08001334XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001335{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001336 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001337 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001338 }
1339 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001340}
1341
1342
Lee Thomason2fa81722012-11-09 12:37:46 -08001343XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001344{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001345 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001346 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001347 }
1348 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001349}
1350
1351
Lee Thomason2fa81722012-11-09 12:37:46 -08001352XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001353{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001354 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001355 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001356 }
1357 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001358}
1359
1360
1361void XMLAttribute::SetAttribute( const char* v )
1362{
Lee Thomason624d43f2012-10-12 10:58:48 -07001363 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001364}
1365
1366
Lee Thomason1ff38e02012-02-14 18:18:16 -08001367void XMLAttribute::SetAttribute( int v )
1368{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001369 char buf[BUF_SIZE];
1370 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001371 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001372}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001373
1374
1375void XMLAttribute::SetAttribute( unsigned v )
1376{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001377 char buf[BUF_SIZE];
1378 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001379 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001380}
1381
1382
Lee Thomason51c12712016-06-04 20:18:49 -07001383void XMLAttribute::SetAttribute(int64_t v)
1384{
1385 char buf[BUF_SIZE];
1386 XMLUtil::ToStr(v, buf, BUF_SIZE);
1387 _value.SetStr(buf);
1388}
1389
1390
1391
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001392void XMLAttribute::SetAttribute( bool v )
1393{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001394 char buf[BUF_SIZE];
1395 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001396 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001397}
1398
1399void XMLAttribute::SetAttribute( double v )
1400{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001401 char buf[BUF_SIZE];
1402 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001403 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001404}
1405
1406void XMLAttribute::SetAttribute( float v )
1407{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001408 char buf[BUF_SIZE];
1409 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001410 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001411}
1412
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001413
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001414// --------- XMLElement ---------- //
1415XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001416 _closingType( 0 ),
1417 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001418{
1419}
1420
1421
1422XMLElement::~XMLElement()
1423{
Lee Thomason624d43f2012-10-12 10:58:48 -07001424 while( _rootAttribute ) {
1425 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001426 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001427 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001428 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001429}
1430
1431
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001432const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1433{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001434 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001435 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1436 return a;
1437 }
1438 }
1439 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001440}
1441
1442
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001443const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001444{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001445 const XMLAttribute* a = FindAttribute( name );
1446 if ( !a ) {
1447 return 0;
1448 }
1449 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1450 return a->Value();
1451 }
1452 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001453}
1454
1455
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001456const char* XMLElement::GetText() const
1457{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001458 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001459 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001460 }
1461 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001462}
1463
1464
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001465void XMLElement::SetText( const char* inText )
1466{
Uli Kusterer869bb592014-01-21 01:36:16 +01001467 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001468 FirstChild()->SetValue( inText );
1469 else {
1470 XMLText* theText = GetDocument()->NewText( inText );
1471 InsertFirstChild( theText );
1472 }
1473}
1474
Lee Thomason5bb2d802014-01-24 10:42:57 -08001475
1476void XMLElement::SetText( int v )
1477{
1478 char buf[BUF_SIZE];
1479 XMLUtil::ToStr( v, buf, BUF_SIZE );
1480 SetText( buf );
1481}
1482
1483
1484void XMLElement::SetText( unsigned v )
1485{
1486 char buf[BUF_SIZE];
1487 XMLUtil::ToStr( v, buf, BUF_SIZE );
1488 SetText( buf );
1489}
1490
1491
Lee Thomason51c12712016-06-04 20:18:49 -07001492void XMLElement::SetText(int64_t v)
1493{
1494 char buf[BUF_SIZE];
1495 XMLUtil::ToStr(v, buf, BUF_SIZE);
1496 SetText(buf);
1497}
1498
1499
1500void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001501{
1502 char buf[BUF_SIZE];
1503 XMLUtil::ToStr( v, buf, BUF_SIZE );
1504 SetText( buf );
1505}
1506
1507
1508void XMLElement::SetText( float v )
1509{
1510 char buf[BUF_SIZE];
1511 XMLUtil::ToStr( v, buf, BUF_SIZE );
1512 SetText( buf );
1513}
1514
1515
1516void XMLElement::SetText( double v )
1517{
1518 char buf[BUF_SIZE];
1519 XMLUtil::ToStr( v, buf, BUF_SIZE );
1520 SetText( buf );
1521}
1522
1523
MortenMacFly4ee49f12013-01-14 20:03:14 +01001524XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001525{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001526 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001527 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001528 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001529 return XML_SUCCESS;
1530 }
1531 return XML_CAN_NOT_CONVERT_TEXT;
1532 }
1533 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001534}
1535
1536
MortenMacFly4ee49f12013-01-14 20:03:14 +01001537XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001538{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001539 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001540 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001541 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001542 return XML_SUCCESS;
1543 }
1544 return XML_CAN_NOT_CONVERT_TEXT;
1545 }
1546 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001547}
1548
1549
Lee Thomason51c12712016-06-04 20:18:49 -07001550XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1551{
1552 if (FirstChild() && FirstChild()->ToText()) {
1553 const char* t = FirstChild()->Value();
1554 if (XMLUtil::ToInt64(t, ival)) {
1555 return XML_SUCCESS;
1556 }
1557 return XML_CAN_NOT_CONVERT_TEXT;
1558 }
1559 return XML_NO_TEXT_NODE;
1560}
1561
1562
MortenMacFly4ee49f12013-01-14 20:03:14 +01001563XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001564{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001565 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001566 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001567 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001568 return XML_SUCCESS;
1569 }
1570 return XML_CAN_NOT_CONVERT_TEXT;
1571 }
1572 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001573}
1574
1575
MortenMacFly4ee49f12013-01-14 20:03:14 +01001576XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001577{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001578 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001579 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001580 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001581 return XML_SUCCESS;
1582 }
1583 return XML_CAN_NOT_CONVERT_TEXT;
1584 }
1585 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001586}
1587
1588
MortenMacFly4ee49f12013-01-14 20:03:14 +01001589XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001590{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001591 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001592 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001593 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001594 return XML_SUCCESS;
1595 }
1596 return XML_CAN_NOT_CONVERT_TEXT;
1597 }
1598 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001599}
1600
1601
1602
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001603XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1604{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001605 XMLAttribute* last = 0;
1606 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001607 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001608 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001609 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001610 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1611 break;
1612 }
1613 }
1614 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001615 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001616 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1617 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001618 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001619 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001620 }
1621 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001622 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001623 }
1624 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001625 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001626 }
1627 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001628}
1629
1630
U-Stream\Leeae25a442012-02-17 17:48:16 -08001631void XMLElement::DeleteAttribute( const char* name )
1632{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001633 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001634 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001635 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1636 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001637 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001638 }
1639 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001640 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001641 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001642 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001643 break;
1644 }
1645 prev = a;
1646 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001647}
1648
1649
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001650char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001651{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001652 const char* start = p;
1653 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001654
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001655 // Read the attributes.
1656 while( p ) {
1657 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001658 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001659 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001660 return 0;
1661 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001662
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001663 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001664 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001665 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001666 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1667 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001668 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001669
Lee Thomason624d43f2012-10-12 10:58:48 -07001670 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001671 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001672 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001673 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001674 return 0;
1675 }
1676 // There is a minor bug here: if the attribute in the source xml
1677 // document is duplicated, it will not be detected and the
1678 // attribute will be doubly added. However, tracking the 'prevAttribute'
1679 // avoids re-scanning the attribute list. Preferring performance for
1680 // now, may reconsider in the future.
1681 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001682 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001683 }
1684 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001685 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001686 }
1687 prevAttribute = attrib;
1688 }
1689 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001690 else if ( *p == '>' ) {
1691 ++p;
1692 break;
1693 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001694 // end of the tag
1695 else if ( *p == '/' && *(p+1) == '>' ) {
1696 _closingType = CLOSED;
1697 return p+2; // done; sealed element.
1698 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001699 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001700 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001701 return 0;
1702 }
1703 }
1704 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001705}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001706
Dmitry-Mee3225b12014-09-03 11:03:11 +04001707void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1708{
1709 if ( attribute == 0 ) {
1710 return;
1711 }
1712 MemPool* pool = attribute->_memPool;
1713 attribute->~XMLAttribute();
1714 pool->Free( attribute );
1715}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001716
Lee Thomason67d61312012-01-24 16:01:51 -08001717//
1718// <ele></ele>
1719// <ele>foo<b>bar</b></ele>
1720//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001721char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001722{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001723 // Read the element name.
1724 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001725
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001726 // The closing element is the </element> form. It is
1727 // parsed just like a regular element then deleted from
1728 // the DOM.
1729 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001730 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001731 ++p;
1732 }
Lee Thomason67d61312012-01-24 16:01:51 -08001733
Lee Thomason624d43f2012-10-12 10:58:48 -07001734 p = _value.ParseName( p );
1735 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001736 return 0;
1737 }
Lee Thomason67d61312012-01-24 16:01:51 -08001738
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001739 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001740 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001741 return p;
1742 }
Lee Thomason67d61312012-01-24 16:01:51 -08001743
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001744 p = XMLNode::ParseDeep( p, strPair );
1745 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001746}
1747
1748
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001749
1750XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1751{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001752 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001753 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001754 }
1755 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1756 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1757 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1758 }
1759 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001760}
1761
1762
1763bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1764{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001765 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001766 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001767 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001768
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001769 const XMLAttribute* a=FirstAttribute();
1770 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001771
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001772 while ( a && b ) {
1773 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1774 return false;
1775 }
1776 a = a->Next();
1777 b = b->Next();
1778 }
1779 if ( a || b ) {
1780 // different count
1781 return false;
1782 }
1783 return true;
1784 }
1785 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001786}
1787
1788
Lee Thomason751da522012-02-10 08:50:51 -08001789bool XMLElement::Accept( XMLVisitor* visitor ) const
1790{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001791 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001792 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001793 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1794 if ( !node->Accept( visitor ) ) {
1795 break;
1796 }
1797 }
1798 }
1799 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001800}
Lee Thomason56bdd022012-02-09 18:16:58 -08001801
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001802
Lee Thomason3f57d272012-01-11 15:30:03 -08001803// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001804
1805// Warning: List must match 'enum XMLError'
1806const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1807 "XML_SUCCESS",
1808 "XML_NO_ATTRIBUTE",
1809 "XML_WRONG_ATTRIBUTE_TYPE",
1810 "XML_ERROR_FILE_NOT_FOUND",
1811 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1812 "XML_ERROR_FILE_READ_ERROR",
1813 "XML_ERROR_ELEMENT_MISMATCH",
1814 "XML_ERROR_PARSING_ELEMENT",
1815 "XML_ERROR_PARSING_ATTRIBUTE",
1816 "XML_ERROR_IDENTIFYING_TAG",
1817 "XML_ERROR_PARSING_TEXT",
1818 "XML_ERROR_PARSING_CDATA",
1819 "XML_ERROR_PARSING_COMMENT",
1820 "XML_ERROR_PARSING_DECLARATION",
1821 "XML_ERROR_PARSING_UNKNOWN",
1822 "XML_ERROR_EMPTY_DOCUMENT",
1823 "XML_ERROR_MISMATCHED_ELEMENT",
1824 "XML_ERROR_PARSING",
1825 "XML_CAN_NOT_CONVERT_TEXT",
1826 "XML_NO_TEXT_NODE"
1827};
1828
1829
Lee Thomason624d43f2012-10-12 10:58:48 -07001830XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001831 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001832 _writeBOM( false ),
1833 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07001834 _errorID(XML_SUCCESS),
Lee Thomason624d43f2012-10-12 10:58:48 -07001835 _whitespace( whitespace ),
1836 _errorStr1( 0 ),
1837 _errorStr2( 0 ),
1838 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001839{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03001840 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
1841 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08001842}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001843
1844
Lee Thomason3f57d272012-01-11 15:30:03 -08001845XMLDocument::~XMLDocument()
1846{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001847 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001848}
1849
1850
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001851void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001852{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001853 DeleteChildren();
1854
Dmitry-Meab37df82014-11-28 12:08:36 +03001855#ifdef DEBUG
1856 const bool hadError = Error();
1857#endif
Lee Thomason85536252016-06-04 19:10:53 -07001858 _errorID = XML_SUCCESS;
Lee Thomason624d43f2012-10-12 10:58:48 -07001859 _errorStr1 = 0;
1860 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001861
Lee Thomason624d43f2012-10-12 10:58:48 -07001862 delete [] _charBuffer;
1863 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001864
1865#if 0
1866 _textPool.Trace( "text" );
1867 _elementPool.Trace( "element" );
1868 _commentPool.Trace( "comment" );
1869 _attributePool.Trace( "attribute" );
1870#endif
1871
1872#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001873 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001874 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1875 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1876 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1877 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1878 }
1879#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001880}
1881
Lee Thomason3f57d272012-01-11 15:30:03 -08001882
Lee Thomason2c85a712012-01-31 08:24:24 -08001883XMLElement* XMLDocument::NewElement( const char* name )
1884{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001885 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001886 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1887 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001888 ele->SetName( name );
1889 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001890}
1891
1892
Lee Thomason1ff38e02012-02-14 18:18:16 -08001893XMLComment* XMLDocument::NewComment( const char* str )
1894{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001895 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001896 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1897 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001898 comment->SetValue( str );
1899 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001900}
1901
1902
1903XMLText* XMLDocument::NewText( const char* str )
1904{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001905 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001906 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1907 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001908 text->SetValue( str );
1909 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001910}
1911
1912
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001913XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1914{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001915 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001916 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1917 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001918 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1919 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001920}
1921
1922
1923XMLUnknown* XMLDocument::NewUnknown( const char* str )
1924{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001925 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001926 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1927 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001928 unk->SetValue( str );
1929 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001930}
1931
Dmitry-Me01578db2014-08-19 10:18:48 +04001932static FILE* callfopen( const char* filepath, const char* mode )
1933{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001934 TIXMLASSERT( filepath );
1935 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001936#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1937 FILE* fp = 0;
1938 errno_t err = fopen_s( &fp, filepath, mode );
1939 if ( err ) {
1940 return 0;
1941 }
1942#else
1943 FILE* fp = fopen( filepath, mode );
1944#endif
1945 return fp;
1946}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001947
1948void XMLDocument::DeleteNode( XMLNode* node ) {
1949 TIXMLASSERT( node );
1950 TIXMLASSERT(node->_document == this );
1951 if (node->_parent) {
1952 node->_parent->DeleteChild( node );
1953 }
1954 else {
1955 // Isn't in the tree.
1956 // Use the parent delete.
1957 // Also, we need to mark it tracked: we 'know'
1958 // it was never used.
1959 node->_memPool->SetTracked();
1960 // Call the static XMLNode version:
1961 XMLNode::DeleteNode(node);
1962 }
1963}
1964
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001965
Lee Thomason2fa81722012-11-09 12:37:46 -08001966XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001967{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001968 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001969 FILE* fp = callfopen( filename, "rb" );
1970 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001971 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001972 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001973 }
1974 LoadFile( fp );
1975 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001976 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001977}
1978
Dmitry-Me901fed52015-09-25 10:29:51 +03001979// This is likely overengineered template art to have a check that unsigned long value incremented
1980// by one still fits into size_t. If size_t type is larger than unsigned long type
1981// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
1982// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
1983// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
1984// types sizes relate to each other.
1985template
1986<bool = (sizeof(unsigned long) >= sizeof(size_t))>
1987struct LongFitsIntoSizeTMinusOne {
1988 static bool Fits( unsigned long value )
1989 {
1990 return value < (size_t)-1;
1991 }
1992};
1993
1994template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02001995struct LongFitsIntoSizeTMinusOne<false> {
1996 static bool Fits( unsigned long )
1997 {
1998 return true;
1999 }
2000};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002001
Lee Thomason2fa81722012-11-09 12:37:46 -08002002XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002003{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002004 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002005
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002006 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002007 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002008 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2009 return _errorID;
2010 }
2011
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002012 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002013 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002014 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002015 if ( filelength == -1L ) {
2016 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2017 return _errorID;
2018 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002019 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002020
Dmitry-Me901fed52015-09-25 10:29:51 +03002021 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002022 // Cannot handle files which won't fit in buffer together with null terminator
2023 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2024 return _errorID;
2025 }
2026
Dmitry-Me72801b82015-05-07 09:41:39 +03002027 if ( filelength == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06002028 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002029 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002030 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002031
Dmitry-Me72801b82015-05-07 09:41:39 +03002032 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002033 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002034 _charBuffer = new char[size+1];
2035 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002036 if ( read != size ) {
2037 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002038 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002039 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002040
Lee Thomason624d43f2012-10-12 10:58:48 -07002041 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002042
Dmitry-Me97476b72015-01-01 16:15:57 +03002043 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002044 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002045}
2046
2047
Lee Thomason2fa81722012-11-09 12:37:46 -08002048XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002049{
Dmitry-Me01578db2014-08-19 10:18:48 +04002050 FILE* fp = callfopen( filename, "w" );
2051 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002052 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002053 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002054 }
2055 SaveFile(fp, compact);
2056 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002057 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002058}
2059
2060
Lee Thomason2fa81722012-11-09 12:37:46 -08002061XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002062{
Ant Mitchell189198f2015-03-24 16:20:36 +00002063 // Clear any error from the last save, otherwise it will get reported
2064 // for *this* call.
Lee Thomason85536252016-06-04 19:10:53 -07002065 SetError(XML_SUCCESS, 0, 0);
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002066 XMLPrinter stream( fp, compact );
2067 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002068 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002069}
2070
Lee Thomason1ff38e02012-02-14 18:18:16 -08002071
Lee Thomason2fa81722012-11-09 12:37:46 -08002072XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002073{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002074 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002075
Lee Thomason82d32002014-02-21 22:47:18 -08002076 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002077 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002078 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002079 }
2080 if ( len == (size_t)(-1) ) {
2081 len = strlen( p );
2082 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002083 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002084 _charBuffer = new char[ len+1 ];
2085 memcpy( _charBuffer, p, len );
2086 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002087
Dmitry-Me97476b72015-01-01 16:15:57 +03002088 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002089 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002090 // clean up now essentially dangling memory.
2091 // and the parse fail can put objects in the
2092 // pools that are dead and inaccessible.
2093 DeleteChildren();
2094 _elementPool.Clear();
2095 _attributePool.Clear();
2096 _textPool.Clear();
2097 _commentPool.Clear();
2098 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002099 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002100}
2101
2102
PKEuS1c5f99e2013-07-06 11:28:39 +02002103void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002104{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002105 if ( streamer ) {
2106 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002107 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002108 else {
2109 XMLPrinter stdoutStreamer( stdout );
2110 Accept( &stdoutStreamer );
2111 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002112}
2113
2114
Lee Thomason2fa81722012-11-09 12:37:46 -08002115void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08002116{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002117 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002118 _errorID = error;
2119 _errorStr1 = str1;
2120 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08002121}
2122
Lee Thomason331596e2014-09-11 14:56:43 -07002123const char* XMLDocument::ErrorName() const
2124{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002125 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002126 const char* errorName = _errorNames[_errorID];
2127 TIXMLASSERT( errorName && errorName[0] );
2128 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002129}
Lee Thomason5cae8972012-01-24 18:03:07 -08002130
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002131void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002132{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002133 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002134 static const int LEN = 20;
2135 char buf1[LEN] = { 0 };
2136 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002137
Lee Thomason624d43f2012-10-12 10:58:48 -07002138 if ( _errorStr1 ) {
2139 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002140 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002141 if ( _errorStr2 ) {
2142 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002143 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002144
Dmitry-Me2ad43202015-04-16 12:18:58 +03002145 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2146 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2147 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
Lee Thomason331596e2014-09-11 14:56:43 -07002148 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
Dmitry-Me400f1192015-04-07 11:51:21 +03002149 static_cast<int>( _errorID ), ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002150 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002151}
2152
Dmitry-Me97476b72015-01-01 16:15:57 +03002153void XMLDocument::Parse()
2154{
2155 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2156 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08002157 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03002158 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03002159 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002160 if ( !*p ) {
2161 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2162 return;
2163 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08002164 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002165}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002166
PKEuS1bfb9542013-08-04 13:51:17 +02002167XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002168 _elementJustOpened( false ),
2169 _firstElement( true ),
2170 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002171 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002172 _textDepth( -1 ),
2173 _processEntities( true ),
2174 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002175{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002176 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002177 _entityFlag[i] = false;
2178 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002179 }
2180 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002181 const char entityValue = entities[i].value;
2182 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
2183 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002184 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002185 _restrictedEntityFlag[(unsigned char)'&'] = true;
2186 _restrictedEntityFlag[(unsigned char)'<'] = true;
2187 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002188 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002189}
2190
2191
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002192void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002193{
2194 va_list va;
2195 va_start( va, format );
2196
Lee Thomason624d43f2012-10-12 10:58:48 -07002197 if ( _fp ) {
2198 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002199 }
2200 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002201 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002202 // Close out and re-start the va-args
2203 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002204 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002205 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002206 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002207 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002208 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002209 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002210 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002211}
2212
2213
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002214void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002215{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002216 for( int i=0; i<depth; ++i ) {
2217 Print( " " );
2218 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002219}
2220
2221
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002222void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002223{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002224 // Look for runs of bytes between entities to print.
2225 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002226
Lee Thomason624d43f2012-10-12 10:58:48 -07002227 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002228 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002229 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002230 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002231 // Remember, char is sometimes signed. (How many times has that bitten me?)
2232 if ( *q > 0 && *q < ENTITY_RANGE ) {
2233 // Check for entities. If one is found, flush
2234 // the stream up until the entity, write the
2235 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002236 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002237 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002238 const size_t delta = q - p;
2239 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002240 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002241 Print( "%.*s", toPrint, p );
2242 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002243 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002244 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002245 for( int i=0; i<NUM_ENTITIES; ++i ) {
2246 if ( entities[i].value == *q ) {
2247 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002248 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002249 break;
2250 }
2251 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002252 if ( !entityPatternPrinted ) {
2253 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2254 TIXMLASSERT( false );
2255 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002256 ++p;
2257 }
2258 }
2259 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002260 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002261 }
2262 }
2263 // Flush the remaining string. This will be the entire
2264 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002265 TIXMLASSERT( p <= q );
2266 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002267 Print( "%s", p );
2268 }
Lee Thomason857b8682012-01-25 17:50:25 -08002269}
2270
U-Stream\Leeae25a442012-02-17 17:48:16 -08002271
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002272void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002273{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002274 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002275 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 -07002276 Print( "%s", bom );
2277 }
2278 if ( writeDec ) {
2279 PushDeclaration( "xml version=\"1.0\"" );
2280 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002281}
2282
2283
Uli Kusterer593a33d2014-02-01 12:48:51 +01002284void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002285{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002286 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002287 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002288
Uli Kusterer593a33d2014-02-01 12:48:51 +01002289 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002290 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002291 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002292 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002293 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002294 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002295
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002296 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002297 _elementJustOpened = true;
2298 _firstElement = false;
2299 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002300}
2301
2302
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002303void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002304{
Lee Thomason624d43f2012-10-12 10:58:48 -07002305 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002306 Print( " %s=\"", name );
2307 PrintString( value, false );
2308 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002309}
2310
2311
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002312void XMLPrinter::PushAttribute( const char* name, int v )
2313{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002314 char buf[BUF_SIZE];
2315 XMLUtil::ToStr( v, buf, BUF_SIZE );
2316 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002317}
2318
2319
2320void XMLPrinter::PushAttribute( const char* name, unsigned v )
2321{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002322 char buf[BUF_SIZE];
2323 XMLUtil::ToStr( v, buf, BUF_SIZE );
2324 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002325}
2326
2327
Lee Thomason51c12712016-06-04 20:18:49 -07002328void XMLPrinter::PushAttribute(const char* name, int64_t v)
2329{
2330 char buf[BUF_SIZE];
2331 XMLUtil::ToStr(v, buf, BUF_SIZE);
2332 PushAttribute(name, buf);
2333}
2334
2335
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002336void XMLPrinter::PushAttribute( const char* name, bool v )
2337{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002338 char buf[BUF_SIZE];
2339 XMLUtil::ToStr( v, buf, BUF_SIZE );
2340 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002341}
2342
2343
2344void XMLPrinter::PushAttribute( const char* name, double v )
2345{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002346 char buf[BUF_SIZE];
2347 XMLUtil::ToStr( v, buf, BUF_SIZE );
2348 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002349}
2350
2351
Uli Kustererca412e82014-02-01 13:35:05 +01002352void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002353{
Lee Thomason624d43f2012-10-12 10:58:48 -07002354 --_depth;
2355 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002356
Lee Thomason624d43f2012-10-12 10:58:48 -07002357 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002358 Print( "/>" );
2359 }
2360 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002361 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002362 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002363 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002364 }
2365 Print( "</%s>", name );
2366 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002367
Lee Thomason624d43f2012-10-12 10:58:48 -07002368 if ( _textDepth == _depth ) {
2369 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002370 }
Uli Kustererca412e82014-02-01 13:35:05 +01002371 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002372 Print( "\n" );
2373 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002374 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002375}
2376
2377
Dmitry-Mea092bc12014-12-23 17:57:05 +03002378void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002379{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002380 if ( !_elementJustOpened ) {
2381 return;
2382 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002383 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002384 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002385}
2386
2387
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002388void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002389{
Lee Thomason624d43f2012-10-12 10:58:48 -07002390 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002391
Dmitry-Mea092bc12014-12-23 17:57:05 +03002392 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002393 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002394 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002395 }
2396 else {
2397 PrintString( text, true );
2398 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002399}
2400
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002401void XMLPrinter::PushText( int64_t value )
2402{
2403 char buf[BUF_SIZE];
2404 XMLUtil::ToStr( value, buf, BUF_SIZE );
2405 PushText( buf, false );
2406}
2407
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002408void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002409{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002410 char buf[BUF_SIZE];
2411 XMLUtil::ToStr( value, buf, BUF_SIZE );
2412 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002413}
2414
2415
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002416void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002417{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002418 char buf[BUF_SIZE];
2419 XMLUtil::ToStr( value, buf, BUF_SIZE );
2420 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002421}
2422
2423
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002424void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002425{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002426 char buf[BUF_SIZE];
2427 XMLUtil::ToStr( value, buf, BUF_SIZE );
2428 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002429}
2430
2431
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002432void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002433{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002434 char buf[BUF_SIZE];
2435 XMLUtil::ToStr( value, buf, BUF_SIZE );
2436 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002437}
2438
2439
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002440void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002441{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002442 char buf[BUF_SIZE];
2443 XMLUtil::ToStr( value, buf, BUF_SIZE );
2444 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002445}
2446
Lee Thomason5cae8972012-01-24 18:03:07 -08002447
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002448void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002449{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002450 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002451 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002452 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002453 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002454 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002455 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002456 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002457}
Lee Thomason751da522012-02-10 08:50:51 -08002458
2459
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002460void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002461{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002462 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002463 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002464 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002465 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002466 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002467 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002468 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002469}
2470
2471
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002472void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002473{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002474 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002475 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002476 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002477 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002478 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002479 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002480 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002481}
2482
2483
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002484bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002485{
Lee Thomason624d43f2012-10-12 10:58:48 -07002486 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002487 if ( doc.HasBOM() ) {
2488 PushHeader( true, false );
2489 }
2490 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002491}
2492
2493
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002494bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002495{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002496 const XMLElement* parentElem = 0;
2497 if ( element.Parent() ) {
2498 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002499 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002500 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002501 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002502 while ( attribute ) {
2503 PushAttribute( attribute->Name(), attribute->Value() );
2504 attribute = attribute->Next();
2505 }
2506 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002507}
2508
2509
Uli Kustererca412e82014-02-01 13:35:05 +01002510bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002511{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002512 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002513 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002514}
2515
2516
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002517bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002518{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002519 PushText( text.Value(), text.CData() );
2520 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002521}
2522
2523
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002524bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002525{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002526 PushComment( comment.Value() );
2527 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002528}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002529
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002530bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002531{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002532 PushDeclaration( declaration.Value() );
2533 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002534}
2535
2536
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002537bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002538{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002539 PushUnknown( unknown.Value() );
2540 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002541}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002542
Lee Thomason685b8952012-11-12 13:00:06 -08002543} // namespace tinyxml2
2544