blob: 5ce806a17ac96488ff4fc887be6ecd3ea3a09daa [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 ) {
Dmitry-Me24495822016-09-02 16:53:32 +0300242 const char* p = _start; // the read pointer
Lee Thomason120b3a62012-10-12 10:06:59 -0700243 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 ) {
Dmitry-Me24495822016-09-02 16:53:32 +0300272 const char* p = _start; // the read pointer
Lee Thomason120b3a62012-10-12 10:06:59 -0700273 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 }
Dmitry-Mefed51122016-09-06 18:08:55 +0300286 *q = LF;
287 ++q;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700288 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700289 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700290 if ( *(p+1) == CR ) {
291 p += 2;
292 }
293 else {
294 ++p;
295 }
Dmitry-Mefed51122016-09-06 18:08:55 +0300296 *q = LF;
297 ++q;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700298 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700299 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700300 // Entities handled by tinyXML2:
301 // - special entities in the entity table [in/out]
302 // - numeric character reference [in]
303 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800304
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700305 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400306 const int buflen = 10;
307 char buf[buflen] = { 0 };
308 int len = 0;
Dmitry-Me6f51c802015-03-14 13:25:03 +0300309 char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
310 if ( adjusted == 0 ) {
311 *q = *p;
312 ++p;
313 ++q;
314 }
315 else {
316 TIXMLASSERT( 0 <= len && len <= buflen );
317 TIXMLASSERT( q + len <= adjusted );
318 p = adjusted;
319 memcpy( q, buf, len );
320 q += len;
321 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700322 }
323 else {
Dmitry-Me764545e2015-05-20 10:29:24 +0300324 bool entityFound = false;
325 for( int i = 0; i < NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400326 const Entity& entity = entities[i];
327 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
328 && *( p + entity.length + 1 ) == ';' ) {
329 // Found an entity - convert.
330 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700331 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400332 p += entity.length + 2;
Dmitry-Me764545e2015-05-20 10:29:24 +0300333 entityFound = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700334 break;
335 }
336 }
Dmitry-Me764545e2015-05-20 10:29:24 +0300337 if ( !entityFound ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700338 // fixme: treat as error?
339 ++p;
340 ++q;
341 }
342 }
343 }
344 else {
345 *q = *p;
346 ++p;
347 ++q;
348 }
349 }
350 *q = 0;
351 }
352 // The loop below has plenty going on, and this
353 // is a less useful mode. Break it out.
Dmitry-Me5420e542015-05-20 10:51:26 +0300354 if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700355 CollapseWhitespace();
356 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700357 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700358 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300359 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700360 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800361}
362
Lee Thomason2c85a712012-01-31 08:24:24 -0800363
Lee Thomasone4422302012-01-20 17:59:50 -0800364
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800365
Lee Thomason56bdd022012-02-09 18:16:58 -0800366// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800367
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800368const char* XMLUtil::ReadBOM( const char* p, bool* bom )
369{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300370 TIXMLASSERT( p );
371 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700372 *bom = false;
373 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
374 // Check for BOM:
375 if ( *(pu+0) == TIXML_UTF_LEAD_0
376 && *(pu+1) == TIXML_UTF_LEAD_1
377 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
378 *bom = true;
379 p += 3;
380 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300381 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700382 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800383}
384
385
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800386void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
387{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700388 const unsigned long BYTE_MASK = 0xBF;
389 const unsigned long BYTE_MARK = 0x80;
390 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800391
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700392 if (input < 0x80) {
393 *length = 1;
394 }
395 else if ( input < 0x800 ) {
396 *length = 2;
397 }
398 else if ( input < 0x10000 ) {
399 *length = 3;
400 }
401 else if ( input < 0x200000 ) {
402 *length = 4;
403 }
404 else {
Dmitry-Me2f465c42015-03-16 11:08:23 +0300405 *length = 0; // This code won't convert this correctly anyway.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700406 return;
407 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800408
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700409 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800410
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700411 // Scary scary fall throughs.
412 switch (*length) {
413 case 4:
414 --output;
415 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
416 input >>= 6;
417 case 3:
418 --output;
419 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
420 input >>= 6;
421 case 2:
422 --output;
423 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
424 input >>= 6;
425 case 1:
426 --output;
427 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100428 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300429 default:
430 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700431 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800432}
433
434
435const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
436{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700437 // Presume an entity, and pull it out.
438 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800439
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700440 if ( *(p+1) == '#' && *(p+2) ) {
441 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300442 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700443 ptrdiff_t delta = 0;
444 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800445 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800446
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700447 if ( *(p+2) == 'x' ) {
448 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300449 const char* q = p+3;
450 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700451 return 0;
452 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800453
Lee Thomason7e67bc82015-01-12 14:05:12 -0800454 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800455
Dmitry-Me9f56e122015-01-12 10:07:54 +0300456 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700457 return 0;
458 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800459 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800460
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700461 delta = q-p;
462 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800463
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700464 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700465 unsigned int digit = 0;
466
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700467 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300468 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700469 }
470 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300471 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700472 }
473 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300474 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700475 }
476 else {
477 return 0;
478 }
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100479 TIXMLASSERT( digit < 16 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300480 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
481 const unsigned int digitScaled = mult * digit;
482 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
483 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300484 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700485 mult *= 16;
486 --q;
487 }
488 }
489 else {
490 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300491 const char* q = p+2;
492 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700493 return 0;
494 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800495
Lee Thomason7e67bc82015-01-12 14:05:12 -0800496 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800497
Dmitry-Me9f56e122015-01-12 10:07:54 +0300498 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700499 return 0;
500 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800501 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800502
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700503 delta = q-p;
504 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800505
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700506 while ( *q != '#' ) {
507 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300508 const unsigned int digit = *q - '0';
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100509 TIXMLASSERT( digit < 10 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300510 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
511 const unsigned int digitScaled = mult * digit;
512 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
513 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700514 }
515 else {
516 return 0;
517 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300518 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700519 mult *= 10;
520 --q;
521 }
522 }
523 // convert the UCS to UTF-8
524 ConvertUTF32ToUTF8( ucs, value, length );
525 return p + delta + 1;
526 }
527 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800528}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800529
530
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700531void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700532{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700533 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700534}
535
536
537void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
538{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700539 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700540}
541
542
543void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
544{
Doruk Turakde45d042016-08-28 20:47:08 +0200545 TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? "true" : "false" );
Lee Thomason21be8822012-07-15 17:27:22 -0700546}
547
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800548/*
549 ToStr() of a number is a very tricky topic.
550 https://github.com/leethomason/tinyxml2/issues/106
551*/
Lee Thomason21be8822012-07-15 17:27:22 -0700552void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
553{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800554 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700555}
556
557
558void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
559{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800560 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700561}
562
563
Lee Thomason51c12712016-06-04 20:18:49 -0700564void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize)
565{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700566 // horrible syntax trick to make the compiler happy about %lld
567 TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v);
Lee Thomason51c12712016-06-04 20:18:49 -0700568}
569
570
Lee Thomason21be8822012-07-15 17:27:22 -0700571bool XMLUtil::ToInt( const char* str, int* value )
572{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700573 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
574 return true;
575 }
576 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700577}
578
579bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
580{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700581 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
582 return true;
583 }
584 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700585}
586
587bool XMLUtil::ToBool( const char* str, bool* value )
588{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700589 int ival = 0;
590 if ( ToInt( str, &ival )) {
591 *value = (ival==0) ? false : true;
592 return true;
593 }
594 if ( StringEqual( str, "true" ) ) {
595 *value = true;
596 return true;
597 }
598 else if ( StringEqual( str, "false" ) ) {
599 *value = false;
600 return true;
601 }
602 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700603}
604
605
606bool XMLUtil::ToFloat( const char* str, float* value )
607{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700608 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
609 return true;
610 }
611 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700612}
613
Lee Thomason51c12712016-06-04 20:18:49 -0700614
Lee Thomason21be8822012-07-15 17:27:22 -0700615bool XMLUtil::ToDouble( const char* str, double* value )
616{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700617 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
618 return true;
619 }
620 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700621}
622
623
Lee Thomason51c12712016-06-04 20:18:49 -0700624bool XMLUtil::ToInt64(const char* str, int64_t* value)
625{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700626 long long v = 0; // horrible syntax trick to make the compiler happy about %lld
627 if (TIXML_SSCANF(str, "%lld", &v) == 1) {
628 *value = (int64_t)v;
Lee Thomason51c12712016-06-04 20:18:49 -0700629 return true;
630 }
631 return false;
632}
633
634
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700635char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800636{
Dmitry-Me02384662015-03-03 16:02:13 +0300637 TIXMLASSERT( node );
638 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400639 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700640 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300641 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300642 *node = 0;
643 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700644 return p;
645 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800646
Dmitry-Me962083b2015-05-26 11:38:30 +0300647 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700648 static const char* xmlHeader = { "<?" };
649 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700650 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300651 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700652 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800653
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700654 static const int xmlHeaderLen = 2;
655 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700656 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300657 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700658 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800659
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700660 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
661 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400662 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700663 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300664 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700665 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
666 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700667 p += xmlHeaderLen;
668 }
669 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300670 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700671 returnNode = new (_commentPool.Alloc()) XMLComment( this );
672 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700673 p += commentHeaderLen;
674 }
675 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300676 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700677 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700678 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700679 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700680 p += cdataHeaderLen;
681 text->SetCData( true );
682 }
683 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300684 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700685 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
686 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700687 p += dtdHeaderLen;
688 }
689 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300690 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700691 returnNode = new (_elementPool.Alloc()) XMLElement( this );
692 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700693 p += elementHeaderLen;
694 }
695 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300696 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700697 returnNode = new (_textPool.Alloc()) XMLText( this );
698 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700699 p = start; // Back it up, all the text counts.
700 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800701
Dmitry-Me02384662015-03-03 16:02:13 +0300702 TIXMLASSERT( returnNode );
703 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700704 *node = returnNode;
705 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800706}
707
708
Lee Thomason751da522012-02-10 08:50:51 -0800709bool XMLDocument::Accept( XMLVisitor* visitor ) const
710{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300711 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700712 if ( visitor->VisitEnter( *this ) ) {
713 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
714 if ( !node->Accept( visitor ) ) {
715 break;
716 }
717 }
718 }
719 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800720}
Lee Thomason56bdd022012-02-09 18:16:58 -0800721
722
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800723// --------- XMLNode ----------- //
724
725XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700726 _document( doc ),
727 _parent( 0 ),
728 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200729 _prev( 0 ), _next( 0 ),
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700730 _userData( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200731 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800732{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800733}
734
735
736XMLNode::~XMLNode()
737{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700738 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700739 if ( _parent ) {
740 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700741 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800742}
743
Michael Daumling21626882013-10-22 17:03:37 +0200744const char* XMLNode::Value() const
745{
Dmitry-Mecaa72a62016-08-10 17:34:34 +0300746 // Edge case: XMLDocuments don't have a Value. Return null.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530747 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530748 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200749 return _value.GetStr();
750}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800751
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800752void XMLNode::SetValue( const char* str, bool staticMem )
753{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700754 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700755 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700756 }
757 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700758 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700759 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800760}
761
762
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800763void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800764{
Lee Thomason624d43f2012-10-12 10:58:48 -0700765 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300766 TIXMLASSERT( _lastChild );
Dmitry-Me9cb4eca2016-08-18 18:10:59 +0300767 DeleteChild( _firstChild );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700768 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700769 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800770}
771
772
773void XMLNode::Unlink( XMLNode* child )
774{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300775 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300776 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300777 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700778 if ( child == _firstChild ) {
779 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700780 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700781 if ( child == _lastChild ) {
782 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700783 }
Lee Thomasond923c672012-01-23 08:44:25 -0800784
Lee Thomason624d43f2012-10-12 10:58:48 -0700785 if ( child->_prev ) {
786 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700787 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700788 if ( child->_next ) {
789 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700790 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700791 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800792}
793
794
U-Stream\Leeae25a442012-02-17 17:48:16 -0800795void XMLNode::DeleteChild( XMLNode* node )
796{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300797 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300798 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700799 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100800 Unlink( node );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400801 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800802}
803
804
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800805XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
806{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300807 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300808 if ( addThis->_document != _document ) {
809 TIXMLASSERT( false );
810 return 0;
811 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800812 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700813
Lee Thomason624d43f2012-10-12 10:58:48 -0700814 if ( _lastChild ) {
815 TIXMLASSERT( _firstChild );
816 TIXMLASSERT( _lastChild->_next == 0 );
817 _lastChild->_next = addThis;
818 addThis->_prev = _lastChild;
819 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800820
Lee Thomason624d43f2012-10-12 10:58:48 -0700821 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700822 }
823 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700824 TIXMLASSERT( _firstChild == 0 );
825 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800826
Lee Thomason624d43f2012-10-12 10:58:48 -0700827 addThis->_prev = 0;
828 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700829 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700830 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700831 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800832}
833
834
Lee Thomason1ff38e02012-02-14 18:18:16 -0800835XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
836{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300837 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300838 if ( addThis->_document != _document ) {
839 TIXMLASSERT( false );
840 return 0;
841 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800842 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700843
Lee Thomason624d43f2012-10-12 10:58:48 -0700844 if ( _firstChild ) {
845 TIXMLASSERT( _lastChild );
846 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800847
Lee Thomason624d43f2012-10-12 10:58:48 -0700848 _firstChild->_prev = addThis;
849 addThis->_next = _firstChild;
850 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800851
Lee Thomason624d43f2012-10-12 10:58:48 -0700852 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700853 }
854 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700855 TIXMLASSERT( _lastChild == 0 );
856 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800857
Lee Thomason624d43f2012-10-12 10:58:48 -0700858 addThis->_prev = 0;
859 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700860 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700861 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400862 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800863}
864
865
866XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
867{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300868 TIXMLASSERT( addThis );
869 if ( addThis->_document != _document ) {
870 TIXMLASSERT( false );
871 return 0;
872 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700873
Dmitry-Meabb2d042014-12-09 12:59:31 +0300874 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700875
Lee Thomason624d43f2012-10-12 10:58:48 -0700876 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300877 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700878 return 0;
879 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800880
Lee Thomason624d43f2012-10-12 10:58:48 -0700881 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700882 // The last node or the only node.
883 return InsertEndChild( addThis );
884 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800885 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700886 addThis->_prev = afterThis;
887 addThis->_next = afterThis->_next;
888 afterThis->_next->_prev = addThis;
889 afterThis->_next = addThis;
890 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700891 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800892}
893
894
895
896
Dmitry-Me886ad972015-07-22 11:00:51 +0300897const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800898{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300899 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300900 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700901 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300902 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700903 }
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 ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300912 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700913 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300914 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700915 }
916 }
917 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800918}
919
920
Dmitry-Me886ad972015-07-22 11:00:51 +0300921const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800922{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300923 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300924 const XMLElement* element = node->ToElementWithName( name );
925 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400926 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700927 }
928 }
929 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800930}
931
932
Dmitry-Me886ad972015-07-22 11:00:51 +0300933const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800934{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300935 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300936 const XMLElement* element = node->ToElementWithName( name );
937 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400938 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700939 }
940 }
941 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800942}
943
944
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800945char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800946{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700947 // This is a recursive method, but thinking about it "at the current level"
948 // it is a pretty simple flat list:
949 // <foo/>
950 // <!-- comment -->
951 //
952 // With a special case:
953 // <foo>
954 // </foo>
955 // <!-- comment -->
956 //
957 // Where the closing element (/foo) *must* be the next thing after the opening
958 // element, and the names must match. BUT the tricky bit is that the closing
959 // element will be read by the child.
960 //
961 // 'endTag' is the end tag for this node, it is returned by a call to a child.
962 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800963
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700964 while( p && *p ) {
965 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800966
Lee Thomason624d43f2012-10-12 10:58:48 -0700967 p = _document->Identify( p, &node );
Dmitry-Me43364312016-11-07 18:48:50 +0300968 TIXMLASSERT( p );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300969 if ( node == 0 ) {
970 break;
971 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800972
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700973 StrPair endTag;
974 p = node->ParseDeep( p, &endTag );
975 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400976 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700977 if ( !_document->Error() ) {
978 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700979 }
980 break;
981 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800982
Sarat Addepalli3df007e2015-05-20 10:43:51 +0530983 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530984 if ( decl ) {
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530985 // A declaration can only be the first child of a document.
986 // Set error, if document already has children.
987 if ( !_document->NoChildren() ) {
988 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0);
Dmitry-Me4de7abb2016-08-10 17:30:02 +0300989 DeleteNode( node );
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530990 break;
991 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530992 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530993
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400994 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700995 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -0500996 // We read the end tag. Return it to the parent.
997 if ( ele->ClosingType() == XMLElement::CLOSING ) {
998 if ( parentEnd ) {
999 ele->_value.TransferTo( parentEnd );
1000 }
1001 node->_memPool->SetTracked(); // created and then immediately deleted.
1002 DeleteNode( node );
1003 return p;
1004 }
1005
1006 // Handle an end tag returned to this level.
1007 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001008 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001009 if ( endTag.Empty() ) {
1010 if ( ele->ClosingType() == XMLElement::OPEN ) {
1011 mismatch = true;
1012 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001013 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001014 else {
1015 if ( ele->ClosingType() != XMLElement::OPEN ) {
1016 mismatch = true;
1017 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001018 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001019 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001020 }
1021 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001022 if ( mismatch ) {
Dmitry-Me886ad972015-07-22 11:00:51 +03001023 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -05001024 DeleteNode( node );
1025 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001026 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001027 }
JayXondbfdd8f2014-12-12 20:07:14 -05001028 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001029 }
1030 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001031}
1032
Dmitry-Mee3225b12014-09-03 11:03:11 +04001033void XMLNode::DeleteNode( XMLNode* node )
1034{
1035 if ( node == 0 ) {
1036 return;
1037 }
1038 MemPool* pool = node->_memPool;
1039 node->~XMLNode();
1040 pool->Free( node );
1041}
1042
Lee Thomason3cebdc42015-01-05 17:16:28 -08001043void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001044{
1045 TIXMLASSERT( insertThis );
1046 TIXMLASSERT( insertThis->_document == _document );
1047
1048 if ( insertThis->_parent )
1049 insertThis->_parent->Unlink( insertThis );
1050 else
1051 insertThis->_memPool->SetTracked();
1052}
1053
Dmitry-Meecb9b072016-10-12 16:44:59 +03001054const XMLElement* XMLNode::ToElementWithName( const char* name ) const
1055{
1056 const XMLElement* element = this->ToElement();
1057 if ( element == 0 ) {
1058 return 0;
1059 }
1060 if ( name == 0 ) {
1061 return element;
1062 }
1063 if ( XMLUtil::StringEqual( element->Name(), name ) ) {
1064 return element;
1065 }
1066 return 0;
1067}
1068
Lee Thomason5492a1c2012-01-23 15:32:10 -08001069// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001070char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001071{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001072 const char* start = p;
1073 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001074 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001075 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001076 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001077 }
1078 return p;
1079 }
1080 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001081 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1082 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001083 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001084 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001085
Lee Thomason624d43f2012-10-12 10:58:48 -07001086 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001087 if ( p && *p ) {
1088 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001089 }
1090 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +03001091 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001092 }
1093 }
1094 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001095}
1096
1097
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001098XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1099{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001100 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001101 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001102 }
1103 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1104 text->SetCData( this->CData() );
1105 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001106}
1107
1108
1109bool XMLText::ShallowEqual( const XMLNode* compare ) const
1110{
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001111 const XMLText* text = compare->ToText();
1112 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001113}
1114
1115
Lee Thomason56bdd022012-02-09 18:16:58 -08001116bool XMLText::Accept( XMLVisitor* visitor ) const
1117{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001118 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001119 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001120}
1121
1122
Lee Thomason3f57d272012-01-11 15:30:03 -08001123// --------- XMLComment ---------- //
1124
Lee Thomasone4422302012-01-20 17:59:50 -08001125XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001126{
1127}
1128
1129
Lee Thomasonce0763e2012-01-11 15:43:54 -08001130XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001131{
Lee Thomason3f57d272012-01-11 15:30:03 -08001132}
1133
1134
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001135char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -08001136{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001137 // Comment parses as text.
1138 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001139 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001140 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001141 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001142 }
1143 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001144}
1145
1146
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001147XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1148{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001149 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001150 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001151 }
1152 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1153 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001154}
1155
1156
1157bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1158{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001159 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001160 const XMLComment* comment = compare->ToComment();
1161 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001162}
1163
1164
Lee Thomason751da522012-02-10 08:50:51 -08001165bool XMLComment::Accept( XMLVisitor* visitor ) const
1166{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001167 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001168 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001169}
Lee Thomason56bdd022012-02-09 18:16:58 -08001170
1171
Lee Thomason50f97b22012-02-11 16:33:40 -08001172// --------- XMLDeclaration ---------- //
1173
1174XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1175{
1176}
1177
1178
1179XMLDeclaration::~XMLDeclaration()
1180{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001181 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001182}
1183
1184
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001185char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001186{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001187 // Declaration parses as text.
1188 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001189 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001190 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001191 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001192 }
1193 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001194}
1195
1196
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001197XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1198{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001199 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001200 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001201 }
1202 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1203 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001204}
1205
1206
1207bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1208{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001209 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001210 const XMLDeclaration* declaration = compare->ToDeclaration();
1211 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001212}
1213
1214
1215
Lee Thomason50f97b22012-02-11 16:33:40 -08001216bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1217{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001218 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001219 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001220}
1221
1222// --------- XMLUnknown ---------- //
1223
1224XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1225{
1226}
1227
1228
1229XMLUnknown::~XMLUnknown()
1230{
1231}
1232
1233
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001234char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001235{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001236 // Unknown parses as text.
1237 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001238
Lee Thomason624d43f2012-10-12 10:58:48 -07001239 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001240 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001241 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001242 }
1243 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001244}
1245
1246
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001247XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1248{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001249 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001250 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001251 }
1252 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1253 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001254}
1255
1256
1257bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1258{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001259 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001260 const XMLUnknown* unknown = compare->ToUnknown();
1261 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001262}
1263
1264
Lee Thomason50f97b22012-02-11 16:33:40 -08001265bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1266{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001267 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001268 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001269}
1270
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001271// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001272
1273const char* XMLAttribute::Name() const
1274{
1275 return _name.GetStr();
1276}
1277
1278const char* XMLAttribute::Value() const
1279{
1280 return _value.GetStr();
1281}
1282
Lee Thomason6f381b72012-03-02 12:59:39 -08001283char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001284{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001285 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001286 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001287 if ( !p || !*p ) {
1288 return 0;
1289 }
Lee Thomason22aead12012-01-23 13:29:35 -08001290
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001291 // Skip white space before =
1292 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001293 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001294 return 0;
1295 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001296
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001297 ++p; // move up to opening quote
1298 p = XMLUtil::SkipWhiteSpace( p );
1299 if ( *p != '\"' && *p != '\'' ) {
1300 return 0;
1301 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001302
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001303 char endTag[2] = { *p, 0 };
1304 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001305
Lee Thomason624d43f2012-10-12 10:58:48 -07001306 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001307 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001308}
1309
1310
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001311void XMLAttribute::SetName( const char* n )
1312{
Lee Thomason624d43f2012-10-12 10:58:48 -07001313 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001314}
1315
1316
Lee Thomason2fa81722012-11-09 12:37:46 -08001317XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001318{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001319 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001320 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001321 }
1322 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001323}
1324
1325
Lee Thomason2fa81722012-11-09 12:37:46 -08001326XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001327{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001328 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001329 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001330 }
1331 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001332}
1333
1334
Lee Thomason51c12712016-06-04 20:18:49 -07001335XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1336{
1337 if (XMLUtil::ToInt64(Value(), value)) {
1338 return XML_SUCCESS;
1339 }
1340 return XML_WRONG_ATTRIBUTE_TYPE;
1341}
1342
1343
Lee Thomason2fa81722012-11-09 12:37:46 -08001344XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001345{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001346 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001347 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001348 }
1349 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001350}
1351
1352
Lee Thomason2fa81722012-11-09 12:37:46 -08001353XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001354{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001355 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001356 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001357 }
1358 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001359}
1360
1361
Lee Thomason2fa81722012-11-09 12:37:46 -08001362XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001363{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001364 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001365 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001366 }
1367 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001368}
1369
1370
1371void XMLAttribute::SetAttribute( const char* v )
1372{
Lee Thomason624d43f2012-10-12 10:58:48 -07001373 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001374}
1375
1376
Lee Thomason1ff38e02012-02-14 18:18:16 -08001377void XMLAttribute::SetAttribute( int v )
1378{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001379 char buf[BUF_SIZE];
1380 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001381 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001382}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001383
1384
1385void XMLAttribute::SetAttribute( unsigned v )
1386{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001387 char buf[BUF_SIZE];
1388 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001389 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001390}
1391
1392
Lee Thomason51c12712016-06-04 20:18:49 -07001393void XMLAttribute::SetAttribute(int64_t v)
1394{
1395 char buf[BUF_SIZE];
1396 XMLUtil::ToStr(v, buf, BUF_SIZE);
1397 _value.SetStr(buf);
1398}
1399
1400
1401
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001402void XMLAttribute::SetAttribute( bool v )
1403{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001404 char buf[BUF_SIZE];
1405 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001406 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001407}
1408
1409void XMLAttribute::SetAttribute( double v )
1410{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001411 char buf[BUF_SIZE];
1412 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001413 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001414}
1415
1416void XMLAttribute::SetAttribute( float v )
1417{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001418 char buf[BUF_SIZE];
1419 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001420 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001421}
1422
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001423
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001424// --------- XMLElement ---------- //
1425XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001426 _closingType( 0 ),
1427 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001428{
1429}
1430
1431
1432XMLElement::~XMLElement()
1433{
Lee Thomason624d43f2012-10-12 10:58:48 -07001434 while( _rootAttribute ) {
1435 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001436 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001437 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001438 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001439}
1440
1441
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001442const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1443{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001444 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001445 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1446 return a;
1447 }
1448 }
1449 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001450}
1451
1452
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001453const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001454{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001455 const XMLAttribute* a = FindAttribute( name );
1456 if ( !a ) {
1457 return 0;
1458 }
1459 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1460 return a->Value();
1461 }
1462 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001463}
1464
1465
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001466const char* XMLElement::GetText() const
1467{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001468 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001469 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001470 }
1471 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001472}
1473
1474
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001475void XMLElement::SetText( const char* inText )
1476{
Uli Kusterer869bb592014-01-21 01:36:16 +01001477 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001478 FirstChild()->SetValue( inText );
1479 else {
1480 XMLText* theText = GetDocument()->NewText( inText );
1481 InsertFirstChild( theText );
1482 }
1483}
1484
Lee Thomason5bb2d802014-01-24 10:42:57 -08001485
1486void XMLElement::SetText( int v )
1487{
1488 char buf[BUF_SIZE];
1489 XMLUtil::ToStr( v, buf, BUF_SIZE );
1490 SetText( buf );
1491}
1492
1493
1494void XMLElement::SetText( unsigned v )
1495{
1496 char buf[BUF_SIZE];
1497 XMLUtil::ToStr( v, buf, BUF_SIZE );
1498 SetText( buf );
1499}
1500
1501
Lee Thomason51c12712016-06-04 20:18:49 -07001502void XMLElement::SetText(int64_t v)
1503{
1504 char buf[BUF_SIZE];
1505 XMLUtil::ToStr(v, buf, BUF_SIZE);
1506 SetText(buf);
1507}
1508
1509
1510void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001511{
1512 char buf[BUF_SIZE];
1513 XMLUtil::ToStr( v, buf, BUF_SIZE );
1514 SetText( buf );
1515}
1516
1517
1518void XMLElement::SetText( float v )
1519{
1520 char buf[BUF_SIZE];
1521 XMLUtil::ToStr( v, buf, BUF_SIZE );
1522 SetText( buf );
1523}
1524
1525
1526void XMLElement::SetText( double v )
1527{
1528 char buf[BUF_SIZE];
1529 XMLUtil::ToStr( v, buf, BUF_SIZE );
1530 SetText( buf );
1531}
1532
1533
MortenMacFly4ee49f12013-01-14 20:03:14 +01001534XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001535{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001536 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001537 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001538 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001539 return XML_SUCCESS;
1540 }
1541 return XML_CAN_NOT_CONVERT_TEXT;
1542 }
1543 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001544}
1545
1546
MortenMacFly4ee49f12013-01-14 20:03:14 +01001547XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001548{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001549 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001550 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001551 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001552 return XML_SUCCESS;
1553 }
1554 return XML_CAN_NOT_CONVERT_TEXT;
1555 }
1556 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001557}
1558
1559
Lee Thomason51c12712016-06-04 20:18:49 -07001560XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1561{
1562 if (FirstChild() && FirstChild()->ToText()) {
1563 const char* t = FirstChild()->Value();
1564 if (XMLUtil::ToInt64(t, ival)) {
1565 return XML_SUCCESS;
1566 }
1567 return XML_CAN_NOT_CONVERT_TEXT;
1568 }
1569 return XML_NO_TEXT_NODE;
1570}
1571
1572
MortenMacFly4ee49f12013-01-14 20:03:14 +01001573XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001574{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001575 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001576 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001577 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001578 return XML_SUCCESS;
1579 }
1580 return XML_CAN_NOT_CONVERT_TEXT;
1581 }
1582 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001583}
1584
1585
MortenMacFly4ee49f12013-01-14 20:03:14 +01001586XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001587{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001588 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001589 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001590 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001591 return XML_SUCCESS;
1592 }
1593 return XML_CAN_NOT_CONVERT_TEXT;
1594 }
1595 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001596}
1597
1598
MortenMacFly4ee49f12013-01-14 20:03:14 +01001599XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001600{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001601 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001602 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001603 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001604 return XML_SUCCESS;
1605 }
1606 return XML_CAN_NOT_CONVERT_TEXT;
1607 }
1608 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001609}
1610
1611
1612
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001613XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1614{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001615 XMLAttribute* last = 0;
1616 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001617 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001618 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001619 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001620 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1621 break;
1622 }
1623 }
1624 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001625 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001626 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1627 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001628 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001629 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001630 }
1631 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001632 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001633 }
1634 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001635 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001636 }
1637 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001638}
1639
1640
U-Stream\Leeae25a442012-02-17 17:48:16 -08001641void XMLElement::DeleteAttribute( const char* name )
1642{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001643 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001644 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001645 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1646 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001647 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001648 }
1649 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001650 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001651 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001652 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001653 break;
1654 }
1655 prev = a;
1656 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001657}
1658
1659
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001660char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001661{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001662 const char* start = p;
1663 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001664
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001665 // Read the attributes.
1666 while( p ) {
1667 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001668 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001669 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001670 return 0;
1671 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001672
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001673 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001674 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001675 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001676 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1677 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001678 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001679
Lee Thomason624d43f2012-10-12 10:58:48 -07001680 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001681 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001682 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001683 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001684 return 0;
1685 }
1686 // There is a minor bug here: if the attribute in the source xml
1687 // document is duplicated, it will not be detected and the
1688 // attribute will be doubly added. However, tracking the 'prevAttribute'
1689 // avoids re-scanning the attribute list. Preferring performance for
1690 // now, may reconsider in the future.
1691 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001692 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001693 }
1694 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001695 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001696 }
1697 prevAttribute = attrib;
1698 }
1699 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001700 else if ( *p == '>' ) {
1701 ++p;
1702 break;
1703 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001704 // end of the tag
1705 else if ( *p == '/' && *(p+1) == '>' ) {
1706 _closingType = CLOSED;
1707 return p+2; // done; sealed element.
1708 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001709 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001710 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001711 return 0;
1712 }
1713 }
1714 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001715}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001716
Dmitry-Mee3225b12014-09-03 11:03:11 +04001717void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1718{
1719 if ( attribute == 0 ) {
1720 return;
1721 }
1722 MemPool* pool = attribute->_memPool;
1723 attribute->~XMLAttribute();
1724 pool->Free( attribute );
1725}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001726
Lee Thomason67d61312012-01-24 16:01:51 -08001727//
1728// <ele></ele>
1729// <ele>foo<b>bar</b></ele>
1730//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001731char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001732{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001733 // Read the element name.
1734 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001735
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001736 // The closing element is the </element> form. It is
1737 // parsed just like a regular element then deleted from
1738 // the DOM.
1739 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001740 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001741 ++p;
1742 }
Lee Thomason67d61312012-01-24 16:01:51 -08001743
Lee Thomason624d43f2012-10-12 10:58:48 -07001744 p = _value.ParseName( p );
1745 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001746 return 0;
1747 }
Lee Thomason67d61312012-01-24 16:01:51 -08001748
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001749 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001750 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001751 return p;
1752 }
Lee Thomason67d61312012-01-24 16:01:51 -08001753
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001754 p = XMLNode::ParseDeep( p, strPair );
1755 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001756}
1757
1758
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001759
1760XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1761{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001762 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001763 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001764 }
1765 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1766 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1767 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1768 }
1769 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001770}
1771
1772
1773bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1774{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001775 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001776 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001777 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001778
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001779 const XMLAttribute* a=FirstAttribute();
1780 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001781
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001782 while ( a && b ) {
1783 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1784 return false;
1785 }
1786 a = a->Next();
1787 b = b->Next();
1788 }
1789 if ( a || b ) {
1790 // different count
1791 return false;
1792 }
1793 return true;
1794 }
1795 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001796}
1797
1798
Lee Thomason751da522012-02-10 08:50:51 -08001799bool XMLElement::Accept( XMLVisitor* visitor ) const
1800{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001801 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001802 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001803 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1804 if ( !node->Accept( visitor ) ) {
1805 break;
1806 }
1807 }
1808 }
1809 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001810}
Lee Thomason56bdd022012-02-09 18:16:58 -08001811
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001812
Lee Thomason3f57d272012-01-11 15:30:03 -08001813// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001814
1815// Warning: List must match 'enum XMLError'
1816const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1817 "XML_SUCCESS",
1818 "XML_NO_ATTRIBUTE",
1819 "XML_WRONG_ATTRIBUTE_TYPE",
1820 "XML_ERROR_FILE_NOT_FOUND",
1821 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1822 "XML_ERROR_FILE_READ_ERROR",
1823 "XML_ERROR_ELEMENT_MISMATCH",
1824 "XML_ERROR_PARSING_ELEMENT",
1825 "XML_ERROR_PARSING_ATTRIBUTE",
1826 "XML_ERROR_IDENTIFYING_TAG",
1827 "XML_ERROR_PARSING_TEXT",
1828 "XML_ERROR_PARSING_CDATA",
1829 "XML_ERROR_PARSING_COMMENT",
1830 "XML_ERROR_PARSING_DECLARATION",
1831 "XML_ERROR_PARSING_UNKNOWN",
1832 "XML_ERROR_EMPTY_DOCUMENT",
1833 "XML_ERROR_MISMATCHED_ELEMENT",
1834 "XML_ERROR_PARSING",
1835 "XML_CAN_NOT_CONVERT_TEXT",
1836 "XML_NO_TEXT_NODE"
1837};
1838
1839
Lee Thomason624d43f2012-10-12 10:58:48 -07001840XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001841 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001842 _writeBOM( false ),
1843 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07001844 _errorID(XML_SUCCESS),
Lee Thomason624d43f2012-10-12 10:58:48 -07001845 _whitespace( whitespace ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001846 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001847{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03001848 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
1849 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08001850}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001851
1852
Lee Thomason3f57d272012-01-11 15:30:03 -08001853XMLDocument::~XMLDocument()
1854{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001855 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001856}
1857
1858
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001859void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001860{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001861 DeleteChildren();
1862
Dmitry-Meab37df82014-11-28 12:08:36 +03001863#ifdef DEBUG
1864 const bool hadError = Error();
1865#endif
Lee Thomason85536252016-06-04 19:10:53 -07001866 _errorID = XML_SUCCESS;
Lee Thomason584af572016-09-05 14:14:16 -07001867 _errorStr1.Reset();
1868 _errorStr2.Reset();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001869
Lee Thomason624d43f2012-10-12 10:58:48 -07001870 delete [] _charBuffer;
1871 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001872
1873#if 0
1874 _textPool.Trace( "text" );
1875 _elementPool.Trace( "element" );
1876 _commentPool.Trace( "comment" );
1877 _attributePool.Trace( "attribute" );
1878#endif
1879
1880#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001881 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001882 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1883 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1884 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1885 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1886 }
1887#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001888}
1889
Lee Thomason3f57d272012-01-11 15:30:03 -08001890
Lee Thomason2c85a712012-01-31 08:24:24 -08001891XMLElement* XMLDocument::NewElement( const char* name )
1892{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001893 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001894 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1895 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001896 ele->SetName( name );
1897 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001898}
1899
1900
Lee Thomason1ff38e02012-02-14 18:18:16 -08001901XMLComment* XMLDocument::NewComment( const char* str )
1902{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001903 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001904 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1905 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001906 comment->SetValue( str );
1907 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001908}
1909
1910
1911XMLText* XMLDocument::NewText( const char* str )
1912{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001913 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001914 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1915 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001916 text->SetValue( str );
1917 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001918}
1919
1920
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001921XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1922{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001923 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001924 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1925 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001926 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1927 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001928}
1929
1930
1931XMLUnknown* XMLDocument::NewUnknown( const char* str )
1932{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001933 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001934 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1935 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001936 unk->SetValue( str );
1937 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001938}
1939
Dmitry-Me01578db2014-08-19 10:18:48 +04001940static FILE* callfopen( const char* filepath, const char* mode )
1941{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001942 TIXMLASSERT( filepath );
1943 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001944#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1945 FILE* fp = 0;
1946 errno_t err = fopen_s( &fp, filepath, mode );
1947 if ( err ) {
1948 return 0;
1949 }
1950#else
1951 FILE* fp = fopen( filepath, mode );
1952#endif
1953 return fp;
1954}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001955
1956void XMLDocument::DeleteNode( XMLNode* node ) {
1957 TIXMLASSERT( node );
1958 TIXMLASSERT(node->_document == this );
1959 if (node->_parent) {
1960 node->_parent->DeleteChild( node );
1961 }
1962 else {
1963 // Isn't in the tree.
1964 // Use the parent delete.
1965 // Also, we need to mark it tracked: we 'know'
1966 // it was never used.
1967 node->_memPool->SetTracked();
1968 // Call the static XMLNode version:
1969 XMLNode::DeleteNode(node);
1970 }
1971}
1972
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001973
Lee Thomason2fa81722012-11-09 12:37:46 -08001974XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001975{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001976 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001977 FILE* fp = callfopen( filename, "rb" );
1978 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001979 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001980 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001981 }
1982 LoadFile( fp );
1983 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001984 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001985}
1986
Dmitry-Me901fed52015-09-25 10:29:51 +03001987// This is likely overengineered template art to have a check that unsigned long value incremented
1988// by one still fits into size_t. If size_t type is larger than unsigned long type
1989// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
1990// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
1991// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
1992// types sizes relate to each other.
1993template
1994<bool = (sizeof(unsigned long) >= sizeof(size_t))>
1995struct LongFitsIntoSizeTMinusOne {
1996 static bool Fits( unsigned long value )
1997 {
1998 return value < (size_t)-1;
1999 }
2000};
2001
2002template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02002003struct LongFitsIntoSizeTMinusOne<false> {
2004 static bool Fits( unsigned long )
2005 {
2006 return true;
2007 }
2008};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002009
Lee Thomason2fa81722012-11-09 12:37:46 -08002010XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002011{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002012 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002013
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002014 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002015 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002016 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2017 return _errorID;
2018 }
2019
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002020 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002021 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002022 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002023 if ( filelength == -1L ) {
2024 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2025 return _errorID;
2026 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002027 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002028
Dmitry-Me901fed52015-09-25 10:29:51 +03002029 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002030 // Cannot handle files which won't fit in buffer together with null terminator
2031 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2032 return _errorID;
2033 }
2034
Dmitry-Me72801b82015-05-07 09:41:39 +03002035 if ( filelength == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06002036 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002037 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002038 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002039
Dmitry-Me72801b82015-05-07 09:41:39 +03002040 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002041 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002042 _charBuffer = new char[size+1];
2043 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002044 if ( read != size ) {
2045 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002046 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002047 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002048
Lee Thomason624d43f2012-10-12 10:58:48 -07002049 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002050
Dmitry-Me97476b72015-01-01 16:15:57 +03002051 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002052 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002053}
2054
2055
Lee Thomason2fa81722012-11-09 12:37:46 -08002056XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002057{
Dmitry-Me01578db2014-08-19 10:18:48 +04002058 FILE* fp = callfopen( filename, "w" );
2059 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002060 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002061 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002062 }
2063 SaveFile(fp, compact);
2064 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002065 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002066}
2067
2068
Lee Thomason2fa81722012-11-09 12:37:46 -08002069XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002070{
Ant Mitchell189198f2015-03-24 16:20:36 +00002071 // Clear any error from the last save, otherwise it will get reported
2072 // for *this* call.
Lee Thomason85536252016-06-04 19:10:53 -07002073 SetError(XML_SUCCESS, 0, 0);
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002074 XMLPrinter stream( fp, compact );
2075 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002076 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002077}
2078
Lee Thomason1ff38e02012-02-14 18:18:16 -08002079
Lee Thomason2fa81722012-11-09 12:37:46 -08002080XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002081{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002082 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002083
Lee Thomason82d32002014-02-21 22:47:18 -08002084 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002085 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002086 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002087 }
2088 if ( len == (size_t)(-1) ) {
2089 len = strlen( p );
2090 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002091 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002092 _charBuffer = new char[ len+1 ];
2093 memcpy( _charBuffer, p, len );
2094 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002095
Dmitry-Me97476b72015-01-01 16:15:57 +03002096 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002097 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002098 // clean up now essentially dangling memory.
2099 // and the parse fail can put objects in the
2100 // pools that are dead and inaccessible.
2101 DeleteChildren();
2102 _elementPool.Clear();
2103 _attributePool.Clear();
2104 _textPool.Clear();
2105 _commentPool.Clear();
2106 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002107 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002108}
2109
2110
PKEuS1c5f99e2013-07-06 11:28:39 +02002111void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002112{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002113 if ( streamer ) {
2114 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002115 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002116 else {
2117 XMLPrinter stdoutStreamer( stdout );
2118 Accept( &stdoutStreamer );
2119 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002120}
2121
2122
Lee Thomason2fa81722012-11-09 12:37:46 -08002123void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08002124{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002125 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002126 _errorID = error;
Lee Thomason584af572016-09-05 14:14:16 -07002127
2128 _errorStr1.Reset();
2129 _errorStr2.Reset();
2130
2131 if (str1)
2132 _errorStr1.SetStr(str1);
2133 if (str2)
2134 _errorStr2.SetStr(str2);
Lee Thomason67d61312012-01-24 16:01:51 -08002135}
2136
Lee Thomason331596e2014-09-11 14:56:43 -07002137const char* XMLDocument::ErrorName() const
2138{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002139 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002140 const char* errorName = _errorNames[_errorID];
2141 TIXMLASSERT( errorName && errorName[0] );
2142 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002143}
Lee Thomason5cae8972012-01-24 18:03:07 -08002144
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002145void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002146{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002147 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002148 static const int LEN = 20;
2149 char buf1[LEN] = { 0 };
2150 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002151
Lee Thomason584af572016-09-05 14:14:16 -07002152 if ( !_errorStr1.Empty() ) {
2153 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002154 }
Lee Thomason584af572016-09-05 14:14:16 -07002155 if ( !_errorStr2.Empty() ) {
2156 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002157 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002158
Dmitry-Me2ad43202015-04-16 12:18:58 +03002159 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2160 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2161 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
Lee Thomason331596e2014-09-11 14:56:43 -07002162 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
Dmitry-Me400f1192015-04-07 11:51:21 +03002163 static_cast<int>( _errorID ), ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002164 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002165}
2166
Dmitry-Me97476b72015-01-01 16:15:57 +03002167void XMLDocument::Parse()
2168{
2169 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2170 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08002171 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03002172 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03002173 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002174 if ( !*p ) {
2175 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2176 return;
2177 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08002178 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002179}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002180
PKEuS1bfb9542013-08-04 13:51:17 +02002181XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002182 _elementJustOpened( false ),
2183 _firstElement( true ),
2184 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002185 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002186 _textDepth( -1 ),
2187 _processEntities( true ),
2188 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002189{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002190 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002191 _entityFlag[i] = false;
2192 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002193 }
2194 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002195 const char entityValue = entities[i].value;
Dmitry-Mec5f1e7c2016-10-14 10:33:02 +03002196 TIXMLASSERT( ((unsigned char)entityValue) < ENTITY_RANGE );
Dmitry-Me8b67d742014-12-22 11:35:12 +03002197 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002198 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002199 _restrictedEntityFlag[(unsigned char)'&'] = true;
2200 _restrictedEntityFlag[(unsigned char)'<'] = true;
2201 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002202 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002203}
2204
2205
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002206void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002207{
2208 va_list va;
2209 va_start( va, format );
2210
Lee Thomason624d43f2012-10-12 10:58:48 -07002211 if ( _fp ) {
2212 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002213 }
2214 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002215 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002216 // Close out and re-start the va-args
2217 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002218 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002219 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002220 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002221 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002222 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002223 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002224 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002225}
2226
2227
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002228void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002229{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002230 for( int i=0; i<depth; ++i ) {
2231 Print( " " );
2232 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002233}
2234
2235
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002236void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002237{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002238 // Look for runs of bytes between entities to print.
2239 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002240
Lee Thomason624d43f2012-10-12 10:58:48 -07002241 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002242 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002243 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002244 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002245 // Remember, char is sometimes signed. (How many times has that bitten me?)
2246 if ( *q > 0 && *q < ENTITY_RANGE ) {
2247 // Check for entities. If one is found, flush
2248 // the stream up until the entity, write the
2249 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002250 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002251 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002252 const size_t delta = q - p;
2253 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002254 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002255 Print( "%.*s", toPrint, p );
2256 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002257 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002258 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002259 for( int i=0; i<NUM_ENTITIES; ++i ) {
2260 if ( entities[i].value == *q ) {
2261 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002262 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002263 break;
2264 }
2265 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002266 if ( !entityPatternPrinted ) {
2267 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2268 TIXMLASSERT( false );
2269 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002270 ++p;
2271 }
2272 }
2273 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002274 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002275 }
2276 }
2277 // Flush the remaining string. This will be the entire
2278 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002279 TIXMLASSERT( p <= q );
2280 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002281 Print( "%s", p );
2282 }
Lee Thomason857b8682012-01-25 17:50:25 -08002283}
2284
U-Stream\Leeae25a442012-02-17 17:48:16 -08002285
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002286void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002287{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002288 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002289 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 -07002290 Print( "%s", bom );
2291 }
2292 if ( writeDec ) {
2293 PushDeclaration( "xml version=\"1.0\"" );
2294 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002295}
2296
2297
Uli Kusterer593a33d2014-02-01 12:48:51 +01002298void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002299{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002300 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002301 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002302
Uli Kusterer593a33d2014-02-01 12:48:51 +01002303 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002304 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002305 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002306 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002307 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002308 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002309
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002310 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002311 _elementJustOpened = true;
2312 _firstElement = false;
2313 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002314}
2315
2316
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002317void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002318{
Lee Thomason624d43f2012-10-12 10:58:48 -07002319 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002320 Print( " %s=\"", name );
2321 PrintString( value, false );
2322 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002323}
2324
2325
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002326void XMLPrinter::PushAttribute( const char* name, int v )
2327{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002328 char buf[BUF_SIZE];
2329 XMLUtil::ToStr( v, buf, BUF_SIZE );
2330 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002331}
2332
2333
2334void XMLPrinter::PushAttribute( const char* name, unsigned 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
Lee Thomason51c12712016-06-04 20:18:49 -07002342void XMLPrinter::PushAttribute(const char* name, int64_t v)
2343{
2344 char buf[BUF_SIZE];
2345 XMLUtil::ToStr(v, buf, BUF_SIZE);
2346 PushAttribute(name, buf);
2347}
2348
2349
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002350void XMLPrinter::PushAttribute( const char* name, bool v )
2351{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002352 char buf[BUF_SIZE];
2353 XMLUtil::ToStr( v, buf, BUF_SIZE );
2354 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002355}
2356
2357
2358void XMLPrinter::PushAttribute( const char* name, double v )
2359{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002360 char buf[BUF_SIZE];
2361 XMLUtil::ToStr( v, buf, BUF_SIZE );
2362 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002363}
2364
2365
Uli Kustererca412e82014-02-01 13:35:05 +01002366void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002367{
Lee Thomason624d43f2012-10-12 10:58:48 -07002368 --_depth;
2369 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002370
Lee Thomason624d43f2012-10-12 10:58:48 -07002371 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002372 Print( "/>" );
2373 }
2374 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002375 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002376 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002377 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002378 }
2379 Print( "</%s>", name );
2380 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002381
Lee Thomason624d43f2012-10-12 10:58:48 -07002382 if ( _textDepth == _depth ) {
2383 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002384 }
Uli Kustererca412e82014-02-01 13:35:05 +01002385 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002386 Print( "\n" );
2387 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002388 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002389}
2390
2391
Dmitry-Mea092bc12014-12-23 17:57:05 +03002392void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002393{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002394 if ( !_elementJustOpened ) {
2395 return;
2396 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002397 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002398 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002399}
2400
2401
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002402void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002403{
Lee Thomason624d43f2012-10-12 10:58:48 -07002404 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002405
Dmitry-Mea092bc12014-12-23 17:57:05 +03002406 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002407 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002408 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002409 }
2410 else {
2411 PrintString( text, true );
2412 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002413}
2414
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002415void XMLPrinter::PushText( int64_t value )
2416{
2417 char buf[BUF_SIZE];
2418 XMLUtil::ToStr( value, buf, BUF_SIZE );
2419 PushText( buf, false );
2420}
2421
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002422void XMLPrinter::PushText( int 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( unsigned 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( bool 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
2445
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002446void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002447{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002448 char buf[BUF_SIZE];
2449 XMLUtil::ToStr( value, buf, BUF_SIZE );
2450 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002451}
2452
2453
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002454void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002455{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002456 char buf[BUF_SIZE];
2457 XMLUtil::ToStr( value, buf, BUF_SIZE );
2458 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002459}
2460
Lee Thomason5cae8972012-01-24 18:03:07 -08002461
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002462void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002463{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002464 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002465 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002466 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002467 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002468 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002469 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002470 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002471}
Lee Thomason751da522012-02-10 08:50:51 -08002472
2473
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002474void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002475{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002476 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002477 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002478 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002479 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002480 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002481 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002482 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002483}
2484
2485
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002486void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002487{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002488 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002489 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002490 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002491 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002492 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002493 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002494 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002495}
2496
2497
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002498bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002499{
Lee Thomason624d43f2012-10-12 10:58:48 -07002500 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002501 if ( doc.HasBOM() ) {
2502 PushHeader( true, false );
2503 }
2504 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002505}
2506
2507
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002508bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002509{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002510 const XMLElement* parentElem = 0;
2511 if ( element.Parent() ) {
2512 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002513 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002514 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002515 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002516 while ( attribute ) {
2517 PushAttribute( attribute->Name(), attribute->Value() );
2518 attribute = attribute->Next();
2519 }
2520 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002521}
2522
2523
Uli Kustererca412e82014-02-01 13:35:05 +01002524bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002525{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002526 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002527 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002528}
2529
2530
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002531bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002532{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002533 PushText( text.Value(), text.CData() );
2534 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002535}
2536
2537
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002538bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002539{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002540 PushComment( comment.Value() );
2541 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002542}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002543
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002544bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002545{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002546 PushDeclaration( declaration.Value() );
2547 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002548}
2549
2550
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002551bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002552{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002553 PushUnknown( unknown.Value() );
2554 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002555}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002556
Lee Thomason685b8952012-11-12 13:00:06 -08002557} // namespace tinyxml2
2558