blob: 9a8904fdbb6557df31d1a0ee6919470b32c6d243 [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
U-Lama\Lee560bd472011-12-28 19:42:49 -080024#include "tinyxml2.h"
25
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070026#include <new> // yes, this one new style header, is in the Android SDK.
Wilfred van Velzen67abee52016-03-25 14:01:15 +010027#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)
Lee Thomasona9cf3f92012-10-11 16:56:51 -070028# include <stddef.h>
Philipp Kloke358202c2015-07-30 16:02:26 +020029# include <stdarg.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070030#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070031# include <cstddef>
Philipp Kloke358202c2015-07-30 16:02:26 +020032# include <cstdarg>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070033#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080034
Lee Thomason53db4a62015-06-11 22:52:08 -070035#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
Dmitry-Me1ca593c2015-06-22 12:49:32 +030036 // Microsoft Visual Studio, version 2005 and higher. Not WinCE.
Lee Thomason53db4a62015-06-11 22:52:08 -070037 /*int _snprintf_s(
38 char *buffer,
39 size_t sizeOfBuffer,
40 size_t count,
41 const char *format [,
42 argument] ...
43 );*/
PKEuScac75782015-08-15 18:17:27 +020044 static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
Lee Thomason53db4a62015-06-11 22:52:08 -070045 {
46 va_list va;
47 va_start( va, format );
48 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
49 va_end( va );
50 return result;
51 }
52
PKEuScac75782015-08-15 18:17:27 +020053 static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070054 {
55 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
56 return result;
57 }
58
59 #define TIXML_VSCPRINTF _vscprintf
60 #define TIXML_SSCANF sscanf_s
61#elif defined _MSC_VER
62 // Microsoft Visual Studio 2003 and earlier or WinCE
63 #define TIXML_SNPRINTF _snprintf
64 #define TIXML_VSNPRINTF _vsnprintf
65 #define TIXML_SSCANF sscanf
Lee Thomasonaa8566b2015-06-19 16:52:40 -070066 #if (_MSC_VER < 1400 ) && (!defined WINCE)
Lee Thomason53db4a62015-06-11 22:52:08 -070067 // Microsoft Visual Studio 2003 and not WinCE.
68 #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have.
69 #else
70 // Microsoft Visual Studio 2003 and earlier or WinCE.
PKEuScac75782015-08-15 18:17:27 +020071 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070072 {
73 int len = 512;
74 for (;;) {
75 len = len*2;
76 char* str = new char[len]();
77 const int required = _vsnprintf(str, len, format, va);
78 delete[] str;
79 if ( required != -1 ) {
Dmitry-Me1d32e582015-07-27 17:11:51 +030080 TIXMLASSERT( required >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070081 len = required;
82 break;
83 }
84 }
Dmitry-Me1d32e582015-07-27 17:11:51 +030085 TIXMLASSERT( len >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070086 return len;
87 }
88 #endif
89#else
90 // GCC version 3 and higher
91 //#warning( "Using sn* functions." )
92 #define TIXML_SNPRINTF snprintf
93 #define TIXML_VSNPRINTF vsnprintf
PKEuScac75782015-08-15 18:17:27 +020094 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070095 {
96 int len = vsnprintf( 0, 0, format, va );
Dmitry-Me1d32e582015-07-27 17:11:51 +030097 TIXMLASSERT( len >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070098 return len;
99 }
100 #define TIXML_SSCANF sscanf
101#endif
102
103
Lee Thomasone4422302012-01-20 17:59:50 -0800104static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -0800105static const char LF = LINE_FEED;
106static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
107static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -0800108static const char SINGLE_QUOTE = '\'';
109static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -0800110
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800111// Bunch of unicode info at:
112// http://www.unicode.org/faq/utf_bom.html
113// ef bb bf (Microsoft "lead bytes") - designates UTF-8
114
115static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
116static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
117static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800118
Kevin Wojniak04c22d22012-11-08 11:02:22 -0800119namespace tinyxml2
120{
121
Lee Thomason8ee79892012-01-25 17:44:30 -0800122struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700123 const char* pattern;
124 int length;
125 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -0800126};
127
128static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700129static const Entity entities[NUM_ENTITIES] = {
130 { "quot", 4, DOUBLE_QUOTE },
131 { "amp", 3, '&' },
132 { "apos", 4, SINGLE_QUOTE },
133 { "lt", 2, '<' },
134 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -0800135};
136
Lee Thomasonfde6a752012-01-14 18:08:12 -0800137
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800138StrPair::~StrPair()
139{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700140 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800141}
142
143
Lee Thomason29658802014-11-27 22:31:11 -0800144void StrPair::TransferTo( StrPair* other )
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300145{
Lee Thomason29658802014-11-27 22:31:11 -0800146 if ( this == other ) {
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300147 return;
148 }
149 // This in effect implements the assignment operator by "moving"
150 // ownership (as in auto_ptr).
151
Dmitry-Medb02b212016-08-04 17:16:05 +0300152 TIXMLASSERT( other != 0 );
Lee Thomason29658802014-11-27 22:31:11 -0800153 TIXMLASSERT( other->_flags == 0 );
154 TIXMLASSERT( other->_start == 0 );
155 TIXMLASSERT( other->_end == 0 );
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300156
Lee Thomason29658802014-11-27 22:31:11 -0800157 other->Reset();
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300158
Lee Thomason29658802014-11-27 22:31:11 -0800159 other->_flags = _flags;
160 other->_start = _start;
161 other->_end = _end;
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300162
163 _flags = 0;
164 _start = 0;
165 _end = 0;
166}
167
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800168void StrPair::Reset()
169{
Lee Thomason120b3a62012-10-12 10:06:59 -0700170 if ( _flags & NEEDS_DELETE ) {
171 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700172 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700173 _flags = 0;
174 _start = 0;
175 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800176}
177
178
179void StrPair::SetStr( const char* str, int flags )
180{
Dmitry-Me0515fa92015-12-09 11:54:06 +0300181 TIXMLASSERT( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700182 Reset();
183 size_t len = strlen( str );
Dmitry-Me96f38cc2015-08-10 16:45:12 +0300184 TIXMLASSERT( _start == 0 );
Lee Thomason120b3a62012-10-12 10:06:59 -0700185 _start = new char[ len+1 ];
186 memcpy( _start, str, len+1 );
187 _end = _start + len;
188 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800189}
190
191
192char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
193{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700194 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800195
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400196 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700197 char endChar = *endTag;
198 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800199
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700200 // Inner loop of text parsing.
201 while ( *p ) {
202 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
203 Set( start, p, strFlags );
204 return p + length;
205 }
206 ++p;
207 }
208 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800209}
210
211
212char* StrPair::ParseName( char* p )
213{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400214 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700215 return 0;
216 }
JayXonee525db2014-12-24 04:01:42 -0500217 if ( !XMLUtil::IsNameStartChar( *p ) ) {
218 return 0;
219 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800220
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400221 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500222 ++p;
223 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700224 ++p;
225 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800226
JayXonee525db2014-12-24 04:01:42 -0500227 Set( start, p, 0 );
228 return p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800229}
230
231
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700232void StrPair::CollapseWhitespace()
233{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400234 // Adjusting _start would cause undefined behavior on delete[]
235 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700236 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700237 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700238
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300239 if ( *_start ) {
Dmitry-Me24495822016-09-02 16:53:32 +0300240 const char* p = _start; // the read pointer
Lee Thomason120b3a62012-10-12 10:06:59 -0700241 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700242
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700243 while( *p ) {
244 if ( XMLUtil::IsWhiteSpace( *p )) {
245 p = XMLUtil::SkipWhiteSpace( p );
246 if ( *p == 0 ) {
247 break; // don't write to q; this trims the trailing space.
248 }
249 *q = ' ';
250 ++q;
251 }
252 *q = *p;
253 ++q;
254 ++p;
255 }
256 *q = 0;
257 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700258}
259
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800260
Lee Thomasone4422302012-01-20 17:59:50 -0800261const char* StrPair::GetStr()
262{
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300263 TIXMLASSERT( _start );
264 TIXMLASSERT( _end );
Lee Thomason120b3a62012-10-12 10:06:59 -0700265 if ( _flags & NEEDS_FLUSH ) {
266 *_end = 0;
267 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800268
Lee Thomason120b3a62012-10-12 10:06:59 -0700269 if ( _flags ) {
Dmitry-Me24495822016-09-02 16:53:32 +0300270 const char* p = _start; // the read pointer
Lee Thomason120b3a62012-10-12 10:06:59 -0700271 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800272
Lee Thomason120b3a62012-10-12 10:06:59 -0700273 while( p < _end ) {
274 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700275 // CR-LF pair becomes LF
276 // CR alone becomes LF
277 // LF-CR becomes LF
278 if ( *(p+1) == LF ) {
279 p += 2;
280 }
281 else {
282 ++p;
283 }
284 *q++ = LF;
285 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700286 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700287 if ( *(p+1) == CR ) {
288 p += 2;
289 }
290 else {
291 ++p;
292 }
293 *q++ = LF;
294 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700295 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700296 // Entities handled by tinyXML2:
297 // - special entities in the entity table [in/out]
298 // - numeric character reference [in]
299 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800300
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700301 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400302 const int buflen = 10;
303 char buf[buflen] = { 0 };
304 int len = 0;
Dmitry-Me6f51c802015-03-14 13:25:03 +0300305 char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
306 if ( adjusted == 0 ) {
307 *q = *p;
308 ++p;
309 ++q;
310 }
311 else {
312 TIXMLASSERT( 0 <= len && len <= buflen );
313 TIXMLASSERT( q + len <= adjusted );
314 p = adjusted;
315 memcpy( q, buf, len );
316 q += len;
317 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700318 }
319 else {
Dmitry-Me764545e2015-05-20 10:29:24 +0300320 bool entityFound = false;
321 for( int i = 0; i < NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400322 const Entity& entity = entities[i];
323 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
324 && *( p + entity.length + 1 ) == ';' ) {
325 // Found an entity - convert.
326 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700327 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400328 p += entity.length + 2;
Dmitry-Me764545e2015-05-20 10:29:24 +0300329 entityFound = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700330 break;
331 }
332 }
Dmitry-Me764545e2015-05-20 10:29:24 +0300333 if ( !entityFound ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700334 // fixme: treat as error?
335 ++p;
336 ++q;
337 }
338 }
339 }
340 else {
341 *q = *p;
342 ++p;
343 ++q;
344 }
345 }
346 *q = 0;
347 }
348 // The loop below has plenty going on, and this
349 // is a less useful mode. Break it out.
Dmitry-Me5420e542015-05-20 10:51:26 +0300350 if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700351 CollapseWhitespace();
352 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700353 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700354 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300355 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700356 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800357}
358
Lee Thomason2c85a712012-01-31 08:24:24 -0800359
Lee Thomasone4422302012-01-20 17:59:50 -0800360
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800361
Lee Thomason56bdd022012-02-09 18:16:58 -0800362// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800363
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800364const char* XMLUtil::ReadBOM( const char* p, bool* bom )
365{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300366 TIXMLASSERT( p );
367 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700368 *bom = false;
369 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
370 // Check for BOM:
371 if ( *(pu+0) == TIXML_UTF_LEAD_0
372 && *(pu+1) == TIXML_UTF_LEAD_1
373 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
374 *bom = true;
375 p += 3;
376 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300377 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700378 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800379}
380
381
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800382void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
383{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700384 const unsigned long BYTE_MASK = 0xBF;
385 const unsigned long BYTE_MARK = 0x80;
386 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800387
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700388 if (input < 0x80) {
389 *length = 1;
390 }
391 else if ( input < 0x800 ) {
392 *length = 2;
393 }
394 else if ( input < 0x10000 ) {
395 *length = 3;
396 }
397 else if ( input < 0x200000 ) {
398 *length = 4;
399 }
400 else {
Dmitry-Me2f465c42015-03-16 11:08:23 +0300401 *length = 0; // This code won't convert this correctly anyway.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700402 return;
403 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800404
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700405 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800406
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700407 // Scary scary fall throughs.
408 switch (*length) {
409 case 4:
410 --output;
411 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
412 input >>= 6;
413 case 3:
414 --output;
415 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
416 input >>= 6;
417 case 2:
418 --output;
419 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
420 input >>= 6;
421 case 1:
422 --output;
423 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100424 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300425 default:
426 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700427 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800428}
429
430
431const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
432{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700433 // Presume an entity, and pull it out.
434 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800435
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700436 if ( *(p+1) == '#' && *(p+2) ) {
437 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300438 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700439 ptrdiff_t delta = 0;
440 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800441 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800442
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700443 if ( *(p+2) == 'x' ) {
444 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300445 const char* q = p+3;
446 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700447 return 0;
448 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800449
Lee Thomason7e67bc82015-01-12 14:05:12 -0800450 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800451
Dmitry-Me9f56e122015-01-12 10:07:54 +0300452 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700453 return 0;
454 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800455 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800456
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700457 delta = q-p;
458 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800459
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700460 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700461 unsigned int digit = 0;
462
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700463 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300464 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700465 }
466 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300467 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700468 }
469 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300470 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700471 }
472 else {
473 return 0;
474 }
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100475 TIXMLASSERT( digit < 16 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300476 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
477 const unsigned int digitScaled = mult * digit;
478 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
479 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300480 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700481 mult *= 16;
482 --q;
483 }
484 }
485 else {
486 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300487 const char* q = p+2;
488 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700489 return 0;
490 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800491
Lee Thomason7e67bc82015-01-12 14:05:12 -0800492 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800493
Dmitry-Me9f56e122015-01-12 10:07:54 +0300494 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700495 return 0;
496 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800497 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800498
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700499 delta = q-p;
500 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800501
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700502 while ( *q != '#' ) {
503 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300504 const unsigned int digit = *q - '0';
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100505 TIXMLASSERT( digit < 10 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300506 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
507 const unsigned int digitScaled = mult * digit;
508 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
509 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700510 }
511 else {
512 return 0;
513 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300514 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700515 mult *= 10;
516 --q;
517 }
518 }
519 // convert the UCS to UTF-8
520 ConvertUTF32ToUTF8( ucs, value, length );
521 return p + delta + 1;
522 }
523 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800524}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800525
526
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700527void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700528{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700529 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700530}
531
532
533void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
534{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700535 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700536}
537
538
539void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
540{
Doruk Turakde45d042016-08-28 20:47:08 +0200541 TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? "true" : "false" );
Lee Thomason21be8822012-07-15 17:27:22 -0700542}
543
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800544/*
545 ToStr() of a number is a very tricky topic.
546 https://github.com/leethomason/tinyxml2/issues/106
547*/
Lee Thomason21be8822012-07-15 17:27:22 -0700548void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
549{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800550 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700551}
552
553
554void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
555{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800556 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700557}
558
559
Lee Thomason51c12712016-06-04 20:18:49 -0700560void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize)
561{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700562 // horrible syntax trick to make the compiler happy about %lld
563 TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v);
Lee Thomason51c12712016-06-04 20:18:49 -0700564}
565
566
Lee Thomason21be8822012-07-15 17:27:22 -0700567bool XMLUtil::ToInt( const char* str, int* value )
568{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700569 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
570 return true;
571 }
572 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700573}
574
575bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
576{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700577 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
578 return true;
579 }
580 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700581}
582
583bool XMLUtil::ToBool( const char* str, bool* value )
584{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700585 int ival = 0;
586 if ( ToInt( str, &ival )) {
587 *value = (ival==0) ? false : true;
588 return true;
589 }
590 if ( StringEqual( str, "true" ) ) {
591 *value = true;
592 return true;
593 }
594 else if ( StringEqual( str, "false" ) ) {
595 *value = false;
596 return true;
597 }
598 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700599}
600
601
602bool XMLUtil::ToFloat( const char* str, float* value )
603{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700604 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
605 return true;
606 }
607 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700608}
609
Lee Thomason51c12712016-06-04 20:18:49 -0700610
Lee Thomason21be8822012-07-15 17:27:22 -0700611bool XMLUtil::ToDouble( const char* str, double* value )
612{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700613 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
614 return true;
615 }
616 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700617}
618
619
Lee Thomason51c12712016-06-04 20:18:49 -0700620bool XMLUtil::ToInt64(const char* str, int64_t* value)
621{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700622 long long v = 0; // horrible syntax trick to make the compiler happy about %lld
623 if (TIXML_SSCANF(str, "%lld", &v) == 1) {
624 *value = (int64_t)v;
Lee Thomason51c12712016-06-04 20:18:49 -0700625 return true;
626 }
627 return false;
628}
629
630
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700631char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800632{
Dmitry-Me02384662015-03-03 16:02:13 +0300633 TIXMLASSERT( node );
634 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400635 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700636 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300637 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300638 *node = 0;
639 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700640 return p;
641 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800642
Dmitry-Me962083b2015-05-26 11:38:30 +0300643 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700644 static const char* xmlHeader = { "<?" };
645 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700646 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300647 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700648 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800649
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700650 static const int xmlHeaderLen = 2;
651 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700652 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300653 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700654 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800655
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700656 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
657 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400658 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700659 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300660 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700661 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
662 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700663 p += xmlHeaderLen;
664 }
665 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300666 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700667 returnNode = new (_commentPool.Alloc()) XMLComment( this );
668 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700669 p += commentHeaderLen;
670 }
671 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300672 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700673 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700674 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700675 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700676 p += cdataHeaderLen;
677 text->SetCData( true );
678 }
679 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300680 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700681 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
682 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700683 p += dtdHeaderLen;
684 }
685 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300686 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700687 returnNode = new (_elementPool.Alloc()) XMLElement( this );
688 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700689 p += elementHeaderLen;
690 }
691 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300692 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700693 returnNode = new (_textPool.Alloc()) XMLText( this );
694 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700695 p = start; // Back it up, all the text counts.
696 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800697
Dmitry-Me02384662015-03-03 16:02:13 +0300698 TIXMLASSERT( returnNode );
699 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700700 *node = returnNode;
701 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800702}
703
704
Lee Thomason751da522012-02-10 08:50:51 -0800705bool XMLDocument::Accept( XMLVisitor* visitor ) const
706{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300707 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700708 if ( visitor->VisitEnter( *this ) ) {
709 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
710 if ( !node->Accept( visitor ) ) {
711 break;
712 }
713 }
714 }
715 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800716}
Lee Thomason56bdd022012-02-09 18:16:58 -0800717
718
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800719// --------- XMLNode ----------- //
720
721XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700722 _document( doc ),
723 _parent( 0 ),
724 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200725 _prev( 0 ), _next( 0 ),
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700726 _userData( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200727 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800728{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800729}
730
731
732XMLNode::~XMLNode()
733{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700734 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700735 if ( _parent ) {
736 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700737 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800738}
739
Michael Daumling21626882013-10-22 17:03:37 +0200740const char* XMLNode::Value() const
741{
Dmitry-Mecaa72a62016-08-10 17:34:34 +0300742 // Edge case: XMLDocuments don't have a Value. Return null.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530743 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530744 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200745 return _value.GetStr();
746}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800747
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800748void XMLNode::SetValue( const char* str, bool staticMem )
749{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700750 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700751 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700752 }
753 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700754 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700755 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800756}
757
758
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800759void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800760{
Lee Thomason624d43f2012-10-12 10:58:48 -0700761 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300762 TIXMLASSERT( _lastChild );
Dmitry-Me9cb4eca2016-08-18 18:10:59 +0300763 DeleteChild( _firstChild );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700764 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700765 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800766}
767
768
769void XMLNode::Unlink( XMLNode* child )
770{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300771 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300772 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300773 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700774 if ( child == _firstChild ) {
775 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700776 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700777 if ( child == _lastChild ) {
778 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700779 }
Lee Thomasond923c672012-01-23 08:44:25 -0800780
Lee Thomason624d43f2012-10-12 10:58:48 -0700781 if ( child->_prev ) {
782 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700783 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700784 if ( child->_next ) {
785 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700786 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700787 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800788}
789
790
U-Stream\Leeae25a442012-02-17 17:48:16 -0800791void XMLNode::DeleteChild( XMLNode* node )
792{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300793 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300794 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700795 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100796 Unlink( node );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400797 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800798}
799
800
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800801XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
802{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300803 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300804 if ( addThis->_document != _document ) {
805 TIXMLASSERT( false );
806 return 0;
807 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800808 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700809
Lee Thomason624d43f2012-10-12 10:58:48 -0700810 if ( _lastChild ) {
811 TIXMLASSERT( _firstChild );
812 TIXMLASSERT( _lastChild->_next == 0 );
813 _lastChild->_next = addThis;
814 addThis->_prev = _lastChild;
815 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800816
Lee Thomason624d43f2012-10-12 10:58:48 -0700817 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700818 }
819 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700820 TIXMLASSERT( _firstChild == 0 );
821 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800822
Lee Thomason624d43f2012-10-12 10:58:48 -0700823 addThis->_prev = 0;
824 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700825 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700826 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700827 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800828}
829
830
Lee Thomason1ff38e02012-02-14 18:18:16 -0800831XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
832{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300833 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300834 if ( addThis->_document != _document ) {
835 TIXMLASSERT( false );
836 return 0;
837 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800838 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700839
Lee Thomason624d43f2012-10-12 10:58:48 -0700840 if ( _firstChild ) {
841 TIXMLASSERT( _lastChild );
842 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800843
Lee Thomason624d43f2012-10-12 10:58:48 -0700844 _firstChild->_prev = addThis;
845 addThis->_next = _firstChild;
846 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800847
Lee Thomason624d43f2012-10-12 10:58:48 -0700848 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700849 }
850 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700851 TIXMLASSERT( _lastChild == 0 );
852 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800853
Lee Thomason624d43f2012-10-12 10:58:48 -0700854 addThis->_prev = 0;
855 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700856 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700857 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400858 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800859}
860
861
862XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
863{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300864 TIXMLASSERT( addThis );
865 if ( addThis->_document != _document ) {
866 TIXMLASSERT( false );
867 return 0;
868 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700869
Dmitry-Meabb2d042014-12-09 12:59:31 +0300870 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700871
Lee Thomason624d43f2012-10-12 10:58:48 -0700872 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300873 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700874 return 0;
875 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800876
Lee Thomason624d43f2012-10-12 10:58:48 -0700877 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700878 // The last node or the only node.
879 return InsertEndChild( addThis );
880 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800881 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700882 addThis->_prev = afterThis;
883 addThis->_next = afterThis->_next;
884 afterThis->_next->_prev = addThis;
885 afterThis->_next = addThis;
886 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700887 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800888}
889
890
891
892
Dmitry-Me886ad972015-07-22 11:00:51 +0300893const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800894{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300895 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
896 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700897 if ( element ) {
Dmitry-Me886ad972015-07-22 11:00:51 +0300898 if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700899 return element;
900 }
901 }
902 }
903 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800904}
905
906
Dmitry-Me886ad972015-07-22 11:00:51 +0300907const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800908{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300909 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
910 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700911 if ( element ) {
Dmitry-Me886ad972015-07-22 11:00:51 +0300912 if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700913 return element;
914 }
915 }
916 }
917 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800918}
919
920
Dmitry-Me886ad972015-07-22 11:00:51 +0300921const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800922{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300923 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400924 const XMLElement* element = node->ToElement();
925 if ( element
Dmitry-Me886ad972015-07-22 11:00:51 +0300926 && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400927 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700928 }
929 }
930 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800931}
932
933
Dmitry-Me886ad972015-07-22 11:00:51 +0300934const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800935{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300936 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400937 const XMLElement* element = node->ToElement();
938 if ( element
Dmitry-Me886ad972015-07-22 11:00:51 +0300939 && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400940 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700941 }
942 }
943 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800944}
945
946
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800947char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800948{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700949 // This is a recursive method, but thinking about it "at the current level"
950 // it is a pretty simple flat list:
951 // <foo/>
952 // <!-- comment -->
953 //
954 // With a special case:
955 // <foo>
956 // </foo>
957 // <!-- comment -->
958 //
959 // Where the closing element (/foo) *must* be the next thing after the opening
960 // element, and the names must match. BUT the tricky bit is that the closing
961 // element will be read by the child.
962 //
963 // 'endTag' is the end tag for this node, it is returned by a call to a child.
964 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800965
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700966 while( p && *p ) {
967 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800968
Lee Thomason624d43f2012-10-12 10:58:48 -0700969 p = _document->Identify( p, &node );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300970 if ( node == 0 ) {
971 break;
972 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800973
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700974 StrPair endTag;
975 p = node->ParseDeep( p, &endTag );
976 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400977 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700978 if ( !_document->Error() ) {
979 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700980 }
981 break;
982 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800983
Sarat Addepalli3df007e2015-05-20 10:43:51 +0530984 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530985 if ( decl ) {
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530986 // A declaration can only be the first child of a document.
987 // Set error, if document already has children.
988 if ( !_document->NoChildren() ) {
989 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0);
Dmitry-Me4de7abb2016-08-10 17:30:02 +0300990 DeleteNode( node );
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530991 break;
992 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530993 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530994
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400995 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700996 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -0500997 // We read the end tag. Return it to the parent.
998 if ( ele->ClosingType() == XMLElement::CLOSING ) {
999 if ( parentEnd ) {
1000 ele->_value.TransferTo( parentEnd );
1001 }
1002 node->_memPool->SetTracked(); // created and then immediately deleted.
1003 DeleteNode( node );
1004 return p;
1005 }
1006
1007 // Handle an end tag returned to this level.
1008 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001009 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001010 if ( endTag.Empty() ) {
1011 if ( ele->ClosingType() == XMLElement::OPEN ) {
1012 mismatch = true;
1013 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001014 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001015 else {
1016 if ( ele->ClosingType() != XMLElement::OPEN ) {
1017 mismatch = true;
1018 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001019 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001020 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001021 }
1022 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001023 if ( mismatch ) {
Dmitry-Me886ad972015-07-22 11:00:51 +03001024 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -05001025 DeleteNode( node );
1026 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001027 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001028 }
JayXondbfdd8f2014-12-12 20:07:14 -05001029 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001030 }
1031 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001032}
1033
Dmitry-Mee3225b12014-09-03 11:03:11 +04001034void XMLNode::DeleteNode( XMLNode* node )
1035{
1036 if ( node == 0 ) {
1037 return;
1038 }
1039 MemPool* pool = node->_memPool;
1040 node->~XMLNode();
1041 pool->Free( node );
1042}
1043
Lee Thomason3cebdc42015-01-05 17:16:28 -08001044void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001045{
1046 TIXMLASSERT( insertThis );
1047 TIXMLASSERT( insertThis->_document == _document );
1048
1049 if ( insertThis->_parent )
1050 insertThis->_parent->Unlink( insertThis );
1051 else
1052 insertThis->_memPool->SetTracked();
1053}
1054
Lee Thomason5492a1c2012-01-23 15:32:10 -08001055// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001056char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001057{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001058 const char* start = p;
1059 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001060 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001061 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001062 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001063 }
1064 return p;
1065 }
1066 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001067 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1068 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001069 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001070 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001071
Lee Thomason624d43f2012-10-12 10:58:48 -07001072 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001073 if ( p && *p ) {
1074 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001075 }
1076 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +03001077 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001078 }
1079 }
1080 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001081}
1082
1083
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001084XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1085{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001086 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001087 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001088 }
1089 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1090 text->SetCData( this->CData() );
1091 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001092}
1093
1094
1095bool XMLText::ShallowEqual( const XMLNode* compare ) const
1096{
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001097 const XMLText* text = compare->ToText();
1098 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001099}
1100
1101
Lee Thomason56bdd022012-02-09 18:16:58 -08001102bool XMLText::Accept( XMLVisitor* visitor ) const
1103{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001104 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001105 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001106}
1107
1108
Lee Thomason3f57d272012-01-11 15:30:03 -08001109// --------- XMLComment ---------- //
1110
Lee Thomasone4422302012-01-20 17:59:50 -08001111XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001112{
1113}
1114
1115
Lee Thomasonce0763e2012-01-11 15:43:54 -08001116XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001117{
Lee Thomason3f57d272012-01-11 15:30:03 -08001118}
1119
1120
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001121char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -08001122{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001123 // Comment parses as text.
1124 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001125 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001126 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001127 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001128 }
1129 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001130}
1131
1132
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001133XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1134{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001135 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001136 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001137 }
1138 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1139 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001140}
1141
1142
1143bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1144{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001145 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001146 const XMLComment* comment = compare->ToComment();
1147 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001148}
1149
1150
Lee Thomason751da522012-02-10 08:50:51 -08001151bool XMLComment::Accept( XMLVisitor* visitor ) const
1152{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001153 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001154 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001155}
Lee Thomason56bdd022012-02-09 18:16:58 -08001156
1157
Lee Thomason50f97b22012-02-11 16:33:40 -08001158// --------- XMLDeclaration ---------- //
1159
1160XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1161{
1162}
1163
1164
1165XMLDeclaration::~XMLDeclaration()
1166{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001167 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001168}
1169
1170
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001171char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001172{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001173 // Declaration parses as text.
1174 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001175 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001176 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001177 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001178 }
1179 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001180}
1181
1182
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001183XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1184{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001185 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001186 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001187 }
1188 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1189 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001190}
1191
1192
1193bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1194{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001195 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001196 const XMLDeclaration* declaration = compare->ToDeclaration();
1197 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001198}
1199
1200
1201
Lee Thomason50f97b22012-02-11 16:33:40 -08001202bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1203{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001204 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001205 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001206}
1207
1208// --------- XMLUnknown ---------- //
1209
1210XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1211{
1212}
1213
1214
1215XMLUnknown::~XMLUnknown()
1216{
1217}
1218
1219
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001220char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001221{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001222 // Unknown parses as text.
1223 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001224
Lee Thomason624d43f2012-10-12 10:58:48 -07001225 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001226 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001227 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001228 }
1229 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001230}
1231
1232
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001233XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1234{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001235 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001236 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001237 }
1238 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1239 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001240}
1241
1242
1243bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1244{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001245 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001246 const XMLUnknown* unknown = compare->ToUnknown();
1247 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001248}
1249
1250
Lee Thomason50f97b22012-02-11 16:33:40 -08001251bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1252{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001253 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001254 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001255}
1256
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001257// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001258
1259const char* XMLAttribute::Name() const
1260{
1261 return _name.GetStr();
1262}
1263
1264const char* XMLAttribute::Value() const
1265{
1266 return _value.GetStr();
1267}
1268
Lee Thomason6f381b72012-03-02 12:59:39 -08001269char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001270{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001271 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001272 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001273 if ( !p || !*p ) {
1274 return 0;
1275 }
Lee Thomason22aead12012-01-23 13:29:35 -08001276
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001277 // Skip white space before =
1278 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001279 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001280 return 0;
1281 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001282
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001283 ++p; // move up to opening quote
1284 p = XMLUtil::SkipWhiteSpace( p );
1285 if ( *p != '\"' && *p != '\'' ) {
1286 return 0;
1287 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001288
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001289 char endTag[2] = { *p, 0 };
1290 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001291
Lee Thomason624d43f2012-10-12 10:58:48 -07001292 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001293 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001294}
1295
1296
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001297void XMLAttribute::SetName( const char* n )
1298{
Lee Thomason624d43f2012-10-12 10:58:48 -07001299 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001300}
1301
1302
Lee Thomason2fa81722012-11-09 12:37:46 -08001303XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001304{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001305 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001306 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001307 }
1308 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001309}
1310
1311
Lee Thomason2fa81722012-11-09 12:37:46 -08001312XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001313{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001314 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001315 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001316 }
1317 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001318}
1319
1320
Lee Thomason51c12712016-06-04 20:18:49 -07001321XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1322{
1323 if (XMLUtil::ToInt64(Value(), value)) {
1324 return XML_SUCCESS;
1325 }
1326 return XML_WRONG_ATTRIBUTE_TYPE;
1327}
1328
1329
Lee Thomason2fa81722012-11-09 12:37:46 -08001330XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001331{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001332 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001333 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001334 }
1335 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001336}
1337
1338
Lee Thomason2fa81722012-11-09 12:37:46 -08001339XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001340{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001341 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001342 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001343 }
1344 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001345}
1346
1347
Lee Thomason2fa81722012-11-09 12:37:46 -08001348XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001349{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001350 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001351 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001352 }
1353 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001354}
1355
1356
1357void XMLAttribute::SetAttribute( const char* v )
1358{
Lee Thomason624d43f2012-10-12 10:58:48 -07001359 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001360}
1361
1362
Lee Thomason1ff38e02012-02-14 18:18:16 -08001363void XMLAttribute::SetAttribute( int v )
1364{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001365 char buf[BUF_SIZE];
1366 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001367 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001368}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001369
1370
1371void XMLAttribute::SetAttribute( unsigned v )
1372{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001373 char buf[BUF_SIZE];
1374 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001375 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001376}
1377
1378
Lee Thomason51c12712016-06-04 20:18:49 -07001379void XMLAttribute::SetAttribute(int64_t v)
1380{
1381 char buf[BUF_SIZE];
1382 XMLUtil::ToStr(v, buf, BUF_SIZE);
1383 _value.SetStr(buf);
1384}
1385
1386
1387
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001388void XMLAttribute::SetAttribute( bool v )
1389{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001390 char buf[BUF_SIZE];
1391 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001392 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001393}
1394
1395void XMLAttribute::SetAttribute( double v )
1396{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001397 char buf[BUF_SIZE];
1398 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001399 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001400}
1401
1402void XMLAttribute::SetAttribute( float v )
1403{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001404 char buf[BUF_SIZE];
1405 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001406 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001407}
1408
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001409
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001410// --------- XMLElement ---------- //
1411XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001412 _closingType( 0 ),
1413 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001414{
1415}
1416
1417
1418XMLElement::~XMLElement()
1419{
Lee Thomason624d43f2012-10-12 10:58:48 -07001420 while( _rootAttribute ) {
1421 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001422 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001423 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001424 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001425}
1426
1427
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001428const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1429{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001430 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001431 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1432 return a;
1433 }
1434 }
1435 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001436}
1437
1438
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001439const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001440{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001441 const XMLAttribute* a = FindAttribute( name );
1442 if ( !a ) {
1443 return 0;
1444 }
1445 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1446 return a->Value();
1447 }
1448 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001449}
1450
1451
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001452const char* XMLElement::GetText() const
1453{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001454 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001455 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001456 }
1457 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001458}
1459
1460
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001461void XMLElement::SetText( const char* inText )
1462{
Uli Kusterer869bb592014-01-21 01:36:16 +01001463 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001464 FirstChild()->SetValue( inText );
1465 else {
1466 XMLText* theText = GetDocument()->NewText( inText );
1467 InsertFirstChild( theText );
1468 }
1469}
1470
Lee Thomason5bb2d802014-01-24 10:42:57 -08001471
1472void XMLElement::SetText( int v )
1473{
1474 char buf[BUF_SIZE];
1475 XMLUtil::ToStr( v, buf, BUF_SIZE );
1476 SetText( buf );
1477}
1478
1479
1480void XMLElement::SetText( unsigned v )
1481{
1482 char buf[BUF_SIZE];
1483 XMLUtil::ToStr( v, buf, BUF_SIZE );
1484 SetText( buf );
1485}
1486
1487
Lee Thomason51c12712016-06-04 20:18:49 -07001488void XMLElement::SetText(int64_t v)
1489{
1490 char buf[BUF_SIZE];
1491 XMLUtil::ToStr(v, buf, BUF_SIZE);
1492 SetText(buf);
1493}
1494
1495
1496void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001497{
1498 char buf[BUF_SIZE];
1499 XMLUtil::ToStr( v, buf, BUF_SIZE );
1500 SetText( buf );
1501}
1502
1503
1504void XMLElement::SetText( float v )
1505{
1506 char buf[BUF_SIZE];
1507 XMLUtil::ToStr( v, buf, BUF_SIZE );
1508 SetText( buf );
1509}
1510
1511
1512void XMLElement::SetText( double v )
1513{
1514 char buf[BUF_SIZE];
1515 XMLUtil::ToStr( v, buf, BUF_SIZE );
1516 SetText( buf );
1517}
1518
1519
MortenMacFly4ee49f12013-01-14 20:03:14 +01001520XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001521{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001522 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001523 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001524 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001525 return XML_SUCCESS;
1526 }
1527 return XML_CAN_NOT_CONVERT_TEXT;
1528 }
1529 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001530}
1531
1532
MortenMacFly4ee49f12013-01-14 20:03:14 +01001533XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001534{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001535 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001536 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001537 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001538 return XML_SUCCESS;
1539 }
1540 return XML_CAN_NOT_CONVERT_TEXT;
1541 }
1542 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001543}
1544
1545
Lee Thomason51c12712016-06-04 20:18:49 -07001546XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1547{
1548 if (FirstChild() && FirstChild()->ToText()) {
1549 const char* t = FirstChild()->Value();
1550 if (XMLUtil::ToInt64(t, ival)) {
1551 return XML_SUCCESS;
1552 }
1553 return XML_CAN_NOT_CONVERT_TEXT;
1554 }
1555 return XML_NO_TEXT_NODE;
1556}
1557
1558
MortenMacFly4ee49f12013-01-14 20:03:14 +01001559XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001560{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001561 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001562 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001563 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001564 return XML_SUCCESS;
1565 }
1566 return XML_CAN_NOT_CONVERT_TEXT;
1567 }
1568 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001569}
1570
1571
MortenMacFly4ee49f12013-01-14 20:03:14 +01001572XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001573{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001574 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001575 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001576 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001577 return XML_SUCCESS;
1578 }
1579 return XML_CAN_NOT_CONVERT_TEXT;
1580 }
1581 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001582}
1583
1584
MortenMacFly4ee49f12013-01-14 20:03:14 +01001585XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001586{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001587 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001588 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001589 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001590 return XML_SUCCESS;
1591 }
1592 return XML_CAN_NOT_CONVERT_TEXT;
1593 }
1594 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001595}
1596
1597
1598
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001599XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1600{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001601 XMLAttribute* last = 0;
1602 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001603 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001604 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001605 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001606 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1607 break;
1608 }
1609 }
1610 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001611 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001612 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1613 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001614 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001615 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001616 }
1617 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001618 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001619 }
1620 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001621 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001622 }
1623 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001624}
1625
1626
U-Stream\Leeae25a442012-02-17 17:48:16 -08001627void XMLElement::DeleteAttribute( const char* name )
1628{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001629 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001630 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001631 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1632 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001633 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001634 }
1635 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001636 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001637 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001638 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001639 break;
1640 }
1641 prev = a;
1642 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001643}
1644
1645
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001646char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001647{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001648 const char* start = p;
1649 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001650
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001651 // Read the attributes.
1652 while( p ) {
1653 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001654 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001655 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001656 return 0;
1657 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001658
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001659 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001660 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001661 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001662 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1663 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001664 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001665
Lee Thomason624d43f2012-10-12 10:58:48 -07001666 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001667 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001668 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001669 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001670 return 0;
1671 }
1672 // There is a minor bug here: if the attribute in the source xml
1673 // document is duplicated, it will not be detected and the
1674 // attribute will be doubly added. However, tracking the 'prevAttribute'
1675 // avoids re-scanning the attribute list. Preferring performance for
1676 // now, may reconsider in the future.
1677 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001678 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001679 }
1680 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001681 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001682 }
1683 prevAttribute = attrib;
1684 }
1685 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001686 else if ( *p == '>' ) {
1687 ++p;
1688 break;
1689 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001690 // end of the tag
1691 else if ( *p == '/' && *(p+1) == '>' ) {
1692 _closingType = CLOSED;
1693 return p+2; // done; sealed element.
1694 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001695 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001696 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001697 return 0;
1698 }
1699 }
1700 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001701}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001702
Dmitry-Mee3225b12014-09-03 11:03:11 +04001703void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1704{
1705 if ( attribute == 0 ) {
1706 return;
1707 }
1708 MemPool* pool = attribute->_memPool;
1709 attribute->~XMLAttribute();
1710 pool->Free( attribute );
1711}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001712
Lee Thomason67d61312012-01-24 16:01:51 -08001713//
1714// <ele></ele>
1715// <ele>foo<b>bar</b></ele>
1716//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001717char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001718{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001719 // Read the element name.
1720 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001721
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001722 // The closing element is the </element> form. It is
1723 // parsed just like a regular element then deleted from
1724 // the DOM.
1725 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001726 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001727 ++p;
1728 }
Lee Thomason67d61312012-01-24 16:01:51 -08001729
Lee Thomason624d43f2012-10-12 10:58:48 -07001730 p = _value.ParseName( p );
1731 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001732 return 0;
1733 }
Lee Thomason67d61312012-01-24 16:01:51 -08001734
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001735 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001736 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001737 return p;
1738 }
Lee Thomason67d61312012-01-24 16:01:51 -08001739
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001740 p = XMLNode::ParseDeep( p, strPair );
1741 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001742}
1743
1744
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001745
1746XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1747{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001748 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001749 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001750 }
1751 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1752 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1753 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1754 }
1755 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001756}
1757
1758
1759bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1760{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001761 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001762 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001763 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001764
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001765 const XMLAttribute* a=FirstAttribute();
1766 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001767
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001768 while ( a && b ) {
1769 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1770 return false;
1771 }
1772 a = a->Next();
1773 b = b->Next();
1774 }
1775 if ( a || b ) {
1776 // different count
1777 return false;
1778 }
1779 return true;
1780 }
1781 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001782}
1783
1784
Lee Thomason751da522012-02-10 08:50:51 -08001785bool XMLElement::Accept( XMLVisitor* visitor ) const
1786{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001787 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001788 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001789 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1790 if ( !node->Accept( visitor ) ) {
1791 break;
1792 }
1793 }
1794 }
1795 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001796}
Lee Thomason56bdd022012-02-09 18:16:58 -08001797
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001798
Lee Thomason3f57d272012-01-11 15:30:03 -08001799// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001800
1801// Warning: List must match 'enum XMLError'
1802const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1803 "XML_SUCCESS",
1804 "XML_NO_ATTRIBUTE",
1805 "XML_WRONG_ATTRIBUTE_TYPE",
1806 "XML_ERROR_FILE_NOT_FOUND",
1807 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1808 "XML_ERROR_FILE_READ_ERROR",
1809 "XML_ERROR_ELEMENT_MISMATCH",
1810 "XML_ERROR_PARSING_ELEMENT",
1811 "XML_ERROR_PARSING_ATTRIBUTE",
1812 "XML_ERROR_IDENTIFYING_TAG",
1813 "XML_ERROR_PARSING_TEXT",
1814 "XML_ERROR_PARSING_CDATA",
1815 "XML_ERROR_PARSING_COMMENT",
1816 "XML_ERROR_PARSING_DECLARATION",
1817 "XML_ERROR_PARSING_UNKNOWN",
1818 "XML_ERROR_EMPTY_DOCUMENT",
1819 "XML_ERROR_MISMATCHED_ELEMENT",
1820 "XML_ERROR_PARSING",
1821 "XML_CAN_NOT_CONVERT_TEXT",
1822 "XML_NO_TEXT_NODE"
1823};
1824
1825
Lee Thomason624d43f2012-10-12 10:58:48 -07001826XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001827 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001828 _writeBOM( false ),
1829 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07001830 _errorID(XML_SUCCESS),
Lee Thomason624d43f2012-10-12 10:58:48 -07001831 _whitespace( whitespace ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001832 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001833{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03001834 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
1835 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08001836}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001837
1838
Lee Thomason3f57d272012-01-11 15:30:03 -08001839XMLDocument::~XMLDocument()
1840{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001841 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001842}
1843
1844
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001845void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001846{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001847 DeleteChildren();
1848
Dmitry-Meab37df82014-11-28 12:08:36 +03001849#ifdef DEBUG
1850 const bool hadError = Error();
1851#endif
Lee Thomason85536252016-06-04 19:10:53 -07001852 _errorID = XML_SUCCESS;
Lee Thomason584af572016-09-05 14:14:16 -07001853 _errorStr1.Reset();
1854 _errorStr2.Reset();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001855
Lee Thomason624d43f2012-10-12 10:58:48 -07001856 delete [] _charBuffer;
1857 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001858
1859#if 0
1860 _textPool.Trace( "text" );
1861 _elementPool.Trace( "element" );
1862 _commentPool.Trace( "comment" );
1863 _attributePool.Trace( "attribute" );
1864#endif
1865
1866#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001867 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001868 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1869 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1870 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1871 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1872 }
1873#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001874}
1875
Lee Thomason3f57d272012-01-11 15:30:03 -08001876
Lee Thomason2c85a712012-01-31 08:24:24 -08001877XMLElement* XMLDocument::NewElement( const char* name )
1878{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001879 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001880 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1881 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001882 ele->SetName( name );
1883 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001884}
1885
1886
Lee Thomason1ff38e02012-02-14 18:18:16 -08001887XMLComment* XMLDocument::NewComment( const char* str )
1888{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001889 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001890 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1891 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001892 comment->SetValue( str );
1893 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001894}
1895
1896
1897XMLText* XMLDocument::NewText( const char* str )
1898{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001899 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001900 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1901 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001902 text->SetValue( str );
1903 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001904}
1905
1906
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001907XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1908{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001909 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001910 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1911 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001912 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1913 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001914}
1915
1916
1917XMLUnknown* XMLDocument::NewUnknown( const char* str )
1918{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001919 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001920 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1921 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001922 unk->SetValue( str );
1923 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001924}
1925
Dmitry-Me01578db2014-08-19 10:18:48 +04001926static FILE* callfopen( const char* filepath, const char* mode )
1927{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001928 TIXMLASSERT( filepath );
1929 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001930#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1931 FILE* fp = 0;
1932 errno_t err = fopen_s( &fp, filepath, mode );
1933 if ( err ) {
1934 return 0;
1935 }
1936#else
1937 FILE* fp = fopen( filepath, mode );
1938#endif
1939 return fp;
1940}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001941
1942void XMLDocument::DeleteNode( XMLNode* node ) {
1943 TIXMLASSERT( node );
1944 TIXMLASSERT(node->_document == this );
1945 if (node->_parent) {
1946 node->_parent->DeleteChild( node );
1947 }
1948 else {
1949 // Isn't in the tree.
1950 // Use the parent delete.
1951 // Also, we need to mark it tracked: we 'know'
1952 // it was never used.
1953 node->_memPool->SetTracked();
1954 // Call the static XMLNode version:
1955 XMLNode::DeleteNode(node);
1956 }
1957}
1958
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001959
Lee Thomason2fa81722012-11-09 12:37:46 -08001960XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001961{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001962 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001963 FILE* fp = callfopen( filename, "rb" );
1964 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001965 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001966 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001967 }
1968 LoadFile( fp );
1969 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001970 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001971}
1972
Dmitry-Me901fed52015-09-25 10:29:51 +03001973// This is likely overengineered template art to have a check that unsigned long value incremented
1974// by one still fits into size_t. If size_t type is larger than unsigned long type
1975// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
1976// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
1977// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
1978// types sizes relate to each other.
1979template
1980<bool = (sizeof(unsigned long) >= sizeof(size_t))>
1981struct LongFitsIntoSizeTMinusOne {
1982 static bool Fits( unsigned long value )
1983 {
1984 return value < (size_t)-1;
1985 }
1986};
1987
1988template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02001989struct LongFitsIntoSizeTMinusOne<false> {
1990 static bool Fits( unsigned long )
1991 {
1992 return true;
1993 }
1994};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001995
Lee Thomason2fa81722012-11-09 12:37:46 -08001996XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001997{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001998 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001999
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002000 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002001 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002002 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2003 return _errorID;
2004 }
2005
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002006 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002007 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002008 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002009 if ( filelength == -1L ) {
2010 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2011 return _errorID;
2012 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002013 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002014
Dmitry-Me901fed52015-09-25 10:29:51 +03002015 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002016 // Cannot handle files which won't fit in buffer together with null terminator
2017 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2018 return _errorID;
2019 }
2020
Dmitry-Me72801b82015-05-07 09:41:39 +03002021 if ( filelength == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06002022 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002023 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002024 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002025
Dmitry-Me72801b82015-05-07 09:41:39 +03002026 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002027 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002028 _charBuffer = new char[size+1];
2029 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002030 if ( read != size ) {
2031 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002032 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002033 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002034
Lee Thomason624d43f2012-10-12 10:58:48 -07002035 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002036
Dmitry-Me97476b72015-01-01 16:15:57 +03002037 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002038 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002039}
2040
2041
Lee Thomason2fa81722012-11-09 12:37:46 -08002042XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002043{
Dmitry-Me01578db2014-08-19 10:18:48 +04002044 FILE* fp = callfopen( filename, "w" );
2045 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002046 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002047 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002048 }
2049 SaveFile(fp, compact);
2050 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002051 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002052}
2053
2054
Lee Thomason2fa81722012-11-09 12:37:46 -08002055XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002056{
Ant Mitchell189198f2015-03-24 16:20:36 +00002057 // Clear any error from the last save, otherwise it will get reported
2058 // for *this* call.
Lee Thomason85536252016-06-04 19:10:53 -07002059 SetError(XML_SUCCESS, 0, 0);
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002060 XMLPrinter stream( fp, compact );
2061 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002062 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002063}
2064
Lee Thomason1ff38e02012-02-14 18:18:16 -08002065
Lee Thomason2fa81722012-11-09 12:37:46 -08002066XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002067{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002068 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002069
Lee Thomason82d32002014-02-21 22:47:18 -08002070 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002071 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002072 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002073 }
2074 if ( len == (size_t)(-1) ) {
2075 len = strlen( p );
2076 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002077 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002078 _charBuffer = new char[ len+1 ];
2079 memcpy( _charBuffer, p, len );
2080 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002081
Dmitry-Me97476b72015-01-01 16:15:57 +03002082 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002083 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002084 // clean up now essentially dangling memory.
2085 // and the parse fail can put objects in the
2086 // pools that are dead and inaccessible.
2087 DeleteChildren();
2088 _elementPool.Clear();
2089 _attributePool.Clear();
2090 _textPool.Clear();
2091 _commentPool.Clear();
2092 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002093 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002094}
2095
2096
PKEuS1c5f99e2013-07-06 11:28:39 +02002097void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002098{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002099 if ( streamer ) {
2100 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002101 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002102 else {
2103 XMLPrinter stdoutStreamer( stdout );
2104 Accept( &stdoutStreamer );
2105 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002106}
2107
2108
Lee Thomason2fa81722012-11-09 12:37:46 -08002109void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08002110{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002111 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002112 _errorID = error;
Lee Thomason584af572016-09-05 14:14:16 -07002113
2114 _errorStr1.Reset();
2115 _errorStr2.Reset();
2116
2117 if (str1)
2118 _errorStr1.SetStr(str1);
2119 if (str2)
2120 _errorStr2.SetStr(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 Thomason584af572016-09-05 14:14:16 -07002138 if ( !_errorStr1.Empty() ) {
2139 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002140 }
Lee Thomason584af572016-09-05 14:14:16 -07002141 if ( !_errorStr2.Empty() ) {
2142 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2.GetStr() );
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