blob: a7c2b1c790e11bf22e612ee0c5d9274620e9fdb6 [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-Me9fcb8762015-03-05 17:53:34 +0300968 if ( node == 0 ) {
969 break;
970 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800971
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700972 StrPair endTag;
973 p = node->ParseDeep( p, &endTag );
974 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400975 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700976 if ( !_document->Error() ) {
977 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700978 }
979 break;
980 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800981
Sarat Addepalli3df007e2015-05-20 10:43:51 +0530982 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530983 if ( decl ) {
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530984 // A declaration can only be the first child of a document.
985 // Set error, if document already has children.
986 if ( !_document->NoChildren() ) {
987 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0);
Dmitry-Me4de7abb2016-08-10 17:30:02 +0300988 DeleteNode( node );
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530989 break;
990 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530991 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530992
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400993 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700994 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -0500995 // We read the end tag. Return it to the parent.
996 if ( ele->ClosingType() == XMLElement::CLOSING ) {
997 if ( parentEnd ) {
998 ele->_value.TransferTo( parentEnd );
999 }
1000 node->_memPool->SetTracked(); // created and then immediately deleted.
1001 DeleteNode( node );
1002 return p;
1003 }
1004
1005 // Handle an end tag returned to this level.
1006 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001007 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001008 if ( endTag.Empty() ) {
1009 if ( ele->ClosingType() == XMLElement::OPEN ) {
1010 mismatch = true;
1011 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001012 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001013 else {
1014 if ( ele->ClosingType() != XMLElement::OPEN ) {
1015 mismatch = true;
1016 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001017 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001018 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001019 }
1020 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001021 if ( mismatch ) {
Dmitry-Me886ad972015-07-22 11:00:51 +03001022 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -05001023 DeleteNode( node );
1024 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001025 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001026 }
JayXondbfdd8f2014-12-12 20:07:14 -05001027 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001028 }
1029 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001030}
1031
Dmitry-Mee3225b12014-09-03 11:03:11 +04001032void XMLNode::DeleteNode( XMLNode* node )
1033{
1034 if ( node == 0 ) {
1035 return;
1036 }
1037 MemPool* pool = node->_memPool;
1038 node->~XMLNode();
1039 pool->Free( node );
1040}
1041
Lee Thomason3cebdc42015-01-05 17:16:28 -08001042void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001043{
1044 TIXMLASSERT( insertThis );
1045 TIXMLASSERT( insertThis->_document == _document );
1046
1047 if ( insertThis->_parent )
1048 insertThis->_parent->Unlink( insertThis );
1049 else
1050 insertThis->_memPool->SetTracked();
1051}
1052
Dmitry-Meecb9b072016-10-12 16:44:59 +03001053const XMLElement* XMLNode::ToElementWithName( const char* name ) const
1054{
1055 const XMLElement* element = this->ToElement();
1056 if ( element == 0 ) {
1057 return 0;
1058 }
1059 if ( name == 0 ) {
1060 return element;
1061 }
1062 if ( XMLUtil::StringEqual( element->Name(), name ) ) {
1063 return element;
1064 }
1065 return 0;
1066}
1067
Lee Thomason5492a1c2012-01-23 15:32:10 -08001068// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001069char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001070{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001071 const char* start = p;
1072 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001073 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001074 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001075 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001076 }
1077 return p;
1078 }
1079 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001080 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1081 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001082 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001083 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001084
Lee Thomason624d43f2012-10-12 10:58:48 -07001085 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001086 if ( p && *p ) {
1087 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001088 }
1089 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +03001090 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001091 }
1092 }
1093 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001094}
1095
1096
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001097XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1098{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001099 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001100 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001101 }
1102 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1103 text->SetCData( this->CData() );
1104 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001105}
1106
1107
1108bool XMLText::ShallowEqual( const XMLNode* compare ) const
1109{
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001110 const XMLText* text = compare->ToText();
1111 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001112}
1113
1114
Lee Thomason56bdd022012-02-09 18:16:58 -08001115bool XMLText::Accept( XMLVisitor* visitor ) const
1116{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001117 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001118 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001119}
1120
1121
Lee Thomason3f57d272012-01-11 15:30:03 -08001122// --------- XMLComment ---------- //
1123
Lee Thomasone4422302012-01-20 17:59:50 -08001124XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001125{
1126}
1127
1128
Lee Thomasonce0763e2012-01-11 15:43:54 -08001129XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001130{
Lee Thomason3f57d272012-01-11 15:30:03 -08001131}
1132
1133
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001134char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -08001135{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001136 // Comment parses as text.
1137 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001138 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001139 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001140 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001141 }
1142 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001143}
1144
1145
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001146XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1147{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001148 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001149 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001150 }
1151 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1152 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001153}
1154
1155
1156bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1157{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001158 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001159 const XMLComment* comment = compare->ToComment();
1160 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001161}
1162
1163
Lee Thomason751da522012-02-10 08:50:51 -08001164bool XMLComment::Accept( XMLVisitor* visitor ) const
1165{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001166 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001167 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001168}
Lee Thomason56bdd022012-02-09 18:16:58 -08001169
1170
Lee Thomason50f97b22012-02-11 16:33:40 -08001171// --------- XMLDeclaration ---------- //
1172
1173XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1174{
1175}
1176
1177
1178XMLDeclaration::~XMLDeclaration()
1179{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001180 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001181}
1182
1183
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001184char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001185{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001186 // Declaration parses as text.
1187 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001188 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001189 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001190 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001191 }
1192 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001193}
1194
1195
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001196XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1197{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001198 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001199 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001200 }
1201 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1202 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001203}
1204
1205
1206bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1207{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001208 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001209 const XMLDeclaration* declaration = compare->ToDeclaration();
1210 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001211}
1212
1213
1214
Lee Thomason50f97b22012-02-11 16:33:40 -08001215bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1216{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001217 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001218 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001219}
1220
1221// --------- XMLUnknown ---------- //
1222
1223XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1224{
1225}
1226
1227
1228XMLUnknown::~XMLUnknown()
1229{
1230}
1231
1232
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001233char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001234{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001235 // Unknown parses as text.
1236 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001237
Lee Thomason624d43f2012-10-12 10:58:48 -07001238 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001239 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001240 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001241 }
1242 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001243}
1244
1245
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001246XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1247{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001248 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001249 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001250 }
1251 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1252 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001253}
1254
1255
1256bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1257{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001258 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001259 const XMLUnknown* unknown = compare->ToUnknown();
1260 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001261}
1262
1263
Lee Thomason50f97b22012-02-11 16:33:40 -08001264bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1265{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001266 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001267 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001268}
1269
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001270// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001271
1272const char* XMLAttribute::Name() const
1273{
1274 return _name.GetStr();
1275}
1276
1277const char* XMLAttribute::Value() const
1278{
1279 return _value.GetStr();
1280}
1281
Lee Thomason6f381b72012-03-02 12:59:39 -08001282char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001283{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001284 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001285 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001286 if ( !p || !*p ) {
1287 return 0;
1288 }
Lee Thomason22aead12012-01-23 13:29:35 -08001289
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001290 // Skip white space before =
1291 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001292 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001293 return 0;
1294 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001295
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001296 ++p; // move up to opening quote
1297 p = XMLUtil::SkipWhiteSpace( p );
1298 if ( *p != '\"' && *p != '\'' ) {
1299 return 0;
1300 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001301
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001302 char endTag[2] = { *p, 0 };
1303 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001304
Lee Thomason624d43f2012-10-12 10:58:48 -07001305 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001306 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001307}
1308
1309
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001310void XMLAttribute::SetName( const char* n )
1311{
Lee Thomason624d43f2012-10-12 10:58:48 -07001312 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001313}
1314
1315
Lee Thomason2fa81722012-11-09 12:37:46 -08001316XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001317{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001318 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001319 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001320 }
1321 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001322}
1323
1324
Lee Thomason2fa81722012-11-09 12:37:46 -08001325XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001326{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001327 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001328 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001329 }
1330 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001331}
1332
1333
Lee Thomason51c12712016-06-04 20:18:49 -07001334XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1335{
1336 if (XMLUtil::ToInt64(Value(), value)) {
1337 return XML_SUCCESS;
1338 }
1339 return XML_WRONG_ATTRIBUTE_TYPE;
1340}
1341
1342
Lee Thomason2fa81722012-11-09 12:37:46 -08001343XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001344{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001345 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001346 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001347 }
1348 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001349}
1350
1351
Lee Thomason2fa81722012-11-09 12:37:46 -08001352XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001353{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001354 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001355 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001356 }
1357 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001358}
1359
1360
Lee Thomason2fa81722012-11-09 12:37:46 -08001361XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001362{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001363 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001364 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001365 }
1366 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001367}
1368
1369
1370void XMLAttribute::SetAttribute( const char* v )
1371{
Lee Thomason624d43f2012-10-12 10:58:48 -07001372 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001373}
1374
1375
Lee Thomason1ff38e02012-02-14 18:18:16 -08001376void XMLAttribute::SetAttribute( int v )
1377{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001378 char buf[BUF_SIZE];
1379 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001380 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001381}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001382
1383
1384void XMLAttribute::SetAttribute( unsigned v )
1385{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001386 char buf[BUF_SIZE];
1387 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001388 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001389}
1390
1391
Lee Thomason51c12712016-06-04 20:18:49 -07001392void XMLAttribute::SetAttribute(int64_t v)
1393{
1394 char buf[BUF_SIZE];
1395 XMLUtil::ToStr(v, buf, BUF_SIZE);
1396 _value.SetStr(buf);
1397}
1398
1399
1400
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001401void XMLAttribute::SetAttribute( bool v )
1402{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001403 char buf[BUF_SIZE];
1404 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001405 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001406}
1407
1408void XMLAttribute::SetAttribute( double v )
1409{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001410 char buf[BUF_SIZE];
1411 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001412 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001413}
1414
1415void XMLAttribute::SetAttribute( float v )
1416{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001417 char buf[BUF_SIZE];
1418 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001419 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001420}
1421
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001422
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001423// --------- XMLElement ---------- //
1424XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001425 _closingType( 0 ),
1426 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001427{
1428}
1429
1430
1431XMLElement::~XMLElement()
1432{
Lee Thomason624d43f2012-10-12 10:58:48 -07001433 while( _rootAttribute ) {
1434 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001435 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001436 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001437 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001438}
1439
1440
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001441const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1442{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001443 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001444 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1445 return a;
1446 }
1447 }
1448 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001449}
1450
1451
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001452const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001453{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001454 const XMLAttribute* a = FindAttribute( name );
1455 if ( !a ) {
1456 return 0;
1457 }
1458 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1459 return a->Value();
1460 }
1461 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001462}
1463
1464
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001465const char* XMLElement::GetText() const
1466{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001467 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001468 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001469 }
1470 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001471}
1472
1473
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001474void XMLElement::SetText( const char* inText )
1475{
Uli Kusterer869bb592014-01-21 01:36:16 +01001476 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001477 FirstChild()->SetValue( inText );
1478 else {
1479 XMLText* theText = GetDocument()->NewText( inText );
1480 InsertFirstChild( theText );
1481 }
1482}
1483
Lee Thomason5bb2d802014-01-24 10:42:57 -08001484
1485void XMLElement::SetText( int v )
1486{
1487 char buf[BUF_SIZE];
1488 XMLUtil::ToStr( v, buf, BUF_SIZE );
1489 SetText( buf );
1490}
1491
1492
1493void XMLElement::SetText( unsigned v )
1494{
1495 char buf[BUF_SIZE];
1496 XMLUtil::ToStr( v, buf, BUF_SIZE );
1497 SetText( buf );
1498}
1499
1500
Lee Thomason51c12712016-06-04 20:18:49 -07001501void XMLElement::SetText(int64_t v)
1502{
1503 char buf[BUF_SIZE];
1504 XMLUtil::ToStr(v, buf, BUF_SIZE);
1505 SetText(buf);
1506}
1507
1508
1509void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001510{
1511 char buf[BUF_SIZE];
1512 XMLUtil::ToStr( v, buf, BUF_SIZE );
1513 SetText( buf );
1514}
1515
1516
1517void XMLElement::SetText( float v )
1518{
1519 char buf[BUF_SIZE];
1520 XMLUtil::ToStr( v, buf, BUF_SIZE );
1521 SetText( buf );
1522}
1523
1524
1525void XMLElement::SetText( double v )
1526{
1527 char buf[BUF_SIZE];
1528 XMLUtil::ToStr( v, buf, BUF_SIZE );
1529 SetText( buf );
1530}
1531
1532
MortenMacFly4ee49f12013-01-14 20:03:14 +01001533XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001534{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001535 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001536 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001537 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001538 return XML_SUCCESS;
1539 }
1540 return XML_CAN_NOT_CONVERT_TEXT;
1541 }
1542 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001543}
1544
1545
MortenMacFly4ee49f12013-01-14 20:03:14 +01001546XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001547{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001548 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001549 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001550 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001551 return XML_SUCCESS;
1552 }
1553 return XML_CAN_NOT_CONVERT_TEXT;
1554 }
1555 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001556}
1557
1558
Lee Thomason51c12712016-06-04 20:18:49 -07001559XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1560{
1561 if (FirstChild() && FirstChild()->ToText()) {
1562 const char* t = FirstChild()->Value();
1563 if (XMLUtil::ToInt64(t, ival)) {
1564 return XML_SUCCESS;
1565 }
1566 return XML_CAN_NOT_CONVERT_TEXT;
1567 }
1568 return XML_NO_TEXT_NODE;
1569}
1570
1571
MortenMacFly4ee49f12013-01-14 20:03:14 +01001572XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001573{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001574 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001575 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001576 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001577 return XML_SUCCESS;
1578 }
1579 return XML_CAN_NOT_CONVERT_TEXT;
1580 }
1581 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001582}
1583
1584
MortenMacFly4ee49f12013-01-14 20:03:14 +01001585XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001586{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001587 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001588 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001589 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001590 return XML_SUCCESS;
1591 }
1592 return XML_CAN_NOT_CONVERT_TEXT;
1593 }
1594 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001595}
1596
1597
MortenMacFly4ee49f12013-01-14 20:03:14 +01001598XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001599{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001600 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001601 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001602 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001603 return XML_SUCCESS;
1604 }
1605 return XML_CAN_NOT_CONVERT_TEXT;
1606 }
1607 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001608}
1609
1610
1611
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001612XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1613{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001614 XMLAttribute* last = 0;
1615 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001616 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001617 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001618 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001619 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1620 break;
1621 }
1622 }
1623 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001624 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001625 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1626 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001627 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001628 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001629 }
1630 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001631 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001632 }
1633 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001634 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001635 }
1636 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001637}
1638
1639
U-Stream\Leeae25a442012-02-17 17:48:16 -08001640void XMLElement::DeleteAttribute( const char* name )
1641{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001642 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001643 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001644 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1645 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001646 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001647 }
1648 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001649 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001650 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001651 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001652 break;
1653 }
1654 prev = a;
1655 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001656}
1657
1658
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001659char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001660{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001661 const char* start = p;
1662 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001663
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001664 // Read the attributes.
1665 while( p ) {
1666 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001667 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001668 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001669 return 0;
1670 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001671
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001672 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001673 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001674 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001675 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1676 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001677 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001678
Lee Thomason624d43f2012-10-12 10:58:48 -07001679 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001680 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001681 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001682 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001683 return 0;
1684 }
1685 // There is a minor bug here: if the attribute in the source xml
1686 // document is duplicated, it will not be detected and the
1687 // attribute will be doubly added. However, tracking the 'prevAttribute'
1688 // avoids re-scanning the attribute list. Preferring performance for
1689 // now, may reconsider in the future.
1690 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001691 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001692 }
1693 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001694 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001695 }
1696 prevAttribute = attrib;
1697 }
1698 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001699 else if ( *p == '>' ) {
1700 ++p;
1701 break;
1702 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001703 // end of the tag
1704 else if ( *p == '/' && *(p+1) == '>' ) {
1705 _closingType = CLOSED;
1706 return p+2; // done; sealed element.
1707 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001708 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001709 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001710 return 0;
1711 }
1712 }
1713 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001714}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001715
Dmitry-Mee3225b12014-09-03 11:03:11 +04001716void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1717{
1718 if ( attribute == 0 ) {
1719 return;
1720 }
1721 MemPool* pool = attribute->_memPool;
1722 attribute->~XMLAttribute();
1723 pool->Free( attribute );
1724}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001725
Lee Thomason67d61312012-01-24 16:01:51 -08001726//
1727// <ele></ele>
1728// <ele>foo<b>bar</b></ele>
1729//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001730char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001731{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001732 // Read the element name.
1733 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001734
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001735 // The closing element is the </element> form. It is
1736 // parsed just like a regular element then deleted from
1737 // the DOM.
1738 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001739 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001740 ++p;
1741 }
Lee Thomason67d61312012-01-24 16:01:51 -08001742
Lee Thomason624d43f2012-10-12 10:58:48 -07001743 p = _value.ParseName( p );
1744 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001745 return 0;
1746 }
Lee Thomason67d61312012-01-24 16:01:51 -08001747
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001748 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001749 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001750 return p;
1751 }
Lee Thomason67d61312012-01-24 16:01:51 -08001752
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001753 p = XMLNode::ParseDeep( p, strPair );
1754 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001755}
1756
1757
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001758
1759XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1760{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001761 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001762 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001763 }
1764 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1765 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1766 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1767 }
1768 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001769}
1770
1771
1772bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1773{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001774 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001775 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001776 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001777
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001778 const XMLAttribute* a=FirstAttribute();
1779 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001780
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001781 while ( a && b ) {
1782 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1783 return false;
1784 }
1785 a = a->Next();
1786 b = b->Next();
1787 }
1788 if ( a || b ) {
1789 // different count
1790 return false;
1791 }
1792 return true;
1793 }
1794 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001795}
1796
1797
Lee Thomason751da522012-02-10 08:50:51 -08001798bool XMLElement::Accept( XMLVisitor* visitor ) const
1799{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001800 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001801 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001802 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1803 if ( !node->Accept( visitor ) ) {
1804 break;
1805 }
1806 }
1807 }
1808 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001809}
Lee Thomason56bdd022012-02-09 18:16:58 -08001810
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001811
Lee Thomason3f57d272012-01-11 15:30:03 -08001812// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001813
1814// Warning: List must match 'enum XMLError'
1815const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1816 "XML_SUCCESS",
1817 "XML_NO_ATTRIBUTE",
1818 "XML_WRONG_ATTRIBUTE_TYPE",
1819 "XML_ERROR_FILE_NOT_FOUND",
1820 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1821 "XML_ERROR_FILE_READ_ERROR",
1822 "XML_ERROR_ELEMENT_MISMATCH",
1823 "XML_ERROR_PARSING_ELEMENT",
1824 "XML_ERROR_PARSING_ATTRIBUTE",
1825 "XML_ERROR_IDENTIFYING_TAG",
1826 "XML_ERROR_PARSING_TEXT",
1827 "XML_ERROR_PARSING_CDATA",
1828 "XML_ERROR_PARSING_COMMENT",
1829 "XML_ERROR_PARSING_DECLARATION",
1830 "XML_ERROR_PARSING_UNKNOWN",
1831 "XML_ERROR_EMPTY_DOCUMENT",
1832 "XML_ERROR_MISMATCHED_ELEMENT",
1833 "XML_ERROR_PARSING",
1834 "XML_CAN_NOT_CONVERT_TEXT",
1835 "XML_NO_TEXT_NODE"
1836};
1837
1838
Lee Thomason624d43f2012-10-12 10:58:48 -07001839XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001840 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001841 _writeBOM( false ),
1842 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07001843 _errorID(XML_SUCCESS),
Lee Thomason624d43f2012-10-12 10:58:48 -07001844 _whitespace( whitespace ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001845 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001846{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03001847 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
1848 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08001849}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001850
1851
Lee Thomason3f57d272012-01-11 15:30:03 -08001852XMLDocument::~XMLDocument()
1853{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001854 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001855}
1856
1857
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001858void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001859{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001860 DeleteChildren();
1861
Dmitry-Meab37df82014-11-28 12:08:36 +03001862#ifdef DEBUG
1863 const bool hadError = Error();
1864#endif
Lee Thomason85536252016-06-04 19:10:53 -07001865 _errorID = XML_SUCCESS;
Lee Thomason584af572016-09-05 14:14:16 -07001866 _errorStr1.Reset();
1867 _errorStr2.Reset();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001868
Lee Thomason624d43f2012-10-12 10:58:48 -07001869 delete [] _charBuffer;
1870 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001871
1872#if 0
1873 _textPool.Trace( "text" );
1874 _elementPool.Trace( "element" );
1875 _commentPool.Trace( "comment" );
1876 _attributePool.Trace( "attribute" );
1877#endif
1878
1879#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001880 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001881 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1882 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1883 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1884 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1885 }
1886#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001887}
1888
Lee Thomason3f57d272012-01-11 15:30:03 -08001889
Lee Thomason2c85a712012-01-31 08:24:24 -08001890XMLElement* XMLDocument::NewElement( const char* name )
1891{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001892 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001893 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1894 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001895 ele->SetName( name );
1896 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001897}
1898
1899
Lee Thomason1ff38e02012-02-14 18:18:16 -08001900XMLComment* XMLDocument::NewComment( const char* str )
1901{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001902 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001903 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1904 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001905 comment->SetValue( str );
1906 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001907}
1908
1909
1910XMLText* XMLDocument::NewText( const char* str )
1911{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001912 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001913 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1914 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001915 text->SetValue( str );
1916 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001917}
1918
1919
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001920XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1921{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001922 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001923 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1924 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001925 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1926 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001927}
1928
1929
1930XMLUnknown* XMLDocument::NewUnknown( const char* str )
1931{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001932 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001933 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1934 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001935 unk->SetValue( str );
1936 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001937}
1938
Dmitry-Me01578db2014-08-19 10:18:48 +04001939static FILE* callfopen( const char* filepath, const char* mode )
1940{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001941 TIXMLASSERT( filepath );
1942 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001943#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1944 FILE* fp = 0;
1945 errno_t err = fopen_s( &fp, filepath, mode );
1946 if ( err ) {
1947 return 0;
1948 }
1949#else
1950 FILE* fp = fopen( filepath, mode );
1951#endif
1952 return fp;
1953}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001954
1955void XMLDocument::DeleteNode( XMLNode* node ) {
1956 TIXMLASSERT( node );
1957 TIXMLASSERT(node->_document == this );
1958 if (node->_parent) {
1959 node->_parent->DeleteChild( node );
1960 }
1961 else {
1962 // Isn't in the tree.
1963 // Use the parent delete.
1964 // Also, we need to mark it tracked: we 'know'
1965 // it was never used.
1966 node->_memPool->SetTracked();
1967 // Call the static XMLNode version:
1968 XMLNode::DeleteNode(node);
1969 }
1970}
1971
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001972
Lee Thomason2fa81722012-11-09 12:37:46 -08001973XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001974{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001975 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001976 FILE* fp = callfopen( filename, "rb" );
1977 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001978 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001979 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001980 }
1981 LoadFile( fp );
1982 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001983 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001984}
1985
Dmitry-Me901fed52015-09-25 10:29:51 +03001986// This is likely overengineered template art to have a check that unsigned long value incremented
1987// by one still fits into size_t. If size_t type is larger than unsigned long type
1988// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
1989// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
1990// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
1991// types sizes relate to each other.
1992template
1993<bool = (sizeof(unsigned long) >= sizeof(size_t))>
1994struct LongFitsIntoSizeTMinusOne {
1995 static bool Fits( unsigned long value )
1996 {
1997 return value < (size_t)-1;
1998 }
1999};
2000
2001template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02002002struct LongFitsIntoSizeTMinusOne<false> {
2003 static bool Fits( unsigned long )
2004 {
2005 return true;
2006 }
2007};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002008
Lee Thomason2fa81722012-11-09 12:37:46 -08002009XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002010{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002011 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002012
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002013 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002014 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002015 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2016 return _errorID;
2017 }
2018
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002019 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002020 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002021 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002022 if ( filelength == -1L ) {
2023 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2024 return _errorID;
2025 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002026 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002027
Dmitry-Me901fed52015-09-25 10:29:51 +03002028 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002029 // Cannot handle files which won't fit in buffer together with null terminator
2030 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2031 return _errorID;
2032 }
2033
Dmitry-Me72801b82015-05-07 09:41:39 +03002034 if ( filelength == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06002035 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002036 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002037 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002038
Dmitry-Me72801b82015-05-07 09:41:39 +03002039 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002040 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002041 _charBuffer = new char[size+1];
2042 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002043 if ( read != size ) {
2044 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002045 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002046 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002047
Lee Thomason624d43f2012-10-12 10:58:48 -07002048 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002049
Dmitry-Me97476b72015-01-01 16:15:57 +03002050 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002051 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002052}
2053
2054
Lee Thomason2fa81722012-11-09 12:37:46 -08002055XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002056{
Dmitry-Me01578db2014-08-19 10:18:48 +04002057 FILE* fp = callfopen( filename, "w" );
2058 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002059 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002060 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002061 }
2062 SaveFile(fp, compact);
2063 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002064 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002065}
2066
2067
Lee Thomason2fa81722012-11-09 12:37:46 -08002068XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002069{
Ant Mitchell189198f2015-03-24 16:20:36 +00002070 // Clear any error from the last save, otherwise it will get reported
2071 // for *this* call.
Lee Thomason85536252016-06-04 19:10:53 -07002072 SetError(XML_SUCCESS, 0, 0);
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002073 XMLPrinter stream( fp, compact );
2074 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002075 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002076}
2077
Lee Thomason1ff38e02012-02-14 18:18:16 -08002078
Lee Thomason2fa81722012-11-09 12:37:46 -08002079XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002080{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002081 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002082
Lee Thomason82d32002014-02-21 22:47:18 -08002083 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002084 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002085 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002086 }
2087 if ( len == (size_t)(-1) ) {
2088 len = strlen( p );
2089 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002090 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002091 _charBuffer = new char[ len+1 ];
2092 memcpy( _charBuffer, p, len );
2093 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002094
Dmitry-Me97476b72015-01-01 16:15:57 +03002095 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002096 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002097 // clean up now essentially dangling memory.
2098 // and the parse fail can put objects in the
2099 // pools that are dead and inaccessible.
2100 DeleteChildren();
2101 _elementPool.Clear();
2102 _attributePool.Clear();
2103 _textPool.Clear();
2104 _commentPool.Clear();
2105 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002106 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002107}
2108
2109
PKEuS1c5f99e2013-07-06 11:28:39 +02002110void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002111{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002112 if ( streamer ) {
2113 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002114 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002115 else {
2116 XMLPrinter stdoutStreamer( stdout );
2117 Accept( &stdoutStreamer );
2118 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002119}
2120
2121
Lee Thomason2fa81722012-11-09 12:37:46 -08002122void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08002123{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002124 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002125 _errorID = error;
Lee Thomason584af572016-09-05 14:14:16 -07002126
2127 _errorStr1.Reset();
2128 _errorStr2.Reset();
2129
2130 if (str1)
2131 _errorStr1.SetStr(str1);
2132 if (str2)
2133 _errorStr2.SetStr(str2);
Lee Thomason67d61312012-01-24 16:01:51 -08002134}
2135
Lee Thomason331596e2014-09-11 14:56:43 -07002136const char* XMLDocument::ErrorName() const
2137{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002138 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002139 const char* errorName = _errorNames[_errorID];
2140 TIXMLASSERT( errorName && errorName[0] );
2141 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002142}
Lee Thomason5cae8972012-01-24 18:03:07 -08002143
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002144void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002145{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002146 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002147 static const int LEN = 20;
2148 char buf1[LEN] = { 0 };
2149 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002150
Lee Thomason584af572016-09-05 14:14:16 -07002151 if ( !_errorStr1.Empty() ) {
2152 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002153 }
Lee Thomason584af572016-09-05 14:14:16 -07002154 if ( !_errorStr2.Empty() ) {
2155 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002156 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002157
Dmitry-Me2ad43202015-04-16 12:18:58 +03002158 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2159 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2160 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
Lee Thomason331596e2014-09-11 14:56:43 -07002161 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
Dmitry-Me400f1192015-04-07 11:51:21 +03002162 static_cast<int>( _errorID ), ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002163 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002164}
2165
Dmitry-Me97476b72015-01-01 16:15:57 +03002166void XMLDocument::Parse()
2167{
2168 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2169 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08002170 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03002171 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03002172 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002173 if ( !*p ) {
2174 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2175 return;
2176 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08002177 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002178}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002179
PKEuS1bfb9542013-08-04 13:51:17 +02002180XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002181 _elementJustOpened( false ),
2182 _firstElement( true ),
2183 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002184 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002185 _textDepth( -1 ),
2186 _processEntities( true ),
2187 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002188{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002189 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002190 _entityFlag[i] = false;
2191 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002192 }
2193 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002194 const char entityValue = entities[i].value;
Dmitry-Mec5f1e7c2016-10-14 10:33:02 +03002195 TIXMLASSERT( ((unsigned char)entityValue) < ENTITY_RANGE );
Dmitry-Me8b67d742014-12-22 11:35:12 +03002196 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002197 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002198 _restrictedEntityFlag[(unsigned char)'&'] = true;
2199 _restrictedEntityFlag[(unsigned char)'<'] = true;
2200 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002201 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002202}
2203
2204
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002205void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002206{
2207 va_list va;
2208 va_start( va, format );
2209
Lee Thomason624d43f2012-10-12 10:58:48 -07002210 if ( _fp ) {
2211 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002212 }
2213 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002214 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002215 // Close out and re-start the va-args
2216 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002217 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002218 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002219 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002220 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002221 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002222 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002223 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002224}
2225
2226
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002227void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002228{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002229 for( int i=0; i<depth; ++i ) {
2230 Print( " " );
2231 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002232}
2233
2234
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002235void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002236{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002237 // Look for runs of bytes between entities to print.
2238 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002239
Lee Thomason624d43f2012-10-12 10:58:48 -07002240 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002241 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002242 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002243 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002244 // Remember, char is sometimes signed. (How many times has that bitten me?)
2245 if ( *q > 0 && *q < ENTITY_RANGE ) {
2246 // Check for entities. If one is found, flush
2247 // the stream up until the entity, write the
2248 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002249 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002250 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002251 const size_t delta = q - p;
2252 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002253 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002254 Print( "%.*s", toPrint, p );
2255 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002256 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002257 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002258 for( int i=0; i<NUM_ENTITIES; ++i ) {
2259 if ( entities[i].value == *q ) {
2260 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002261 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002262 break;
2263 }
2264 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002265 if ( !entityPatternPrinted ) {
2266 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2267 TIXMLASSERT( false );
2268 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002269 ++p;
2270 }
2271 }
2272 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002273 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002274 }
2275 }
2276 // Flush the remaining string. This will be the entire
2277 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002278 TIXMLASSERT( p <= q );
2279 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002280 Print( "%s", p );
2281 }
Lee Thomason857b8682012-01-25 17:50:25 -08002282}
2283
U-Stream\Leeae25a442012-02-17 17:48:16 -08002284
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002285void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002286{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002287 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002288 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 -07002289 Print( "%s", bom );
2290 }
2291 if ( writeDec ) {
2292 PushDeclaration( "xml version=\"1.0\"" );
2293 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002294}
2295
2296
Uli Kusterer593a33d2014-02-01 12:48:51 +01002297void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002298{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002299 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002300 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002301
Uli Kusterer593a33d2014-02-01 12:48:51 +01002302 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002303 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002304 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002305 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002306 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002307 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002308
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002309 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002310 _elementJustOpened = true;
2311 _firstElement = false;
2312 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002313}
2314
2315
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002316void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002317{
Lee Thomason624d43f2012-10-12 10:58:48 -07002318 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002319 Print( " %s=\"", name );
2320 PrintString( value, false );
2321 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002322}
2323
2324
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002325void XMLPrinter::PushAttribute( const char* name, int v )
2326{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002327 char buf[BUF_SIZE];
2328 XMLUtil::ToStr( v, buf, BUF_SIZE );
2329 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002330}
2331
2332
2333void XMLPrinter::PushAttribute( const char* name, unsigned v )
2334{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002335 char buf[BUF_SIZE];
2336 XMLUtil::ToStr( v, buf, BUF_SIZE );
2337 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002338}
2339
2340
Lee Thomason51c12712016-06-04 20:18:49 -07002341void XMLPrinter::PushAttribute(const char* name, int64_t v)
2342{
2343 char buf[BUF_SIZE];
2344 XMLUtil::ToStr(v, buf, BUF_SIZE);
2345 PushAttribute(name, buf);
2346}
2347
2348
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002349void XMLPrinter::PushAttribute( const char* name, bool v )
2350{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002351 char buf[BUF_SIZE];
2352 XMLUtil::ToStr( v, buf, BUF_SIZE );
2353 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002354}
2355
2356
2357void XMLPrinter::PushAttribute( const char* name, double v )
2358{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002359 char buf[BUF_SIZE];
2360 XMLUtil::ToStr( v, buf, BUF_SIZE );
2361 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002362}
2363
2364
Uli Kustererca412e82014-02-01 13:35:05 +01002365void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002366{
Lee Thomason624d43f2012-10-12 10:58:48 -07002367 --_depth;
2368 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002369
Lee Thomason624d43f2012-10-12 10:58:48 -07002370 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002371 Print( "/>" );
2372 }
2373 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002374 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002375 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002376 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002377 }
2378 Print( "</%s>", name );
2379 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002380
Lee Thomason624d43f2012-10-12 10:58:48 -07002381 if ( _textDepth == _depth ) {
2382 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002383 }
Uli Kustererca412e82014-02-01 13:35:05 +01002384 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002385 Print( "\n" );
2386 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002387 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002388}
2389
2390
Dmitry-Mea092bc12014-12-23 17:57:05 +03002391void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002392{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002393 if ( !_elementJustOpened ) {
2394 return;
2395 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002396 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002397 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002398}
2399
2400
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002401void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002402{
Lee Thomason624d43f2012-10-12 10:58:48 -07002403 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002404
Dmitry-Mea092bc12014-12-23 17:57:05 +03002405 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002406 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002407 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002408 }
2409 else {
2410 PrintString( text, true );
2411 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002412}
2413
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002414void XMLPrinter::PushText( int64_t value )
2415{
2416 char buf[BUF_SIZE];
2417 XMLUtil::ToStr( value, buf, BUF_SIZE );
2418 PushText( buf, false );
2419}
2420
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002421void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002422{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002423 char buf[BUF_SIZE];
2424 XMLUtil::ToStr( value, buf, BUF_SIZE );
2425 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002426}
2427
2428
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002429void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002430{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002431 char buf[BUF_SIZE];
2432 XMLUtil::ToStr( value, buf, BUF_SIZE );
2433 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002434}
2435
2436
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002437void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002438{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002439 char buf[BUF_SIZE];
2440 XMLUtil::ToStr( value, buf, BUF_SIZE );
2441 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002442}
2443
2444
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002445void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002446{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002447 char buf[BUF_SIZE];
2448 XMLUtil::ToStr( value, buf, BUF_SIZE );
2449 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002450}
2451
2452
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002453void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002454{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002455 char buf[BUF_SIZE];
2456 XMLUtil::ToStr( value, buf, BUF_SIZE );
2457 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002458}
2459
Lee Thomason5cae8972012-01-24 18:03:07 -08002460
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002461void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002462{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002463 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002464 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002465 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002466 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002467 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002468 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002469 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002470}
Lee Thomason751da522012-02-10 08:50:51 -08002471
2472
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002473void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002474{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002475 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002476 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002477 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002478 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002479 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002480 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002481 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002482}
2483
2484
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002485void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002486{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002487 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002488 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002489 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002490 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002491 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002492 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002493 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002494}
2495
2496
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002497bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002498{
Lee Thomason624d43f2012-10-12 10:58:48 -07002499 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002500 if ( doc.HasBOM() ) {
2501 PushHeader( true, false );
2502 }
2503 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002504}
2505
2506
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002507bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002508{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002509 const XMLElement* parentElem = 0;
2510 if ( element.Parent() ) {
2511 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002512 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002513 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002514 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002515 while ( attribute ) {
2516 PushAttribute( attribute->Name(), attribute->Value() );
2517 attribute = attribute->Next();
2518 }
2519 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002520}
2521
2522
Uli Kustererca412e82014-02-01 13:35:05 +01002523bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002524{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002525 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002526 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002527}
2528
2529
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002530bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002531{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002532 PushText( text.Value(), text.CData() );
2533 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002534}
2535
2536
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002537bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002538{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002539 PushComment( comment.Value() );
2540 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002541}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002542
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002543bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002544{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002545 PushDeclaration( declaration.Value() );
2546 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002547}
2548
2549
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002550bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002551{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002552 PushUnknown( unknown.Value() );
2553 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002554}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002555
Lee Thomason685b8952012-11-12 13:00:06 -08002556} // namespace tinyxml2
2557