blob: b181b6715e1822882123ec6bfe50221e33bf540a [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
U-Lama\Lee560bd472011-12-28 19:42:49 -080024#include "tinyxml2.h"
25
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070026#include <new> // yes, this one new style header, is in the Android SDK.
Wilfred van Velzen67abee52016-03-25 14:01:15 +010027#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)
Lee Thomasona9cf3f92012-10-11 16:56:51 -070028# include <stddef.h>
Philipp Kloke358202c2015-07-30 16:02:26 +020029# include <stdarg.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070030#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070031# include <cstddef>
Philipp Kloke358202c2015-07-30 16:02:26 +020032# include <cstdarg>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070033#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080034
Lee Thomason53db4a62015-06-11 22:52:08 -070035#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
Dmitry-Me1ca593c2015-06-22 12:49:32 +030036 // Microsoft Visual Studio, version 2005 and higher. Not WinCE.
Lee Thomason53db4a62015-06-11 22:52:08 -070037 /*int _snprintf_s(
38 char *buffer,
39 size_t sizeOfBuffer,
40 size_t count,
41 const char *format [,
42 argument] ...
43 );*/
PKEuScac75782015-08-15 18:17:27 +020044 static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
Lee Thomason53db4a62015-06-11 22:52:08 -070045 {
46 va_list va;
47 va_start( va, format );
48 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
49 va_end( va );
50 return result;
51 }
52
PKEuScac75782015-08-15 18:17:27 +020053 static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070054 {
55 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
56 return result;
57 }
58
59 #define TIXML_VSCPRINTF _vscprintf
60 #define TIXML_SSCANF sscanf_s
61#elif defined _MSC_VER
62 // Microsoft Visual Studio 2003 and earlier or WinCE
63 #define TIXML_SNPRINTF _snprintf
64 #define TIXML_VSNPRINTF _vsnprintf
65 #define TIXML_SSCANF sscanf
Lee Thomasonaa8566b2015-06-19 16:52:40 -070066 #if (_MSC_VER < 1400 ) && (!defined WINCE)
Lee Thomason53db4a62015-06-11 22:52:08 -070067 // Microsoft Visual Studio 2003 and not WinCE.
68 #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have.
69 #else
70 // Microsoft Visual Studio 2003 and earlier or WinCE.
PKEuScac75782015-08-15 18:17:27 +020071 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070072 {
73 int len = 512;
74 for (;;) {
75 len = len*2;
76 char* str = new char[len]();
77 const int required = _vsnprintf(str, len, format, va);
78 delete[] str;
79 if ( required != -1 ) {
Dmitry-Me1d32e582015-07-27 17:11:51 +030080 TIXMLASSERT( required >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070081 len = required;
82 break;
83 }
84 }
Dmitry-Me1d32e582015-07-27 17:11:51 +030085 TIXMLASSERT( len >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070086 return len;
87 }
88 #endif
89#else
90 // GCC version 3 and higher
91 //#warning( "Using sn* functions." )
92 #define TIXML_SNPRINTF snprintf
93 #define TIXML_VSNPRINTF vsnprintf
PKEuScac75782015-08-15 18:17:27 +020094 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070095 {
96 int len = vsnprintf( 0, 0, format, va );
Dmitry-Me1d32e582015-07-27 17:11:51 +030097 TIXMLASSERT( len >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070098 return len;
99 }
100 #define TIXML_SSCANF sscanf
101#endif
102
103
Lee Thomasone4422302012-01-20 17:59:50 -0800104static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -0800105static const char LF = LINE_FEED;
106static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
107static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -0800108static const char SINGLE_QUOTE = '\'';
109static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -0800110
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800111// Bunch of unicode info at:
112// http://www.unicode.org/faq/utf_bom.html
113// ef bb bf (Microsoft "lead bytes") - designates UTF-8
114
115static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
116static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
117static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800118
Kevin Wojniak04c22d22012-11-08 11:02:22 -0800119namespace tinyxml2
120{
121
Lee Thomason8ee79892012-01-25 17:44:30 -0800122struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700123 const char* pattern;
124 int length;
125 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -0800126};
127
128static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700129static const Entity entities[NUM_ENTITIES] = {
130 { "quot", 4, DOUBLE_QUOTE },
131 { "amp", 3, '&' },
132 { "apos", 4, SINGLE_QUOTE },
133 { "lt", 2, '<' },
134 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -0800135};
136
Lee Thomasonfde6a752012-01-14 18:08:12 -0800137
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800138StrPair::~StrPair()
139{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700140 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800141}
142
143
Lee Thomason29658802014-11-27 22:31:11 -0800144void StrPair::TransferTo( StrPair* other )
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300145{
Lee Thomason29658802014-11-27 22:31:11 -0800146 if ( this == other ) {
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300147 return;
148 }
149 // This in effect implements the assignment operator by "moving"
150 // ownership (as in auto_ptr).
151
Dmitry-Medb02b212016-08-04 17:16:05 +0300152 TIXMLASSERT( other != 0 );
Lee Thomason29658802014-11-27 22:31:11 -0800153 TIXMLASSERT( other->_flags == 0 );
154 TIXMLASSERT( other->_start == 0 );
155 TIXMLASSERT( other->_end == 0 );
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300156
Lee Thomason29658802014-11-27 22:31:11 -0800157 other->Reset();
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300158
Lee Thomason29658802014-11-27 22:31:11 -0800159 other->_flags = _flags;
160 other->_start = _start;
161 other->_end = _end;
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300162
163 _flags = 0;
164 _start = 0;
165 _end = 0;
166}
167
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800168void StrPair::Reset()
169{
Lee Thomason120b3a62012-10-12 10:06:59 -0700170 if ( _flags & NEEDS_DELETE ) {
171 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700172 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700173 _flags = 0;
174 _start = 0;
175 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800176}
177
178
179void StrPair::SetStr( const char* str, int flags )
180{
Dmitry-Me0515fa92015-12-09 11:54:06 +0300181 TIXMLASSERT( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700182 Reset();
183 size_t len = strlen( str );
Dmitry-Me96f38cc2015-08-10 16:45:12 +0300184 TIXMLASSERT( _start == 0 );
Lee Thomason120b3a62012-10-12 10:06:59 -0700185 _start = new char[ len+1 ];
186 memcpy( _start, str, len+1 );
187 _end = _start + len;
188 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800189}
190
191
192char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
193{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700194 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800195
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400196 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700197 char endChar = *endTag;
198 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800199
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700200 // Inner loop of text parsing.
201 while ( *p ) {
202 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
203 Set( start, p, strFlags );
204 return p + length;
205 }
206 ++p;
207 }
208 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800209}
210
211
212char* StrPair::ParseName( char* p )
213{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400214 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700215 return 0;
216 }
JayXonee525db2014-12-24 04:01:42 -0500217 if ( !XMLUtil::IsNameStartChar( *p ) ) {
218 return 0;
219 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800220
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400221 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500222 ++p;
223 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700224 ++p;
225 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800226
JayXonee525db2014-12-24 04:01:42 -0500227 Set( start, p, 0 );
228 return p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800229}
230
231
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700232void StrPair::CollapseWhitespace()
233{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400234 // Adjusting _start would cause undefined behavior on delete[]
235 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700236 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700237 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700238
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300239 if ( *_start ) {
Lee Thomason120b3a62012-10-12 10:06:59 -0700240 char* p = _start; // the read pointer
241 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700242
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700243 while( *p ) {
244 if ( XMLUtil::IsWhiteSpace( *p )) {
245 p = XMLUtil::SkipWhiteSpace( p );
246 if ( *p == 0 ) {
247 break; // don't write to q; this trims the trailing space.
248 }
249 *q = ' ';
250 ++q;
251 }
252 *q = *p;
253 ++q;
254 ++p;
255 }
256 *q = 0;
257 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700258}
259
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800260
Lee Thomasone4422302012-01-20 17:59:50 -0800261const char* StrPair::GetStr()
262{
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300263 TIXMLASSERT( _start );
264 TIXMLASSERT( _end );
Lee Thomason120b3a62012-10-12 10:06:59 -0700265 if ( _flags & NEEDS_FLUSH ) {
266 *_end = 0;
267 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800268
Lee Thomason120b3a62012-10-12 10:06:59 -0700269 if ( _flags ) {
270 char* p = _start; // the read pointer
271 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800272
Lee Thomason120b3a62012-10-12 10:06:59 -0700273 while( p < _end ) {
274 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700275 // CR-LF pair becomes LF
276 // CR alone becomes LF
277 // LF-CR becomes LF
278 if ( *(p+1) == LF ) {
279 p += 2;
280 }
281 else {
282 ++p;
283 }
284 *q++ = LF;
285 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700286 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700287 if ( *(p+1) == CR ) {
288 p += 2;
289 }
290 else {
291 ++p;
292 }
293 *q++ = LF;
294 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700295 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700296 // Entities handled by tinyXML2:
297 // - special entities in the entity table [in/out]
298 // - numeric character reference [in]
299 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800300
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700301 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400302 const int buflen = 10;
303 char buf[buflen] = { 0 };
304 int len = 0;
Dmitry-Me6f51c802015-03-14 13:25:03 +0300305 char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
306 if ( adjusted == 0 ) {
307 *q = *p;
308 ++p;
309 ++q;
310 }
311 else {
312 TIXMLASSERT( 0 <= len && len <= buflen );
313 TIXMLASSERT( q + len <= adjusted );
314 p = adjusted;
315 memcpy( q, buf, len );
316 q += len;
317 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700318 }
319 else {
Dmitry-Me764545e2015-05-20 10:29:24 +0300320 bool entityFound = false;
321 for( int i = 0; i < NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400322 const Entity& entity = entities[i];
323 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
324 && *( p + entity.length + 1 ) == ';' ) {
325 // Found an entity - convert.
326 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700327 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400328 p += entity.length + 2;
Dmitry-Me764545e2015-05-20 10:29:24 +0300329 entityFound = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700330 break;
331 }
332 }
Dmitry-Me764545e2015-05-20 10:29:24 +0300333 if ( !entityFound ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700334 // fixme: treat as error?
335 ++p;
336 ++q;
337 }
338 }
339 }
340 else {
341 *q = *p;
342 ++p;
343 ++q;
344 }
345 }
346 *q = 0;
347 }
348 // The loop below has plenty going on, and this
349 // is a less useful mode. Break it out.
Dmitry-Me5420e542015-05-20 10:51:26 +0300350 if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700351 CollapseWhitespace();
352 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700353 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700354 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300355 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700356 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800357}
358
Lee Thomason2c85a712012-01-31 08:24:24 -0800359
Lee Thomasone4422302012-01-20 17:59:50 -0800360
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800361
Lee Thomason56bdd022012-02-09 18:16:58 -0800362// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800363
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800364const char* XMLUtil::ReadBOM( const char* p, bool* bom )
365{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300366 TIXMLASSERT( p );
367 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700368 *bom = false;
369 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
370 // Check for BOM:
371 if ( *(pu+0) == TIXML_UTF_LEAD_0
372 && *(pu+1) == TIXML_UTF_LEAD_1
373 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
374 *bom = true;
375 p += 3;
376 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300377 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700378 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800379}
380
381
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800382void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
383{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700384 const unsigned long BYTE_MASK = 0xBF;
385 const unsigned long BYTE_MARK = 0x80;
386 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800387
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700388 if (input < 0x80) {
389 *length = 1;
390 }
391 else if ( input < 0x800 ) {
392 *length = 2;
393 }
394 else if ( input < 0x10000 ) {
395 *length = 3;
396 }
397 else if ( input < 0x200000 ) {
398 *length = 4;
399 }
400 else {
Dmitry-Me2f465c42015-03-16 11:08:23 +0300401 *length = 0; // This code won't convert this correctly anyway.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700402 return;
403 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800404
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700405 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800406
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700407 // Scary scary fall throughs.
408 switch (*length) {
409 case 4:
410 --output;
411 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
412 input >>= 6;
413 case 3:
414 --output;
415 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
416 input >>= 6;
417 case 2:
418 --output;
419 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
420 input >>= 6;
421 case 1:
422 --output;
423 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100424 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300425 default:
426 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700427 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800428}
429
430
431const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
432{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700433 // Presume an entity, and pull it out.
434 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800435
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700436 if ( *(p+1) == '#' && *(p+2) ) {
437 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300438 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700439 ptrdiff_t delta = 0;
440 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800441 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800442
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700443 if ( *(p+2) == 'x' ) {
444 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300445 const char* q = p+3;
446 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700447 return 0;
448 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800449
Lee Thomason7e67bc82015-01-12 14:05:12 -0800450 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800451
Dmitry-Me9f56e122015-01-12 10:07:54 +0300452 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700453 return 0;
454 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800455 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800456
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700457 delta = q-p;
458 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800459
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700460 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700461 unsigned int digit = 0;
462
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700463 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300464 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700465 }
466 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300467 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700468 }
469 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300470 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700471 }
472 else {
473 return 0;
474 }
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100475 TIXMLASSERT( digit < 16 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300476 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
477 const unsigned int digitScaled = mult * digit;
478 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
479 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300480 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700481 mult *= 16;
482 --q;
483 }
484 }
485 else {
486 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300487 const char* q = p+2;
488 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700489 return 0;
490 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800491
Lee Thomason7e67bc82015-01-12 14:05:12 -0800492 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800493
Dmitry-Me9f56e122015-01-12 10:07:54 +0300494 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700495 return 0;
496 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800497 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800498
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700499 delta = q-p;
500 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800501
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700502 while ( *q != '#' ) {
503 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300504 const unsigned int digit = *q - '0';
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100505 TIXMLASSERT( digit < 10 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300506 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
507 const unsigned int digitScaled = mult * digit;
508 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
509 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700510 }
511 else {
512 return 0;
513 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300514 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700515 mult *= 10;
516 --q;
517 }
518 }
519 // convert the UCS to UTF-8
520 ConvertUTF32ToUTF8( ucs, value, length );
521 return p + delta + 1;
522 }
523 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800524}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800525
526
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700527void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700528{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700529 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700530}
531
532
533void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
534{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700535 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700536}
537
538
539void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
540{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700541 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700542}
543
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800544/*
545 ToStr() of a number is a very tricky topic.
546 https://github.com/leethomason/tinyxml2/issues/106
547*/
Lee Thomason21be8822012-07-15 17:27:22 -0700548void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
549{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800550 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700551}
552
553
554void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
555{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800556 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700557}
558
559
Lee Thomason51c12712016-06-04 20:18:49 -0700560void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize)
561{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700562 // horrible syntax trick to make the compiler happy about %lld
563 TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v);
Lee Thomason51c12712016-06-04 20:18:49 -0700564}
565
566
Lee Thomason21be8822012-07-15 17:27:22 -0700567bool XMLUtil::ToInt( const char* str, int* value )
568{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700569 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
570 return true;
571 }
572 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700573}
574
575bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
576{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700577 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
578 return true;
579 }
580 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700581}
582
583bool XMLUtil::ToBool( const char* str, bool* value )
584{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700585 int ival = 0;
586 if ( ToInt( str, &ival )) {
587 *value = (ival==0) ? false : true;
588 return true;
589 }
590 if ( StringEqual( str, "true" ) ) {
591 *value = true;
592 return true;
593 }
594 else if ( StringEqual( str, "false" ) ) {
595 *value = false;
596 return true;
597 }
598 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700599}
600
601
602bool XMLUtil::ToFloat( const char* str, float* value )
603{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700604 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
605 return true;
606 }
607 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700608}
609
Lee Thomason51c12712016-06-04 20:18:49 -0700610
Lee Thomason21be8822012-07-15 17:27:22 -0700611bool XMLUtil::ToDouble( const char* str, double* value )
612{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700613 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
614 return true;
615 }
616 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700617}
618
619
Lee Thomason51c12712016-06-04 20:18:49 -0700620bool XMLUtil::ToInt64(const char* str, int64_t* value)
621{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700622 long long v = 0; // horrible syntax trick to make the compiler happy about %lld
623 if (TIXML_SSCANF(str, "%lld", &v) == 1) {
624 *value = (int64_t)v;
Lee Thomason51c12712016-06-04 20:18:49 -0700625 return true;
626 }
627 return false;
628}
629
630
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700631char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800632{
Dmitry-Me02384662015-03-03 16:02:13 +0300633 TIXMLASSERT( node );
634 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400635 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700636 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300637 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300638 *node = 0;
639 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700640 return p;
641 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800642
Dmitry-Me962083b2015-05-26 11:38:30 +0300643 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700644 static const char* xmlHeader = { "<?" };
645 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700646 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300647 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700648 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800649
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700650 static const int xmlHeaderLen = 2;
651 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700652 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300653 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700654 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800655
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700656 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
657 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400658 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700659 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300660 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700661 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
662 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700663 p += xmlHeaderLen;
664 }
665 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300666 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700667 returnNode = new (_commentPool.Alloc()) XMLComment( this );
668 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700669 p += commentHeaderLen;
670 }
671 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300672 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700673 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700674 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700675 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700676 p += cdataHeaderLen;
677 text->SetCData( true );
678 }
679 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300680 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700681 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
682 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700683 p += dtdHeaderLen;
684 }
685 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300686 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700687 returnNode = new (_elementPool.Alloc()) XMLElement( this );
688 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700689 p += elementHeaderLen;
690 }
691 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300692 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700693 returnNode = new (_textPool.Alloc()) XMLText( this );
694 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700695 p = start; // Back it up, all the text counts.
696 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800697
Dmitry-Me02384662015-03-03 16:02:13 +0300698 TIXMLASSERT( returnNode );
699 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700700 *node = returnNode;
701 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800702}
703
704
Lee Thomason751da522012-02-10 08:50:51 -0800705bool XMLDocument::Accept( XMLVisitor* visitor ) const
706{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300707 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700708 if ( visitor->VisitEnter( *this ) ) {
709 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
710 if ( !node->Accept( visitor ) ) {
711 break;
712 }
713 }
714 }
715 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800716}
Lee Thomason56bdd022012-02-09 18:16:58 -0800717
718
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800719// --------- XMLNode ----------- //
720
721XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700722 _document( doc ),
723 _parent( 0 ),
724 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200725 _prev( 0 ), _next( 0 ),
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700726 _userData( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200727 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800728{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800729}
730
731
732XMLNode::~XMLNode()
733{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700734 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700735 if ( _parent ) {
736 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700737 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800738}
739
Michael Daumling21626882013-10-22 17:03:37 +0200740const char* XMLNode::Value() const
741{
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 ),
1832 _errorStr1( 0 ),
1833 _errorStr2( 0 ),
1834 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001835{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03001836 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
1837 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08001838}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001839
1840
Lee Thomason3f57d272012-01-11 15:30:03 -08001841XMLDocument::~XMLDocument()
1842{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001843 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001844}
1845
1846
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001847void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001848{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001849 DeleteChildren();
1850
Dmitry-Meab37df82014-11-28 12:08:36 +03001851#ifdef DEBUG
1852 const bool hadError = Error();
1853#endif
Lee Thomason85536252016-06-04 19:10:53 -07001854 _errorID = XML_SUCCESS;
Lee Thomason624d43f2012-10-12 10:58:48 -07001855 _errorStr1 = 0;
1856 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001857
Lee Thomason624d43f2012-10-12 10:58:48 -07001858 delete [] _charBuffer;
1859 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001860
1861#if 0
1862 _textPool.Trace( "text" );
1863 _elementPool.Trace( "element" );
1864 _commentPool.Trace( "comment" );
1865 _attributePool.Trace( "attribute" );
1866#endif
1867
1868#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001869 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001870 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1871 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1872 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1873 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1874 }
1875#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001876}
1877
Lee Thomason3f57d272012-01-11 15:30:03 -08001878
Lee Thomason2c85a712012-01-31 08:24:24 -08001879XMLElement* XMLDocument::NewElement( const char* name )
1880{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001881 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001882 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1883 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001884 ele->SetName( name );
1885 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001886}
1887
1888
Lee Thomason1ff38e02012-02-14 18:18:16 -08001889XMLComment* XMLDocument::NewComment( const char* str )
1890{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001891 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001892 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1893 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001894 comment->SetValue( str );
1895 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001896}
1897
1898
1899XMLText* XMLDocument::NewText( const char* str )
1900{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001901 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001902 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1903 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001904 text->SetValue( str );
1905 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001906}
1907
1908
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001909XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1910{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001911 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001912 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1913 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001914 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1915 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001916}
1917
1918
1919XMLUnknown* XMLDocument::NewUnknown( const char* str )
1920{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001921 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001922 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1923 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001924 unk->SetValue( str );
1925 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001926}
1927
Dmitry-Me01578db2014-08-19 10:18:48 +04001928static FILE* callfopen( const char* filepath, const char* mode )
1929{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001930 TIXMLASSERT( filepath );
1931 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001932#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1933 FILE* fp = 0;
1934 errno_t err = fopen_s( &fp, filepath, mode );
1935 if ( err ) {
1936 return 0;
1937 }
1938#else
1939 FILE* fp = fopen( filepath, mode );
1940#endif
1941 return fp;
1942}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001943
1944void XMLDocument::DeleteNode( XMLNode* node ) {
1945 TIXMLASSERT( node );
1946 TIXMLASSERT(node->_document == this );
1947 if (node->_parent) {
1948 node->_parent->DeleteChild( node );
1949 }
1950 else {
1951 // Isn't in the tree.
1952 // Use the parent delete.
1953 // Also, we need to mark it tracked: we 'know'
1954 // it was never used.
1955 node->_memPool->SetTracked();
1956 // Call the static XMLNode version:
1957 XMLNode::DeleteNode(node);
1958 }
1959}
1960
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001961
Lee Thomason2fa81722012-11-09 12:37:46 -08001962XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001963{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001964 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001965 FILE* fp = callfopen( filename, "rb" );
1966 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001967 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001968 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001969 }
1970 LoadFile( fp );
1971 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001972 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001973}
1974
Dmitry-Me901fed52015-09-25 10:29:51 +03001975// This is likely overengineered template art to have a check that unsigned long value incremented
1976// by one still fits into size_t. If size_t type is larger than unsigned long type
1977// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
1978// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
1979// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
1980// types sizes relate to each other.
1981template
1982<bool = (sizeof(unsigned long) >= sizeof(size_t))>
1983struct LongFitsIntoSizeTMinusOne {
1984 static bool Fits( unsigned long value )
1985 {
1986 return value < (size_t)-1;
1987 }
1988};
1989
1990template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02001991struct LongFitsIntoSizeTMinusOne<false> {
1992 static bool Fits( unsigned long )
1993 {
1994 return true;
1995 }
1996};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001997
Lee Thomason2fa81722012-11-09 12:37:46 -08001998XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001999{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002000 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002001
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002002 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002003 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002004 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2005 return _errorID;
2006 }
2007
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002008 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002009 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002010 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002011 if ( filelength == -1L ) {
2012 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2013 return _errorID;
2014 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002015 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002016
Dmitry-Me901fed52015-09-25 10:29:51 +03002017 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002018 // Cannot handle files which won't fit in buffer together with null terminator
2019 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2020 return _errorID;
2021 }
2022
Dmitry-Me72801b82015-05-07 09:41:39 +03002023 if ( filelength == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06002024 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002025 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002026 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002027
Dmitry-Me72801b82015-05-07 09:41:39 +03002028 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002029 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002030 _charBuffer = new char[size+1];
2031 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002032 if ( read != size ) {
2033 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002034 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002035 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002036
Lee Thomason624d43f2012-10-12 10:58:48 -07002037 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002038
Dmitry-Me97476b72015-01-01 16:15:57 +03002039 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002040 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002041}
2042
2043
Lee Thomason2fa81722012-11-09 12:37:46 -08002044XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002045{
Dmitry-Me01578db2014-08-19 10:18:48 +04002046 FILE* fp = callfopen( filename, "w" );
2047 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002048 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002049 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002050 }
2051 SaveFile(fp, compact);
2052 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002053 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002054}
2055
2056
Lee Thomason2fa81722012-11-09 12:37:46 -08002057XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002058{
Ant Mitchell189198f2015-03-24 16:20:36 +00002059 // Clear any error from the last save, otherwise it will get reported
2060 // for *this* call.
Lee Thomason85536252016-06-04 19:10:53 -07002061 SetError(XML_SUCCESS, 0, 0);
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002062 XMLPrinter stream( fp, compact );
2063 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002064 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002065}
2066
Lee Thomason1ff38e02012-02-14 18:18:16 -08002067
Lee Thomason2fa81722012-11-09 12:37:46 -08002068XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002069{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002070 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002071
Lee Thomason82d32002014-02-21 22:47:18 -08002072 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002073 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002074 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002075 }
2076 if ( len == (size_t)(-1) ) {
2077 len = strlen( p );
2078 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002079 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002080 _charBuffer = new char[ len+1 ];
2081 memcpy( _charBuffer, p, len );
2082 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002083
Dmitry-Me97476b72015-01-01 16:15:57 +03002084 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002085 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002086 // clean up now essentially dangling memory.
2087 // and the parse fail can put objects in the
2088 // pools that are dead and inaccessible.
2089 DeleteChildren();
2090 _elementPool.Clear();
2091 _attributePool.Clear();
2092 _textPool.Clear();
2093 _commentPool.Clear();
2094 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002095 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002096}
2097
2098
PKEuS1c5f99e2013-07-06 11:28:39 +02002099void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002100{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002101 if ( streamer ) {
2102 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002103 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002104 else {
2105 XMLPrinter stdoutStreamer( stdout );
2106 Accept( &stdoutStreamer );
2107 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002108}
2109
2110
Lee Thomason2fa81722012-11-09 12:37:46 -08002111void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08002112{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002113 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002114 _errorID = error;
2115 _errorStr1 = str1;
2116 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08002117}
2118
Lee Thomason331596e2014-09-11 14:56:43 -07002119const char* XMLDocument::ErrorName() const
2120{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002121 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002122 const char* errorName = _errorNames[_errorID];
2123 TIXMLASSERT( errorName && errorName[0] );
2124 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002125}
Lee Thomason5cae8972012-01-24 18:03:07 -08002126
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002127void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002128{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002129 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002130 static const int LEN = 20;
2131 char buf1[LEN] = { 0 };
2132 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002133
Lee Thomason624d43f2012-10-12 10:58:48 -07002134 if ( _errorStr1 ) {
2135 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002136 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002137 if ( _errorStr2 ) {
2138 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002139 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002140
Dmitry-Me2ad43202015-04-16 12:18:58 +03002141 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2142 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2143 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
Lee Thomason331596e2014-09-11 14:56:43 -07002144 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
Dmitry-Me400f1192015-04-07 11:51:21 +03002145 static_cast<int>( _errorID ), ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002146 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002147}
2148
Dmitry-Me97476b72015-01-01 16:15:57 +03002149void XMLDocument::Parse()
2150{
2151 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2152 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08002153 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03002154 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03002155 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002156 if ( !*p ) {
2157 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2158 return;
2159 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08002160 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002161}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002162
PKEuS1bfb9542013-08-04 13:51:17 +02002163XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002164 _elementJustOpened( false ),
2165 _firstElement( true ),
2166 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002167 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002168 _textDepth( -1 ),
2169 _processEntities( true ),
2170 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002171{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002172 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002173 _entityFlag[i] = false;
2174 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002175 }
2176 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002177 const char entityValue = entities[i].value;
2178 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
2179 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002180 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002181 _restrictedEntityFlag[(unsigned char)'&'] = true;
2182 _restrictedEntityFlag[(unsigned char)'<'] = true;
2183 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002184 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002185}
2186
2187
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002188void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002189{
2190 va_list va;
2191 va_start( va, format );
2192
Lee Thomason624d43f2012-10-12 10:58:48 -07002193 if ( _fp ) {
2194 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002195 }
2196 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002197 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002198 // Close out and re-start the va-args
2199 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002200 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002201 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002202 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002203 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002204 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002205 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002206 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002207}
2208
2209
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002210void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002211{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002212 for( int i=0; i<depth; ++i ) {
2213 Print( " " );
2214 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002215}
2216
2217
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002218void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002219{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002220 // Look for runs of bytes between entities to print.
2221 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002222
Lee Thomason624d43f2012-10-12 10:58:48 -07002223 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002224 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002225 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002226 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002227 // Remember, char is sometimes signed. (How many times has that bitten me?)
2228 if ( *q > 0 && *q < ENTITY_RANGE ) {
2229 // Check for entities. If one is found, flush
2230 // the stream up until the entity, write the
2231 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002232 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002233 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002234 const size_t delta = q - p;
2235 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002236 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002237 Print( "%.*s", toPrint, p );
2238 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002239 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002240 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002241 for( int i=0; i<NUM_ENTITIES; ++i ) {
2242 if ( entities[i].value == *q ) {
2243 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002244 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002245 break;
2246 }
2247 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002248 if ( !entityPatternPrinted ) {
2249 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2250 TIXMLASSERT( false );
2251 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002252 ++p;
2253 }
2254 }
2255 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002256 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002257 }
2258 }
2259 // Flush the remaining string. This will be the entire
2260 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002261 TIXMLASSERT( p <= q );
2262 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002263 Print( "%s", p );
2264 }
Lee Thomason857b8682012-01-25 17:50:25 -08002265}
2266
U-Stream\Leeae25a442012-02-17 17:48:16 -08002267
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002268void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002269{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002270 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002271 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 -07002272 Print( "%s", bom );
2273 }
2274 if ( writeDec ) {
2275 PushDeclaration( "xml version=\"1.0\"" );
2276 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002277}
2278
2279
Uli Kusterer593a33d2014-02-01 12:48:51 +01002280void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002281{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002282 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002283 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002284
Uli Kusterer593a33d2014-02-01 12:48:51 +01002285 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002286 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002287 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002288 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002289 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002290 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002291
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002292 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002293 _elementJustOpened = true;
2294 _firstElement = false;
2295 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002296}
2297
2298
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002299void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002300{
Lee Thomason624d43f2012-10-12 10:58:48 -07002301 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002302 Print( " %s=\"", name );
2303 PrintString( value, false );
2304 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002305}
2306
2307
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002308void XMLPrinter::PushAttribute( const char* name, int v )
2309{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002310 char buf[BUF_SIZE];
2311 XMLUtil::ToStr( v, buf, BUF_SIZE );
2312 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002313}
2314
2315
2316void XMLPrinter::PushAttribute( const char* name, unsigned v )
2317{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002318 char buf[BUF_SIZE];
2319 XMLUtil::ToStr( v, buf, BUF_SIZE );
2320 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002321}
2322
2323
Lee Thomason51c12712016-06-04 20:18:49 -07002324void XMLPrinter::PushAttribute(const char* name, int64_t v)
2325{
2326 char buf[BUF_SIZE];
2327 XMLUtil::ToStr(v, buf, BUF_SIZE);
2328 PushAttribute(name, buf);
2329}
2330
2331
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002332void XMLPrinter::PushAttribute( const char* name, bool v )
2333{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002334 char buf[BUF_SIZE];
2335 XMLUtil::ToStr( v, buf, BUF_SIZE );
2336 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002337}
2338
2339
2340void XMLPrinter::PushAttribute( const char* name, double v )
2341{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002342 char buf[BUF_SIZE];
2343 XMLUtil::ToStr( v, buf, BUF_SIZE );
2344 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002345}
2346
2347
Uli Kustererca412e82014-02-01 13:35:05 +01002348void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002349{
Lee Thomason624d43f2012-10-12 10:58:48 -07002350 --_depth;
2351 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002352
Lee Thomason624d43f2012-10-12 10:58:48 -07002353 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002354 Print( "/>" );
2355 }
2356 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002357 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002358 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002359 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002360 }
2361 Print( "</%s>", name );
2362 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002363
Lee Thomason624d43f2012-10-12 10:58:48 -07002364 if ( _textDepth == _depth ) {
2365 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002366 }
Uli Kustererca412e82014-02-01 13:35:05 +01002367 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002368 Print( "\n" );
2369 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002370 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002371}
2372
2373
Dmitry-Mea092bc12014-12-23 17:57:05 +03002374void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002375{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002376 if ( !_elementJustOpened ) {
2377 return;
2378 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002379 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002380 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002381}
2382
2383
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002384void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002385{
Lee Thomason624d43f2012-10-12 10:58:48 -07002386 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002387
Dmitry-Mea092bc12014-12-23 17:57:05 +03002388 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002389 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002390 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002391 }
2392 else {
2393 PrintString( text, true );
2394 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002395}
2396
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002397void XMLPrinter::PushText( int64_t value )
2398{
2399 char buf[BUF_SIZE];
2400 XMLUtil::ToStr( value, buf, BUF_SIZE );
2401 PushText( buf, false );
2402}
2403
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002404void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002405{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002406 char buf[BUF_SIZE];
2407 XMLUtil::ToStr( value, buf, BUF_SIZE );
2408 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002409}
2410
2411
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002412void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002413{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002414 char buf[BUF_SIZE];
2415 XMLUtil::ToStr( value, buf, BUF_SIZE );
2416 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002417}
2418
2419
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002420void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002421{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002422 char buf[BUF_SIZE];
2423 XMLUtil::ToStr( value, buf, BUF_SIZE );
2424 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002425}
2426
2427
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002428void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002429{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002430 char buf[BUF_SIZE];
2431 XMLUtil::ToStr( value, buf, BUF_SIZE );
2432 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002433}
2434
2435
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002436void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002437{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002438 char buf[BUF_SIZE];
2439 XMLUtil::ToStr( value, buf, BUF_SIZE );
2440 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002441}
2442
Lee Thomason5cae8972012-01-24 18:03:07 -08002443
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002444void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002445{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002446 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002447 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002448 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002449 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002450 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002451 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002452 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002453}
Lee Thomason751da522012-02-10 08:50:51 -08002454
2455
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002456void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002457{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002458 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002459 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002460 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002461 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002462 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002463 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002464 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002465}
2466
2467
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002468void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002469{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002470 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002471 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002472 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002473 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002474 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002475 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002476 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002477}
2478
2479
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002480bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002481{
Lee Thomason624d43f2012-10-12 10:58:48 -07002482 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002483 if ( doc.HasBOM() ) {
2484 PushHeader( true, false );
2485 }
2486 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002487}
2488
2489
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002490bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002491{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002492 const XMLElement* parentElem = 0;
2493 if ( element.Parent() ) {
2494 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002495 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002496 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002497 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002498 while ( attribute ) {
2499 PushAttribute( attribute->Name(), attribute->Value() );
2500 attribute = attribute->Next();
2501 }
2502 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002503}
2504
2505
Uli Kustererca412e82014-02-01 13:35:05 +01002506bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002507{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002508 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002509 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002510}
2511
2512
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002513bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002514{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002515 PushText( text.Value(), text.CData() );
2516 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002517}
2518
2519
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002520bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002521{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002522 PushComment( comment.Value() );
2523 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002524}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002525
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002526bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002527{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002528 PushDeclaration( declaration.Value() );
2529 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002530}
2531
2532
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002533bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002534{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002535 PushUnknown( unknown.Value() );
2536 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002537}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002538
Lee Thomason685b8952012-11-12 13:00:06 -08002539} // namespace tinyxml2
2540