blob: 0a28f68f8923004d4f0957eaef32dea833207d6a [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{
Dmitry-Mef9f3c3e2016-08-30 15:51:55 +0300194 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700195 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800196
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400197 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700198 char endChar = *endTag;
199 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800200
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700201 // Inner loop of text parsing.
202 while ( *p ) {
203 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
204 Set( start, p, strFlags );
205 return p + length;
206 }
207 ++p;
Dmitry-Mef9f3c3e2016-08-30 15:51:55 +0300208 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700209 }
210 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800211}
212
213
214char* StrPair::ParseName( char* p )
215{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400216 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700217 return 0;
218 }
JayXonee525db2014-12-24 04:01:42 -0500219 if ( !XMLUtil::IsNameStartChar( *p ) ) {
220 return 0;
221 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800222
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400223 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500224 ++p;
225 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700226 ++p;
227 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800228
JayXonee525db2014-12-24 04:01:42 -0500229 Set( start, p, 0 );
230 return p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800231}
232
233
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700234void StrPair::CollapseWhitespace()
235{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400236 // Adjusting _start would cause undefined behavior on delete[]
237 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700238 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700239 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700240
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300241 if ( *_start ) {
Lee Thomason120b3a62012-10-12 10:06:59 -0700242 char* p = _start; // the read pointer
243 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700244
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700245 while( *p ) {
246 if ( XMLUtil::IsWhiteSpace( *p )) {
247 p = XMLUtil::SkipWhiteSpace( p );
248 if ( *p == 0 ) {
249 break; // don't write to q; this trims the trailing space.
250 }
251 *q = ' ';
252 ++q;
253 }
254 *q = *p;
255 ++q;
256 ++p;
257 }
258 *q = 0;
259 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700260}
261
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800262
Lee Thomasone4422302012-01-20 17:59:50 -0800263const char* StrPair::GetStr()
264{
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300265 TIXMLASSERT( _start );
266 TIXMLASSERT( _end );
Lee Thomason120b3a62012-10-12 10:06:59 -0700267 if ( _flags & NEEDS_FLUSH ) {
268 *_end = 0;
269 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800270
Lee Thomason120b3a62012-10-12 10:06:59 -0700271 if ( _flags ) {
272 char* p = _start; // the read pointer
273 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800274
Lee Thomason120b3a62012-10-12 10:06:59 -0700275 while( p < _end ) {
276 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700277 // CR-LF pair becomes LF
278 // CR alone becomes LF
279 // LF-CR becomes LF
280 if ( *(p+1) == LF ) {
281 p += 2;
282 }
283 else {
284 ++p;
285 }
286 *q++ = LF;
287 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700288 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700289 if ( *(p+1) == CR ) {
290 p += 2;
291 }
292 else {
293 ++p;
294 }
295 *q++ = LF;
296 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700297 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700298 // Entities handled by tinyXML2:
299 // - special entities in the entity table [in/out]
300 // - numeric character reference [in]
301 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800302
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700303 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400304 const int buflen = 10;
305 char buf[buflen] = { 0 };
306 int len = 0;
Dmitry-Me6f51c802015-03-14 13:25:03 +0300307 char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
308 if ( adjusted == 0 ) {
309 *q = *p;
310 ++p;
311 ++q;
312 }
313 else {
314 TIXMLASSERT( 0 <= len && len <= buflen );
315 TIXMLASSERT( q + len <= adjusted );
316 p = adjusted;
317 memcpy( q, buf, len );
318 q += len;
319 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700320 }
321 else {
Dmitry-Me764545e2015-05-20 10:29:24 +0300322 bool entityFound = false;
323 for( int i = 0; i < NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400324 const Entity& entity = entities[i];
325 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
326 && *( p + entity.length + 1 ) == ';' ) {
327 // Found an entity - convert.
328 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700329 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400330 p += entity.length + 2;
Dmitry-Me764545e2015-05-20 10:29:24 +0300331 entityFound = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700332 break;
333 }
334 }
Dmitry-Me764545e2015-05-20 10:29:24 +0300335 if ( !entityFound ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700336 // fixme: treat as error?
337 ++p;
338 ++q;
339 }
340 }
341 }
342 else {
343 *q = *p;
344 ++p;
345 ++q;
346 }
347 }
348 *q = 0;
349 }
350 // The loop below has plenty going on, and this
351 // is a less useful mode. Break it out.
Dmitry-Me5420e542015-05-20 10:51:26 +0300352 if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700353 CollapseWhitespace();
354 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700355 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700356 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300357 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700358 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800359}
360
Lee Thomason2c85a712012-01-31 08:24:24 -0800361
Lee Thomasone4422302012-01-20 17:59:50 -0800362
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800363
Lee Thomason56bdd022012-02-09 18:16:58 -0800364// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800365
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800366const char* XMLUtil::ReadBOM( const char* p, bool* bom )
367{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300368 TIXMLASSERT( p );
369 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700370 *bom = false;
371 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
372 // Check for BOM:
373 if ( *(pu+0) == TIXML_UTF_LEAD_0
374 && *(pu+1) == TIXML_UTF_LEAD_1
375 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
376 *bom = true;
377 p += 3;
378 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300379 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700380 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800381}
382
383
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800384void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
385{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700386 const unsigned long BYTE_MASK = 0xBF;
387 const unsigned long BYTE_MARK = 0x80;
388 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800389
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700390 if (input < 0x80) {
391 *length = 1;
392 }
393 else if ( input < 0x800 ) {
394 *length = 2;
395 }
396 else if ( input < 0x10000 ) {
397 *length = 3;
398 }
399 else if ( input < 0x200000 ) {
400 *length = 4;
401 }
402 else {
Dmitry-Me2f465c42015-03-16 11:08:23 +0300403 *length = 0; // This code won't convert this correctly anyway.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700404 return;
405 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800406
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700407 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800408
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700409 // Scary scary fall throughs.
410 switch (*length) {
411 case 4:
412 --output;
413 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
414 input >>= 6;
415 case 3:
416 --output;
417 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
418 input >>= 6;
419 case 2:
420 --output;
421 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
422 input >>= 6;
423 case 1:
424 --output;
425 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100426 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300427 default:
428 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700429 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800430}
431
432
433const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
434{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700435 // Presume an entity, and pull it out.
436 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800437
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700438 if ( *(p+1) == '#' && *(p+2) ) {
439 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300440 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700441 ptrdiff_t delta = 0;
442 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800443 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800444
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700445 if ( *(p+2) == 'x' ) {
446 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300447 const char* q = p+3;
448 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700449 return 0;
450 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800451
Lee Thomason7e67bc82015-01-12 14:05:12 -0800452 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800453
Dmitry-Me9f56e122015-01-12 10:07:54 +0300454 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700455 return 0;
456 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800457 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800458
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700459 delta = q-p;
460 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800461
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700462 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700463 unsigned int digit = 0;
464
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700465 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300466 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700467 }
468 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300469 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700470 }
471 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300472 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700473 }
474 else {
475 return 0;
476 }
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100477 TIXMLASSERT( digit < 16 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300478 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
479 const unsigned int digitScaled = mult * digit;
480 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
481 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300482 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700483 mult *= 16;
484 --q;
485 }
486 }
487 else {
488 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300489 const char* q = p+2;
490 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700491 return 0;
492 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800493
Lee Thomason7e67bc82015-01-12 14:05:12 -0800494 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800495
Dmitry-Me9f56e122015-01-12 10:07:54 +0300496 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700497 return 0;
498 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800499 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800500
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700501 delta = q-p;
502 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800503
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700504 while ( *q != '#' ) {
505 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300506 const unsigned int digit = *q - '0';
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100507 TIXMLASSERT( digit < 10 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300508 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
509 const unsigned int digitScaled = mult * digit;
510 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
511 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700512 }
513 else {
514 return 0;
515 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300516 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700517 mult *= 10;
518 --q;
519 }
520 }
521 // convert the UCS to UTF-8
522 ConvertUTF32ToUTF8( ucs, value, length );
523 return p + delta + 1;
524 }
525 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800526}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800527
528
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700529void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700530{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700531 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700532}
533
534
535void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
536{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700537 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700538}
539
540
541void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
542{
Doruk Turakde45d042016-08-28 20:47:08 +0200543 TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? "true" : "false" );
Lee Thomason21be8822012-07-15 17:27:22 -0700544}
545
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800546/*
547 ToStr() of a number is a very tricky topic.
548 https://github.com/leethomason/tinyxml2/issues/106
549*/
Lee Thomason21be8822012-07-15 17:27:22 -0700550void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
551{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800552 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700553}
554
555
556void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
557{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800558 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700559}
560
561
Lee Thomason51c12712016-06-04 20:18:49 -0700562void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize)
563{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700564 // horrible syntax trick to make the compiler happy about %lld
565 TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v);
Lee Thomason51c12712016-06-04 20:18:49 -0700566}
567
568
Lee Thomason21be8822012-07-15 17:27:22 -0700569bool XMLUtil::ToInt( const char* str, int* value )
570{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700571 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
572 return true;
573 }
574 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700575}
576
577bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
578{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700579 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
580 return true;
581 }
582 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700583}
584
585bool XMLUtil::ToBool( const char* str, bool* value )
586{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700587 int ival = 0;
588 if ( ToInt( str, &ival )) {
589 *value = (ival==0) ? false : true;
590 return true;
591 }
592 if ( StringEqual( str, "true" ) ) {
593 *value = true;
594 return true;
595 }
596 else if ( StringEqual( str, "false" ) ) {
597 *value = false;
598 return true;
599 }
600 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700601}
602
603
604bool XMLUtil::ToFloat( const char* str, float* value )
605{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700606 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
607 return true;
608 }
609 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700610}
611
Lee Thomason51c12712016-06-04 20:18:49 -0700612
Lee Thomason21be8822012-07-15 17:27:22 -0700613bool XMLUtil::ToDouble( const char* str, double* value )
614{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700615 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
616 return true;
617 }
618 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700619}
620
621
Lee Thomason51c12712016-06-04 20:18:49 -0700622bool XMLUtil::ToInt64(const char* str, int64_t* value)
623{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700624 long long v = 0; // horrible syntax trick to make the compiler happy about %lld
625 if (TIXML_SSCANF(str, "%lld", &v) == 1) {
626 *value = (int64_t)v;
Lee Thomason51c12712016-06-04 20:18:49 -0700627 return true;
628 }
629 return false;
630}
631
632
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700633char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800634{
Dmitry-Me02384662015-03-03 16:02:13 +0300635 TIXMLASSERT( node );
636 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400637 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700638 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300639 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300640 *node = 0;
641 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700642 return p;
643 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800644
Dmitry-Me962083b2015-05-26 11:38:30 +0300645 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700646 static const char* xmlHeader = { "<?" };
647 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700648 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300649 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700650 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800651
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700652 static const int xmlHeaderLen = 2;
653 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700654 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300655 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700656 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800657
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700658 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
659 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400660 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700661 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300662 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700663 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
664 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700665 p += xmlHeaderLen;
666 }
667 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300668 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700669 returnNode = new (_commentPool.Alloc()) XMLComment( this );
670 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700671 p += commentHeaderLen;
672 }
673 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300674 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700675 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700676 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700677 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700678 p += cdataHeaderLen;
679 text->SetCData( true );
680 }
681 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300682 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700683 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
684 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700685 p += dtdHeaderLen;
686 }
687 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300688 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700689 returnNode = new (_elementPool.Alloc()) XMLElement( this );
690 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700691 p += elementHeaderLen;
692 }
693 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300694 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700695 returnNode = new (_textPool.Alloc()) XMLText( this );
696 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700697 p = start; // Back it up, all the text counts.
698 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800699
Dmitry-Me02384662015-03-03 16:02:13 +0300700 TIXMLASSERT( returnNode );
701 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700702 *node = returnNode;
703 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800704}
705
706
Lee Thomason751da522012-02-10 08:50:51 -0800707bool XMLDocument::Accept( XMLVisitor* visitor ) const
708{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300709 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700710 if ( visitor->VisitEnter( *this ) ) {
711 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
712 if ( !node->Accept( visitor ) ) {
713 break;
714 }
715 }
716 }
717 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800718}
Lee Thomason56bdd022012-02-09 18:16:58 -0800719
720
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800721// --------- XMLNode ----------- //
722
723XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700724 _document( doc ),
725 _parent( 0 ),
726 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200727 _prev( 0 ), _next( 0 ),
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700728 _userData( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200729 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800730{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800731}
732
733
734XMLNode::~XMLNode()
735{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700736 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700737 if ( _parent ) {
738 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700739 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800740}
741
Michael Daumling21626882013-10-22 17:03:37 +0200742const char* XMLNode::Value() const
743{
Dmitry-Mecaa72a62016-08-10 17:34:34 +0300744 // Edge case: XMLDocuments don't have a Value. Return null.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530745 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530746 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200747 return _value.GetStr();
748}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800749
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800750void XMLNode::SetValue( const char* str, bool staticMem )
751{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700752 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700753 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700754 }
755 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700756 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700757 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800758}
759
760
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800761void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800762{
Lee Thomason624d43f2012-10-12 10:58:48 -0700763 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300764 TIXMLASSERT( _lastChild );
Dmitry-Me9cb4eca2016-08-18 18:10:59 +0300765 DeleteChild( _firstChild );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700766 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700767 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800768}
769
770
771void XMLNode::Unlink( XMLNode* child )
772{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300773 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300774 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300775 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700776 if ( child == _firstChild ) {
777 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700778 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700779 if ( child == _lastChild ) {
780 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700781 }
Lee Thomasond923c672012-01-23 08:44:25 -0800782
Lee Thomason624d43f2012-10-12 10:58:48 -0700783 if ( child->_prev ) {
784 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700785 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700786 if ( child->_next ) {
787 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700788 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700789 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800790}
791
792
U-Stream\Leeae25a442012-02-17 17:48:16 -0800793void XMLNode::DeleteChild( XMLNode* node )
794{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300795 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300796 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700797 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100798 Unlink( node );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400799 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800800}
801
802
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800803XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
804{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300805 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300806 if ( addThis->_document != _document ) {
807 TIXMLASSERT( false );
808 return 0;
809 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800810 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700811
Lee Thomason624d43f2012-10-12 10:58:48 -0700812 if ( _lastChild ) {
813 TIXMLASSERT( _firstChild );
814 TIXMLASSERT( _lastChild->_next == 0 );
815 _lastChild->_next = addThis;
816 addThis->_prev = _lastChild;
817 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800818
Lee Thomason624d43f2012-10-12 10:58:48 -0700819 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700820 }
821 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700822 TIXMLASSERT( _firstChild == 0 );
823 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800824
Lee Thomason624d43f2012-10-12 10:58:48 -0700825 addThis->_prev = 0;
826 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700827 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700828 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700829 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800830}
831
832
Lee Thomason1ff38e02012-02-14 18:18:16 -0800833XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
834{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300835 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300836 if ( addThis->_document != _document ) {
837 TIXMLASSERT( false );
838 return 0;
839 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800840 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700841
Lee Thomason624d43f2012-10-12 10:58:48 -0700842 if ( _firstChild ) {
843 TIXMLASSERT( _lastChild );
844 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800845
Lee Thomason624d43f2012-10-12 10:58:48 -0700846 _firstChild->_prev = addThis;
847 addThis->_next = _firstChild;
848 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800849
Lee Thomason624d43f2012-10-12 10:58:48 -0700850 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700851 }
852 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700853 TIXMLASSERT( _lastChild == 0 );
854 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800855
Lee Thomason624d43f2012-10-12 10:58:48 -0700856 addThis->_prev = 0;
857 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700858 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700859 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400860 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800861}
862
863
864XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
865{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300866 TIXMLASSERT( addThis );
867 if ( addThis->_document != _document ) {
868 TIXMLASSERT( false );
869 return 0;
870 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700871
Dmitry-Meabb2d042014-12-09 12:59:31 +0300872 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700873
Lee Thomason624d43f2012-10-12 10:58:48 -0700874 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300875 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700876 return 0;
877 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800878
Lee Thomason624d43f2012-10-12 10:58:48 -0700879 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700880 // The last node or the only node.
881 return InsertEndChild( addThis );
882 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800883 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700884 addThis->_prev = afterThis;
885 addThis->_next = afterThis->_next;
886 afterThis->_next->_prev = addThis;
887 afterThis->_next = addThis;
888 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700889 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800890}
891
892
893
894
Dmitry-Me886ad972015-07-22 11:00:51 +0300895const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800896{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300897 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
898 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700899 if ( element ) {
Dmitry-Me886ad972015-07-22 11:00:51 +0300900 if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700901 return element;
902 }
903 }
904 }
905 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800906}
907
908
Dmitry-Me886ad972015-07-22 11:00:51 +0300909const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800910{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300911 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
912 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700913 if ( element ) {
Dmitry-Me886ad972015-07-22 11:00:51 +0300914 if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700915 return element;
916 }
917 }
918 }
919 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800920}
921
922
Dmitry-Me886ad972015-07-22 11:00:51 +0300923const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800924{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300925 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400926 const XMLElement* element = node->ToElement();
927 if ( element
Dmitry-Me886ad972015-07-22 11:00:51 +0300928 && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400929 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700930 }
931 }
932 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800933}
934
935
Dmitry-Me886ad972015-07-22 11:00:51 +0300936const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800937{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300938 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400939 const XMLElement* element = node->ToElement();
940 if ( element
Dmitry-Me886ad972015-07-22 11:00:51 +0300941 && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400942 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700943 }
944 }
945 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800946}
947
948
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800949char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800950{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700951 // This is a recursive method, but thinking about it "at the current level"
952 // it is a pretty simple flat list:
953 // <foo/>
954 // <!-- comment -->
955 //
956 // With a special case:
957 // <foo>
958 // </foo>
959 // <!-- comment -->
960 //
961 // Where the closing element (/foo) *must* be the next thing after the opening
962 // element, and the names must match. BUT the tricky bit is that the closing
963 // element will be read by the child.
964 //
965 // 'endTag' is the end tag for this node, it is returned by a call to a child.
966 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800967
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700968 while( p && *p ) {
969 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800970
Lee Thomason624d43f2012-10-12 10:58:48 -0700971 p = _document->Identify( p, &node );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300972 if ( node == 0 ) {
973 break;
974 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800975
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700976 StrPair endTag;
977 p = node->ParseDeep( p, &endTag );
978 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400979 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700980 if ( !_document->Error() ) {
981 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700982 }
983 break;
984 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800985
Sarat Addepalli3df007e2015-05-20 10:43:51 +0530986 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530987 if ( decl ) {
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530988 // A declaration can only be the first child of a document.
989 // Set error, if document already has children.
990 if ( !_document->NoChildren() ) {
991 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0);
Dmitry-Me4de7abb2016-08-10 17:30:02 +0300992 DeleteNode( node );
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530993 break;
994 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530995 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530996
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400997 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700998 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -0500999 // We read the end tag. Return it to the parent.
1000 if ( ele->ClosingType() == XMLElement::CLOSING ) {
1001 if ( parentEnd ) {
1002 ele->_value.TransferTo( parentEnd );
1003 }
1004 node->_memPool->SetTracked(); // created and then immediately deleted.
1005 DeleteNode( node );
1006 return p;
1007 }
1008
1009 // Handle an end tag returned to this level.
1010 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001011 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001012 if ( endTag.Empty() ) {
1013 if ( ele->ClosingType() == XMLElement::OPEN ) {
1014 mismatch = true;
1015 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001016 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001017 else {
1018 if ( ele->ClosingType() != XMLElement::OPEN ) {
1019 mismatch = true;
1020 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001021 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001022 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001023 }
1024 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001025 if ( mismatch ) {
Dmitry-Me886ad972015-07-22 11:00:51 +03001026 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -05001027 DeleteNode( node );
1028 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001029 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001030 }
JayXondbfdd8f2014-12-12 20:07:14 -05001031 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001032 }
1033 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001034}
1035
Dmitry-Mee3225b12014-09-03 11:03:11 +04001036void XMLNode::DeleteNode( XMLNode* node )
1037{
1038 if ( node == 0 ) {
1039 return;
1040 }
1041 MemPool* pool = node->_memPool;
1042 node->~XMLNode();
1043 pool->Free( node );
1044}
1045
Lee Thomason3cebdc42015-01-05 17:16:28 -08001046void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001047{
1048 TIXMLASSERT( insertThis );
1049 TIXMLASSERT( insertThis->_document == _document );
1050
1051 if ( insertThis->_parent )
1052 insertThis->_parent->Unlink( insertThis );
1053 else
1054 insertThis->_memPool->SetTracked();
1055}
1056
Lee Thomason5492a1c2012-01-23 15:32:10 -08001057// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001058char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001059{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001060 const char* start = p;
1061 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001062 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001063 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001064 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001065 }
1066 return p;
1067 }
1068 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001069 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1070 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001071 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001072 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001073
Lee Thomason624d43f2012-10-12 10:58:48 -07001074 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001075 if ( p && *p ) {
1076 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001077 }
1078 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +03001079 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001080 }
1081 }
1082 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001083}
1084
1085
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001086XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1087{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001088 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001089 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001090 }
1091 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1092 text->SetCData( this->CData() );
1093 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001094}
1095
1096
1097bool XMLText::ShallowEqual( const XMLNode* compare ) const
1098{
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001099 const XMLText* text = compare->ToText();
1100 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001101}
1102
1103
Lee Thomason56bdd022012-02-09 18:16:58 -08001104bool XMLText::Accept( XMLVisitor* visitor ) const
1105{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001106 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001107 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001108}
1109
1110
Lee Thomason3f57d272012-01-11 15:30:03 -08001111// --------- XMLComment ---------- //
1112
Lee Thomasone4422302012-01-20 17:59:50 -08001113XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001114{
1115}
1116
1117
Lee Thomasonce0763e2012-01-11 15:43:54 -08001118XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001119{
Lee Thomason3f57d272012-01-11 15:30:03 -08001120}
1121
1122
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001123char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -08001124{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001125 // Comment parses as text.
1126 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001127 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001128 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001129 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001130 }
1131 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001132}
1133
1134
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001135XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1136{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001137 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001138 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001139 }
1140 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1141 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001142}
1143
1144
1145bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1146{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001147 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001148 const XMLComment* comment = compare->ToComment();
1149 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001150}
1151
1152
Lee Thomason751da522012-02-10 08:50:51 -08001153bool XMLComment::Accept( XMLVisitor* visitor ) const
1154{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001155 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001156 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001157}
Lee Thomason56bdd022012-02-09 18:16:58 -08001158
1159
Lee Thomason50f97b22012-02-11 16:33:40 -08001160// --------- XMLDeclaration ---------- //
1161
1162XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1163{
1164}
1165
1166
1167XMLDeclaration::~XMLDeclaration()
1168{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001169 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001170}
1171
1172
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001173char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001174{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001175 // Declaration parses as text.
1176 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001177 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001178 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001179 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001180 }
1181 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001182}
1183
1184
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001185XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1186{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001187 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001188 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001189 }
1190 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1191 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001192}
1193
1194
1195bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1196{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001197 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001198 const XMLDeclaration* declaration = compare->ToDeclaration();
1199 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001200}
1201
1202
1203
Lee Thomason50f97b22012-02-11 16:33:40 -08001204bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1205{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001206 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001207 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001208}
1209
1210// --------- XMLUnknown ---------- //
1211
1212XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1213{
1214}
1215
1216
1217XMLUnknown::~XMLUnknown()
1218{
1219}
1220
1221
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001222char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001223{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001224 // Unknown parses as text.
1225 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001226
Lee Thomason624d43f2012-10-12 10:58:48 -07001227 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001228 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001229 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001230 }
1231 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001232}
1233
1234
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001235XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1236{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001237 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001238 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001239 }
1240 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1241 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001242}
1243
1244
1245bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1246{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001247 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001248 const XMLUnknown* unknown = compare->ToUnknown();
1249 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001250}
1251
1252
Lee Thomason50f97b22012-02-11 16:33:40 -08001253bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1254{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001255 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001256 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001257}
1258
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001259// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001260
1261const char* XMLAttribute::Name() const
1262{
1263 return _name.GetStr();
1264}
1265
1266const char* XMLAttribute::Value() const
1267{
1268 return _value.GetStr();
1269}
1270
Lee Thomason6f381b72012-03-02 12:59:39 -08001271char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001272{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001273 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001274 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001275 if ( !p || !*p ) {
1276 return 0;
1277 }
Lee Thomason22aead12012-01-23 13:29:35 -08001278
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001279 // Skip white space before =
1280 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001281 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001282 return 0;
1283 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001284
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001285 ++p; // move up to opening quote
1286 p = XMLUtil::SkipWhiteSpace( p );
1287 if ( *p != '\"' && *p != '\'' ) {
1288 return 0;
1289 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001290
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001291 char endTag[2] = { *p, 0 };
1292 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001293
Lee Thomason624d43f2012-10-12 10:58:48 -07001294 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001295 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001296}
1297
1298
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001299void XMLAttribute::SetName( const char* n )
1300{
Lee Thomason624d43f2012-10-12 10:58:48 -07001301 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001302}
1303
1304
Lee Thomason2fa81722012-11-09 12:37:46 -08001305XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001306{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001307 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001308 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001309 }
1310 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001311}
1312
1313
Lee Thomason2fa81722012-11-09 12:37:46 -08001314XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001315{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001316 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001317 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001318 }
1319 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001320}
1321
1322
Lee Thomason51c12712016-06-04 20:18:49 -07001323XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1324{
1325 if (XMLUtil::ToInt64(Value(), value)) {
1326 return XML_SUCCESS;
1327 }
1328 return XML_WRONG_ATTRIBUTE_TYPE;
1329}
1330
1331
Lee Thomason2fa81722012-11-09 12:37:46 -08001332XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001333{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001334 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001335 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001336 }
1337 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001338}
1339
1340
Lee Thomason2fa81722012-11-09 12:37:46 -08001341XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001342{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001343 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001344 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001345 }
1346 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001347}
1348
1349
Lee Thomason2fa81722012-11-09 12:37:46 -08001350XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001351{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001352 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001353 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001354 }
1355 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001356}
1357
1358
1359void XMLAttribute::SetAttribute( const char* v )
1360{
Lee Thomason624d43f2012-10-12 10:58:48 -07001361 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001362}
1363
1364
Lee Thomason1ff38e02012-02-14 18:18:16 -08001365void XMLAttribute::SetAttribute( int v )
1366{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001367 char buf[BUF_SIZE];
1368 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001369 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001370}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001371
1372
1373void XMLAttribute::SetAttribute( unsigned v )
1374{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001375 char buf[BUF_SIZE];
1376 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001377 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001378}
1379
1380
Lee Thomason51c12712016-06-04 20:18:49 -07001381void XMLAttribute::SetAttribute(int64_t v)
1382{
1383 char buf[BUF_SIZE];
1384 XMLUtil::ToStr(v, buf, BUF_SIZE);
1385 _value.SetStr(buf);
1386}
1387
1388
1389
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001390void XMLAttribute::SetAttribute( bool v )
1391{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001392 char buf[BUF_SIZE];
1393 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001394 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001395}
1396
1397void XMLAttribute::SetAttribute( double v )
1398{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001399 char buf[BUF_SIZE];
1400 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001401 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001402}
1403
1404void XMLAttribute::SetAttribute( float v )
1405{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001406 char buf[BUF_SIZE];
1407 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001408 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001409}
1410
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001411
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001412// --------- XMLElement ---------- //
1413XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001414 _closingType( 0 ),
1415 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001416{
1417}
1418
1419
1420XMLElement::~XMLElement()
1421{
Lee Thomason624d43f2012-10-12 10:58:48 -07001422 while( _rootAttribute ) {
1423 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001424 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001425 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001426 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001427}
1428
1429
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001430const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1431{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001432 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001433 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1434 return a;
1435 }
1436 }
1437 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001438}
1439
1440
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001441const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001442{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001443 const XMLAttribute* a = FindAttribute( name );
1444 if ( !a ) {
1445 return 0;
1446 }
1447 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1448 return a->Value();
1449 }
1450 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001451}
1452
1453
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001454const char* XMLElement::GetText() const
1455{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001456 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001457 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001458 }
1459 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001460}
1461
1462
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001463void XMLElement::SetText( const char* inText )
1464{
Uli Kusterer869bb592014-01-21 01:36:16 +01001465 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001466 FirstChild()->SetValue( inText );
1467 else {
1468 XMLText* theText = GetDocument()->NewText( inText );
1469 InsertFirstChild( theText );
1470 }
1471}
1472
Lee Thomason5bb2d802014-01-24 10:42:57 -08001473
1474void XMLElement::SetText( int v )
1475{
1476 char buf[BUF_SIZE];
1477 XMLUtil::ToStr( v, buf, BUF_SIZE );
1478 SetText( buf );
1479}
1480
1481
1482void XMLElement::SetText( unsigned v )
1483{
1484 char buf[BUF_SIZE];
1485 XMLUtil::ToStr( v, buf, BUF_SIZE );
1486 SetText( buf );
1487}
1488
1489
Lee Thomason51c12712016-06-04 20:18:49 -07001490void XMLElement::SetText(int64_t v)
1491{
1492 char buf[BUF_SIZE];
1493 XMLUtil::ToStr(v, buf, BUF_SIZE);
1494 SetText(buf);
1495}
1496
1497
1498void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001499{
1500 char buf[BUF_SIZE];
1501 XMLUtil::ToStr( v, buf, BUF_SIZE );
1502 SetText( buf );
1503}
1504
1505
1506void XMLElement::SetText( float v )
1507{
1508 char buf[BUF_SIZE];
1509 XMLUtil::ToStr( v, buf, BUF_SIZE );
1510 SetText( buf );
1511}
1512
1513
1514void XMLElement::SetText( double v )
1515{
1516 char buf[BUF_SIZE];
1517 XMLUtil::ToStr( v, buf, BUF_SIZE );
1518 SetText( buf );
1519}
1520
1521
MortenMacFly4ee49f12013-01-14 20:03:14 +01001522XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001523{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001524 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001525 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001526 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001527 return XML_SUCCESS;
1528 }
1529 return XML_CAN_NOT_CONVERT_TEXT;
1530 }
1531 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001532}
1533
1534
MortenMacFly4ee49f12013-01-14 20:03:14 +01001535XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001536{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001537 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001538 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001539 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001540 return XML_SUCCESS;
1541 }
1542 return XML_CAN_NOT_CONVERT_TEXT;
1543 }
1544 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001545}
1546
1547
Lee Thomason51c12712016-06-04 20:18:49 -07001548XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1549{
1550 if (FirstChild() && FirstChild()->ToText()) {
1551 const char* t = FirstChild()->Value();
1552 if (XMLUtil::ToInt64(t, ival)) {
1553 return XML_SUCCESS;
1554 }
1555 return XML_CAN_NOT_CONVERT_TEXT;
1556 }
1557 return XML_NO_TEXT_NODE;
1558}
1559
1560
MortenMacFly4ee49f12013-01-14 20:03:14 +01001561XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001562{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001563 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001564 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001565 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001566 return XML_SUCCESS;
1567 }
1568 return XML_CAN_NOT_CONVERT_TEXT;
1569 }
1570 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001571}
1572
1573
MortenMacFly4ee49f12013-01-14 20:03:14 +01001574XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001575{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001576 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001577 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001578 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001579 return XML_SUCCESS;
1580 }
1581 return XML_CAN_NOT_CONVERT_TEXT;
1582 }
1583 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001584}
1585
1586
MortenMacFly4ee49f12013-01-14 20:03:14 +01001587XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001588{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001589 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001590 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001591 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001592 return XML_SUCCESS;
1593 }
1594 return XML_CAN_NOT_CONVERT_TEXT;
1595 }
1596 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001597}
1598
1599
1600
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001601XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1602{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001603 XMLAttribute* last = 0;
1604 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001605 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001606 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001607 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001608 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1609 break;
1610 }
1611 }
1612 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001613 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001614 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1615 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001616 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001617 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001618 }
1619 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001620 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001621 }
1622 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001623 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001624 }
1625 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001626}
1627
1628
U-Stream\Leeae25a442012-02-17 17:48:16 -08001629void XMLElement::DeleteAttribute( const char* name )
1630{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001631 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001632 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001633 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1634 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001635 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001636 }
1637 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001638 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001639 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001640 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001641 break;
1642 }
1643 prev = a;
1644 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001645}
1646
1647
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001648char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001649{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001650 const char* start = p;
1651 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001652
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001653 // Read the attributes.
1654 while( p ) {
1655 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001656 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001657 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001658 return 0;
1659 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001660
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001661 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001662 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001663 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001664 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1665 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001666 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001667
Lee Thomason624d43f2012-10-12 10:58:48 -07001668 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001669 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001670 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001671 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001672 return 0;
1673 }
1674 // There is a minor bug here: if the attribute in the source xml
1675 // document is duplicated, it will not be detected and the
1676 // attribute will be doubly added. However, tracking the 'prevAttribute'
1677 // avoids re-scanning the attribute list. Preferring performance for
1678 // now, may reconsider in the future.
1679 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001680 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001681 }
1682 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001683 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001684 }
1685 prevAttribute = attrib;
1686 }
1687 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001688 else if ( *p == '>' ) {
1689 ++p;
1690 break;
1691 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001692 // end of the tag
1693 else if ( *p == '/' && *(p+1) == '>' ) {
1694 _closingType = CLOSED;
1695 return p+2; // done; sealed element.
1696 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001697 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001698 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001699 return 0;
1700 }
1701 }
1702 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001703}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001704
Dmitry-Mee3225b12014-09-03 11:03:11 +04001705void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1706{
1707 if ( attribute == 0 ) {
1708 return;
1709 }
1710 MemPool* pool = attribute->_memPool;
1711 attribute->~XMLAttribute();
1712 pool->Free( attribute );
1713}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001714
Lee Thomason67d61312012-01-24 16:01:51 -08001715//
1716// <ele></ele>
1717// <ele>foo<b>bar</b></ele>
1718//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001719char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001720{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001721 // Read the element name.
1722 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001723
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001724 // The closing element is the </element> form. It is
1725 // parsed just like a regular element then deleted from
1726 // the DOM.
1727 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001728 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001729 ++p;
1730 }
Lee Thomason67d61312012-01-24 16:01:51 -08001731
Lee Thomason624d43f2012-10-12 10:58:48 -07001732 p = _value.ParseName( p );
1733 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001734 return 0;
1735 }
Lee Thomason67d61312012-01-24 16:01:51 -08001736
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001737 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001738 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001739 return p;
1740 }
Lee Thomason67d61312012-01-24 16:01:51 -08001741
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001742 p = XMLNode::ParseDeep( p, strPair );
1743 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001744}
1745
1746
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001747
1748XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1749{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001750 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001751 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001752 }
1753 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1754 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1755 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1756 }
1757 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001758}
1759
1760
1761bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1762{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001763 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001764 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001765 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001766
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001767 const XMLAttribute* a=FirstAttribute();
1768 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001769
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001770 while ( a && b ) {
1771 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1772 return false;
1773 }
1774 a = a->Next();
1775 b = b->Next();
1776 }
1777 if ( a || b ) {
1778 // different count
1779 return false;
1780 }
1781 return true;
1782 }
1783 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001784}
1785
1786
Lee Thomason751da522012-02-10 08:50:51 -08001787bool XMLElement::Accept( XMLVisitor* visitor ) const
1788{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001789 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001790 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001791 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1792 if ( !node->Accept( visitor ) ) {
1793 break;
1794 }
1795 }
1796 }
1797 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001798}
Lee Thomason56bdd022012-02-09 18:16:58 -08001799
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001800
Lee Thomason3f57d272012-01-11 15:30:03 -08001801// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001802
1803// Warning: List must match 'enum XMLError'
1804const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1805 "XML_SUCCESS",
1806 "XML_NO_ATTRIBUTE",
1807 "XML_WRONG_ATTRIBUTE_TYPE",
1808 "XML_ERROR_FILE_NOT_FOUND",
1809 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1810 "XML_ERROR_FILE_READ_ERROR",
1811 "XML_ERROR_ELEMENT_MISMATCH",
1812 "XML_ERROR_PARSING_ELEMENT",
1813 "XML_ERROR_PARSING_ATTRIBUTE",
1814 "XML_ERROR_IDENTIFYING_TAG",
1815 "XML_ERROR_PARSING_TEXT",
1816 "XML_ERROR_PARSING_CDATA",
1817 "XML_ERROR_PARSING_COMMENT",
1818 "XML_ERROR_PARSING_DECLARATION",
1819 "XML_ERROR_PARSING_UNKNOWN",
1820 "XML_ERROR_EMPTY_DOCUMENT",
1821 "XML_ERROR_MISMATCHED_ELEMENT",
1822 "XML_ERROR_PARSING",
1823 "XML_CAN_NOT_CONVERT_TEXT",
1824 "XML_NO_TEXT_NODE"
1825};
1826
1827
Lee Thomason624d43f2012-10-12 10:58:48 -07001828XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001829 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001830 _writeBOM( false ),
1831 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07001832 _errorID(XML_SUCCESS),
Lee Thomason624d43f2012-10-12 10:58:48 -07001833 _whitespace( whitespace ),
1834 _errorStr1( 0 ),
1835 _errorStr2( 0 ),
1836 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001837{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03001838 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
1839 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08001840}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001841
1842
Lee Thomason3f57d272012-01-11 15:30:03 -08001843XMLDocument::~XMLDocument()
1844{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001845 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001846}
1847
1848
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001849void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001850{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001851 DeleteChildren();
1852
Dmitry-Meab37df82014-11-28 12:08:36 +03001853#ifdef DEBUG
1854 const bool hadError = Error();
1855#endif
Lee Thomason85536252016-06-04 19:10:53 -07001856 _errorID = XML_SUCCESS;
Lee Thomason624d43f2012-10-12 10:58:48 -07001857 _errorStr1 = 0;
1858 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001859
Lee Thomason624d43f2012-10-12 10:58:48 -07001860 delete [] _charBuffer;
1861 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001862
1863#if 0
1864 _textPool.Trace( "text" );
1865 _elementPool.Trace( "element" );
1866 _commentPool.Trace( "comment" );
1867 _attributePool.Trace( "attribute" );
1868#endif
1869
1870#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001871 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001872 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1873 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1874 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1875 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1876 }
1877#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001878}
1879
Lee Thomason3f57d272012-01-11 15:30:03 -08001880
Lee Thomason2c85a712012-01-31 08:24:24 -08001881XMLElement* XMLDocument::NewElement( const char* name )
1882{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001883 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001884 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1885 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001886 ele->SetName( name );
1887 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001888}
1889
1890
Lee Thomason1ff38e02012-02-14 18:18:16 -08001891XMLComment* XMLDocument::NewComment( const char* str )
1892{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001893 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001894 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1895 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001896 comment->SetValue( str );
1897 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001898}
1899
1900
1901XMLText* XMLDocument::NewText( const char* str )
1902{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001903 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001904 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1905 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001906 text->SetValue( str );
1907 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001908}
1909
1910
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001911XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1912{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001913 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001914 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1915 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001916 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1917 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001918}
1919
1920
1921XMLUnknown* XMLDocument::NewUnknown( const char* str )
1922{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001923 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001924 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1925 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001926 unk->SetValue( str );
1927 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001928}
1929
Dmitry-Me01578db2014-08-19 10:18:48 +04001930static FILE* callfopen( const char* filepath, const char* mode )
1931{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001932 TIXMLASSERT( filepath );
1933 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001934#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1935 FILE* fp = 0;
1936 errno_t err = fopen_s( &fp, filepath, mode );
1937 if ( err ) {
1938 return 0;
1939 }
1940#else
1941 FILE* fp = fopen( filepath, mode );
1942#endif
1943 return fp;
1944}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001945
1946void XMLDocument::DeleteNode( XMLNode* node ) {
1947 TIXMLASSERT( node );
1948 TIXMLASSERT(node->_document == this );
1949 if (node->_parent) {
1950 node->_parent->DeleteChild( node );
1951 }
1952 else {
1953 // Isn't in the tree.
1954 // Use the parent delete.
1955 // Also, we need to mark it tracked: we 'know'
1956 // it was never used.
1957 node->_memPool->SetTracked();
1958 // Call the static XMLNode version:
1959 XMLNode::DeleteNode(node);
1960 }
1961}
1962
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001963
Lee Thomason2fa81722012-11-09 12:37:46 -08001964XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001965{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001966 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001967 FILE* fp = callfopen( filename, "rb" );
1968 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001969 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001970 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001971 }
1972 LoadFile( fp );
1973 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001974 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001975}
1976
Dmitry-Me901fed52015-09-25 10:29:51 +03001977// This is likely overengineered template art to have a check that unsigned long value incremented
1978// by one still fits into size_t. If size_t type is larger than unsigned long type
1979// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
1980// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
1981// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
1982// types sizes relate to each other.
1983template
1984<bool = (sizeof(unsigned long) >= sizeof(size_t))>
1985struct LongFitsIntoSizeTMinusOne {
1986 static bool Fits( unsigned long value )
1987 {
1988 return value < (size_t)-1;
1989 }
1990};
1991
1992template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02001993struct LongFitsIntoSizeTMinusOne<false> {
1994 static bool Fits( unsigned long )
1995 {
1996 return true;
1997 }
1998};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001999
Lee Thomason2fa81722012-11-09 12:37:46 -08002000XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002001{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002002 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002003
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002004 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002005 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002006 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2007 return _errorID;
2008 }
2009
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002010 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002011 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002012 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002013 if ( filelength == -1L ) {
2014 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2015 return _errorID;
2016 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002017 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002018
Dmitry-Me901fed52015-09-25 10:29:51 +03002019 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002020 // Cannot handle files which won't fit in buffer together with null terminator
2021 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2022 return _errorID;
2023 }
2024
Dmitry-Me72801b82015-05-07 09:41:39 +03002025 if ( filelength == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06002026 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002027 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002028 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002029
Dmitry-Me72801b82015-05-07 09:41:39 +03002030 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002031 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002032 _charBuffer = new char[size+1];
2033 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002034 if ( read != size ) {
2035 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002036 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002037 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002038
Lee Thomason624d43f2012-10-12 10:58:48 -07002039 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002040
Dmitry-Me97476b72015-01-01 16:15:57 +03002041 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002042 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002043}
2044
2045
Lee Thomason2fa81722012-11-09 12:37:46 -08002046XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002047{
Dmitry-Me01578db2014-08-19 10:18:48 +04002048 FILE* fp = callfopen( filename, "w" );
2049 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002050 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002051 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002052 }
2053 SaveFile(fp, compact);
2054 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002055 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002056}
2057
2058
Lee Thomason2fa81722012-11-09 12:37:46 -08002059XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002060{
Ant Mitchell189198f2015-03-24 16:20:36 +00002061 // Clear any error from the last save, otherwise it will get reported
2062 // for *this* call.
Lee Thomason85536252016-06-04 19:10:53 -07002063 SetError(XML_SUCCESS, 0, 0);
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002064 XMLPrinter stream( fp, compact );
2065 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002066 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002067}
2068
Lee Thomason1ff38e02012-02-14 18:18:16 -08002069
Lee Thomason2fa81722012-11-09 12:37:46 -08002070XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002071{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002072 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002073
Lee Thomason82d32002014-02-21 22:47:18 -08002074 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002075 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002076 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002077 }
2078 if ( len == (size_t)(-1) ) {
2079 len = strlen( p );
2080 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002081 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002082 _charBuffer = new char[ len+1 ];
2083 memcpy( _charBuffer, p, len );
2084 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002085
Dmitry-Me97476b72015-01-01 16:15:57 +03002086 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002087 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002088 // clean up now essentially dangling memory.
2089 // and the parse fail can put objects in the
2090 // pools that are dead and inaccessible.
2091 DeleteChildren();
2092 _elementPool.Clear();
2093 _attributePool.Clear();
2094 _textPool.Clear();
2095 _commentPool.Clear();
2096 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002097 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002098}
2099
2100
PKEuS1c5f99e2013-07-06 11:28:39 +02002101void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002102{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002103 if ( streamer ) {
2104 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002105 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002106 else {
2107 XMLPrinter stdoutStreamer( stdout );
2108 Accept( &stdoutStreamer );
2109 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002110}
2111
2112
Lee Thomason2fa81722012-11-09 12:37:46 -08002113void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08002114{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002115 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002116 _errorID = error;
2117 _errorStr1 = str1;
2118 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08002119}
2120
Lee Thomason331596e2014-09-11 14:56:43 -07002121const char* XMLDocument::ErrorName() const
2122{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002123 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002124 const char* errorName = _errorNames[_errorID];
2125 TIXMLASSERT( errorName && errorName[0] );
2126 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002127}
Lee Thomason5cae8972012-01-24 18:03:07 -08002128
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002129void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002130{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002131 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002132 static const int LEN = 20;
2133 char buf1[LEN] = { 0 };
2134 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002135
Lee Thomason624d43f2012-10-12 10:58:48 -07002136 if ( _errorStr1 ) {
2137 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002138 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002139 if ( _errorStr2 ) {
2140 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002141 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002142
Dmitry-Me2ad43202015-04-16 12:18:58 +03002143 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2144 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2145 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
Lee Thomason331596e2014-09-11 14:56:43 -07002146 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
Dmitry-Me400f1192015-04-07 11:51:21 +03002147 static_cast<int>( _errorID ), ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002148 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002149}
2150
Dmitry-Me97476b72015-01-01 16:15:57 +03002151void XMLDocument::Parse()
2152{
2153 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2154 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08002155 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03002156 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03002157 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002158 if ( !*p ) {
2159 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2160 return;
2161 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08002162 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002163}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002164
PKEuS1bfb9542013-08-04 13:51:17 +02002165XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002166 _elementJustOpened( false ),
2167 _firstElement( true ),
2168 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002169 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002170 _textDepth( -1 ),
2171 _processEntities( true ),
2172 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002173{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002174 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002175 _entityFlag[i] = false;
2176 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002177 }
2178 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002179 const char entityValue = entities[i].value;
2180 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
2181 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002182 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002183 _restrictedEntityFlag[(unsigned char)'&'] = true;
2184 _restrictedEntityFlag[(unsigned char)'<'] = true;
2185 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002186 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002187}
2188
2189
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002190void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002191{
2192 va_list va;
2193 va_start( va, format );
2194
Lee Thomason624d43f2012-10-12 10:58:48 -07002195 if ( _fp ) {
2196 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002197 }
2198 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002199 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002200 // Close out and re-start the va-args
2201 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002202 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002203 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002204 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002205 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002206 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002207 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002208 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002209}
2210
2211
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002212void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002213{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002214 for( int i=0; i<depth; ++i ) {
2215 Print( " " );
2216 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002217}
2218
2219
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002220void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002221{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002222 // Look for runs of bytes between entities to print.
2223 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002224
Lee Thomason624d43f2012-10-12 10:58:48 -07002225 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002226 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002227 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002228 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002229 // Remember, char is sometimes signed. (How many times has that bitten me?)
2230 if ( *q > 0 && *q < ENTITY_RANGE ) {
2231 // Check for entities. If one is found, flush
2232 // the stream up until the entity, write the
2233 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002234 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002235 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002236 const size_t delta = q - p;
2237 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002238 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002239 Print( "%.*s", toPrint, p );
2240 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002241 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002242 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002243 for( int i=0; i<NUM_ENTITIES; ++i ) {
2244 if ( entities[i].value == *q ) {
2245 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002246 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002247 break;
2248 }
2249 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002250 if ( !entityPatternPrinted ) {
2251 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2252 TIXMLASSERT( false );
2253 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002254 ++p;
2255 }
2256 }
2257 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002258 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002259 }
2260 }
2261 // Flush the remaining string. This will be the entire
2262 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002263 TIXMLASSERT( p <= q );
2264 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002265 Print( "%s", p );
2266 }
Lee Thomason857b8682012-01-25 17:50:25 -08002267}
2268
U-Stream\Leeae25a442012-02-17 17:48:16 -08002269
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002270void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002271{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002272 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002273 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 -07002274 Print( "%s", bom );
2275 }
2276 if ( writeDec ) {
2277 PushDeclaration( "xml version=\"1.0\"" );
2278 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002279}
2280
2281
Uli Kusterer593a33d2014-02-01 12:48:51 +01002282void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002283{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002284 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002285 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002286
Uli Kusterer593a33d2014-02-01 12:48:51 +01002287 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002288 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002289 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002290 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002291 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002292 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002293
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002294 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002295 _elementJustOpened = true;
2296 _firstElement = false;
2297 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002298}
2299
2300
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002301void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002302{
Lee Thomason624d43f2012-10-12 10:58:48 -07002303 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002304 Print( " %s=\"", name );
2305 PrintString( value, false );
2306 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002307}
2308
2309
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002310void XMLPrinter::PushAttribute( const char* name, int v )
2311{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002312 char buf[BUF_SIZE];
2313 XMLUtil::ToStr( v, buf, BUF_SIZE );
2314 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002315}
2316
2317
2318void XMLPrinter::PushAttribute( const char* name, unsigned v )
2319{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002320 char buf[BUF_SIZE];
2321 XMLUtil::ToStr( v, buf, BUF_SIZE );
2322 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002323}
2324
2325
Lee Thomason51c12712016-06-04 20:18:49 -07002326void XMLPrinter::PushAttribute(const char* name, int64_t v)
2327{
2328 char buf[BUF_SIZE];
2329 XMLUtil::ToStr(v, buf, BUF_SIZE);
2330 PushAttribute(name, buf);
2331}
2332
2333
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002334void XMLPrinter::PushAttribute( const char* name, bool v )
2335{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002336 char buf[BUF_SIZE];
2337 XMLUtil::ToStr( v, buf, BUF_SIZE );
2338 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002339}
2340
2341
2342void XMLPrinter::PushAttribute( const char* name, double v )
2343{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002344 char buf[BUF_SIZE];
2345 XMLUtil::ToStr( v, buf, BUF_SIZE );
2346 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002347}
2348
2349
Uli Kustererca412e82014-02-01 13:35:05 +01002350void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002351{
Lee Thomason624d43f2012-10-12 10:58:48 -07002352 --_depth;
2353 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002354
Lee Thomason624d43f2012-10-12 10:58:48 -07002355 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002356 Print( "/>" );
2357 }
2358 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002359 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002360 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002361 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002362 }
2363 Print( "</%s>", name );
2364 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002365
Lee Thomason624d43f2012-10-12 10:58:48 -07002366 if ( _textDepth == _depth ) {
2367 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002368 }
Uli Kustererca412e82014-02-01 13:35:05 +01002369 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002370 Print( "\n" );
2371 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002372 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002373}
2374
2375
Dmitry-Mea092bc12014-12-23 17:57:05 +03002376void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002377{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002378 if ( !_elementJustOpened ) {
2379 return;
2380 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002381 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002382 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002383}
2384
2385
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002386void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002387{
Lee Thomason624d43f2012-10-12 10:58:48 -07002388 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002389
Dmitry-Mea092bc12014-12-23 17:57:05 +03002390 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002391 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002392 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002393 }
2394 else {
2395 PrintString( text, true );
2396 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002397}
2398
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002399void XMLPrinter::PushText( int64_t value )
2400{
2401 char buf[BUF_SIZE];
2402 XMLUtil::ToStr( value, buf, BUF_SIZE );
2403 PushText( buf, false );
2404}
2405
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002406void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002407{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002408 char buf[BUF_SIZE];
2409 XMLUtil::ToStr( value, buf, BUF_SIZE );
2410 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002411}
2412
2413
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002414void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002415{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002416 char buf[BUF_SIZE];
2417 XMLUtil::ToStr( value, buf, BUF_SIZE );
2418 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002419}
2420
2421
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002422void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002423{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002424 char buf[BUF_SIZE];
2425 XMLUtil::ToStr( value, buf, BUF_SIZE );
2426 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002427}
2428
2429
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002430void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002431{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002432 char buf[BUF_SIZE];
2433 XMLUtil::ToStr( value, buf, BUF_SIZE );
2434 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002435}
2436
2437
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002438void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002439{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002440 char buf[BUF_SIZE];
2441 XMLUtil::ToStr( value, buf, BUF_SIZE );
2442 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002443}
2444
Lee Thomason5cae8972012-01-24 18:03:07 -08002445
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002446void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002447{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002448 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002449 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002450 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002451 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002452 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002453 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002454 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002455}
Lee Thomason751da522012-02-10 08:50:51 -08002456
2457
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002458void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002459{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002460 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002461 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002462 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002463 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002464 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002465 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002466 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002467}
2468
2469
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002470void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002471{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002472 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002473 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002474 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002475 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002476 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002477 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002478 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002479}
2480
2481
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002482bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002483{
Lee Thomason624d43f2012-10-12 10:58:48 -07002484 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002485 if ( doc.HasBOM() ) {
2486 PushHeader( true, false );
2487 }
2488 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002489}
2490
2491
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002492bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002493{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002494 const XMLElement* parentElem = 0;
2495 if ( element.Parent() ) {
2496 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002497 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002498 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002499 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002500 while ( attribute ) {
2501 PushAttribute( attribute->Name(), attribute->Value() );
2502 attribute = attribute->Next();
2503 }
2504 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002505}
2506
2507
Uli Kustererca412e82014-02-01 13:35:05 +01002508bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002509{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002510 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002511 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002512}
2513
2514
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002515bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002516{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002517 PushText( text.Value(), text.CData() );
2518 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002519}
2520
2521
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002522bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002523{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002524 PushComment( comment.Value() );
2525 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002526}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002527
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002528bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002529{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002530 PushDeclaration( declaration.Value() );
2531 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002532}
2533
2534
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002535bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002536{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002537 PushUnknown( unknown.Value() );
2538 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002539}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002540
Lee Thomason685b8952012-11-12 13:00:06 -08002541} // namespace tinyxml2
2542