blob: 6ce4332316944d44cf8a6ac3e3b26256501a7d41 [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
U-Lama\Lee560bd472011-12-28 19:42:49 -080024#include "tinyxml2.h"
25
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070026#include <new> // yes, this one new style header, is in the Android SDK.
Wilfred van Velzen67abee52016-03-25 14:01:15 +010027#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)
Lee Thomasona9cf3f92012-10-11 16:56:51 -070028# include <stddef.h>
Philipp Kloke358202c2015-07-30 16:02:26 +020029# include <stdarg.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070030#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070031# include <cstddef>
Philipp Kloke358202c2015-07-30 16:02:26 +020032# include <cstdarg>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070033#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080034
Lee Thomason53db4a62015-06-11 22:52:08 -070035#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
Dmitry-Me1ca593c2015-06-22 12:49:32 +030036 // Microsoft Visual Studio, version 2005 and higher. Not WinCE.
Lee Thomason53db4a62015-06-11 22:52:08 -070037 /*int _snprintf_s(
38 char *buffer,
39 size_t sizeOfBuffer,
40 size_t count,
41 const char *format [,
42 argument] ...
43 );*/
PKEuScac75782015-08-15 18:17:27 +020044 static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
Lee Thomason53db4a62015-06-11 22:52:08 -070045 {
46 va_list va;
47 va_start( va, format );
48 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
49 va_end( va );
50 return result;
51 }
52
PKEuScac75782015-08-15 18:17:27 +020053 static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070054 {
55 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
56 return result;
57 }
58
59 #define TIXML_VSCPRINTF _vscprintf
60 #define TIXML_SSCANF sscanf_s
61#elif defined _MSC_VER
62 // Microsoft Visual Studio 2003 and earlier or WinCE
63 #define TIXML_SNPRINTF _snprintf
64 #define TIXML_VSNPRINTF _vsnprintf
65 #define TIXML_SSCANF sscanf
Lee Thomasonaa8566b2015-06-19 16:52:40 -070066 #if (_MSC_VER < 1400 ) && (!defined WINCE)
Lee Thomason53db4a62015-06-11 22:52:08 -070067 // Microsoft Visual Studio 2003 and not WinCE.
68 #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have.
69 #else
70 // Microsoft Visual Studio 2003 and earlier or WinCE.
PKEuScac75782015-08-15 18:17:27 +020071 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070072 {
73 int len = 512;
74 for (;;) {
75 len = len*2;
76 char* str = new char[len]();
77 const int required = _vsnprintf(str, len, format, va);
78 delete[] str;
79 if ( required != -1 ) {
Dmitry-Me1d32e582015-07-27 17:11:51 +030080 TIXMLASSERT( required >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070081 len = required;
82 break;
83 }
84 }
Dmitry-Me1d32e582015-07-27 17:11:51 +030085 TIXMLASSERT( len >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070086 return len;
87 }
88 #endif
89#else
90 // GCC version 3 and higher
91 //#warning( "Using sn* functions." )
92 #define TIXML_SNPRINTF snprintf
93 #define TIXML_VSNPRINTF vsnprintf
PKEuScac75782015-08-15 18:17:27 +020094 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070095 {
96 int len = vsnprintf( 0, 0, format, va );
Dmitry-Me1d32e582015-07-27 17:11:51 +030097 TIXMLASSERT( len >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070098 return len;
99 }
100 #define TIXML_SSCANF sscanf
101#endif
102
103
Lee Thomasone4422302012-01-20 17:59:50 -0800104static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -0800105static const char LF = LINE_FEED;
106static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
107static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -0800108static const char SINGLE_QUOTE = '\'';
109static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -0800110
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800111// Bunch of unicode info at:
112// http://www.unicode.org/faq/utf_bom.html
113// ef bb bf (Microsoft "lead bytes") - designates UTF-8
114
115static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
116static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
117static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800118
Kevin Wojniak04c22d22012-11-08 11:02:22 -0800119namespace tinyxml2
120{
121
Lee Thomason8ee79892012-01-25 17:44:30 -0800122struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700123 const char* pattern;
124 int length;
125 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -0800126};
127
128static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700129static const Entity entities[NUM_ENTITIES] = {
130 { "quot", 4, DOUBLE_QUOTE },
131 { "amp", 3, '&' },
132 { "apos", 4, SINGLE_QUOTE },
133 { "lt", 2, '<' },
134 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -0800135};
136
Lee Thomasonfde6a752012-01-14 18:08:12 -0800137
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800138StrPair::~StrPair()
139{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700140 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800141}
142
143
Lee Thomason29658802014-11-27 22:31:11 -0800144void StrPair::TransferTo( StrPair* other )
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300145{
Lee Thomason29658802014-11-27 22:31:11 -0800146 if ( this == other ) {
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300147 return;
148 }
149 // This in effect implements the assignment operator by "moving"
150 // ownership (as in auto_ptr).
151
Dmitry-Medb02b212016-08-04 17:16:05 +0300152 TIXMLASSERT( other != 0 );
Lee Thomason29658802014-11-27 22:31:11 -0800153 TIXMLASSERT( other->_flags == 0 );
154 TIXMLASSERT( other->_start == 0 );
155 TIXMLASSERT( other->_end == 0 );
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300156
Lee Thomason29658802014-11-27 22:31:11 -0800157 other->Reset();
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300158
Lee Thomason29658802014-11-27 22:31:11 -0800159 other->_flags = _flags;
160 other->_start = _start;
161 other->_end = _end;
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300162
163 _flags = 0;
164 _start = 0;
165 _end = 0;
166}
167
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800168void StrPair::Reset()
169{
Lee Thomason120b3a62012-10-12 10:06:59 -0700170 if ( _flags & NEEDS_DELETE ) {
171 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700172 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700173 _flags = 0;
174 _start = 0;
175 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800176}
177
178
179void StrPair::SetStr( const char* str, int flags )
180{
Dmitry-Me0515fa92015-12-09 11:54:06 +0300181 TIXMLASSERT( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700182 Reset();
183 size_t len = strlen( str );
Dmitry-Me96f38cc2015-08-10 16:45:12 +0300184 TIXMLASSERT( _start == 0 );
Lee Thomason120b3a62012-10-12 10:06:59 -0700185 _start = new char[ len+1 ];
186 memcpy( _start, str, len+1 );
187 _end = _start + len;
188 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800189}
190
191
192char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
193{
Dmitry-Mef9f3c3e2016-08-30 15:51:55 +0300194 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700195 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800196
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400197 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700198 char endChar = *endTag;
199 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800200
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700201 // Inner loop of text parsing.
202 while ( *p ) {
203 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
204 Set( start, p, strFlags );
205 return p + length;
206 }
207 ++p;
Dmitry-Mef9f3c3e2016-08-30 15:51:55 +0300208 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700209 }
210 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800211}
212
213
214char* StrPair::ParseName( char* p )
215{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400216 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700217 return 0;
218 }
JayXonee525db2014-12-24 04:01:42 -0500219 if ( !XMLUtil::IsNameStartChar( *p ) ) {
220 return 0;
221 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800222
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400223 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500224 ++p;
225 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700226 ++p;
227 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800228
JayXonee525db2014-12-24 04:01:42 -0500229 Set( start, p, 0 );
230 return p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800231}
232
233
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700234void StrPair::CollapseWhitespace()
235{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400236 // Adjusting _start would cause undefined behavior on delete[]
237 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700238 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700239 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700240
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300241 if ( *_start ) {
Dmitry-Me24495822016-09-02 16:53:32 +0300242 const char* p = _start; // the read pointer
Lee Thomason120b3a62012-10-12 10:06:59 -0700243 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700244
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700245 while( *p ) {
246 if ( XMLUtil::IsWhiteSpace( *p )) {
247 p = XMLUtil::SkipWhiteSpace( p );
248 if ( *p == 0 ) {
249 break; // don't write to q; this trims the trailing space.
250 }
251 *q = ' ';
252 ++q;
253 }
254 *q = *p;
255 ++q;
256 ++p;
257 }
258 *q = 0;
259 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700260}
261
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800262
Lee Thomasone4422302012-01-20 17:59:50 -0800263const char* StrPair::GetStr()
264{
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300265 TIXMLASSERT( _start );
266 TIXMLASSERT( _end );
Lee Thomason120b3a62012-10-12 10:06:59 -0700267 if ( _flags & NEEDS_FLUSH ) {
268 *_end = 0;
269 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800270
Lee Thomason120b3a62012-10-12 10:06:59 -0700271 if ( _flags ) {
Dmitry-Me24495822016-09-02 16:53:32 +0300272 const char* p = _start; // the read pointer
Lee Thomason120b3a62012-10-12 10:06:59 -0700273 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800274
Lee Thomason120b3a62012-10-12 10:06:59 -0700275 while( p < _end ) {
276 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700277 // CR-LF pair becomes LF
278 // CR alone becomes LF
279 // LF-CR becomes LF
280 if ( *(p+1) == LF ) {
281 p += 2;
282 }
283 else {
284 ++p;
285 }
Dmitry-Mefed51122016-09-06 18:08:55 +0300286 *q = LF;
287 ++q;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700288 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700289 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700290 if ( *(p+1) == CR ) {
291 p += 2;
292 }
293 else {
294 ++p;
295 }
Dmitry-Mefed51122016-09-06 18:08:55 +0300296 *q = LF;
297 ++q;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700298 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700299 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700300 // Entities handled by tinyXML2:
301 // - special entities in the entity table [in/out]
302 // - numeric character reference [in]
303 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800304
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700305 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400306 const int buflen = 10;
307 char buf[buflen] = { 0 };
308 int len = 0;
Dmitry-Me6f51c802015-03-14 13:25:03 +0300309 char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
310 if ( adjusted == 0 ) {
311 *q = *p;
312 ++p;
313 ++q;
314 }
315 else {
316 TIXMLASSERT( 0 <= len && len <= buflen );
317 TIXMLASSERT( q + len <= adjusted );
318 p = adjusted;
319 memcpy( q, buf, len );
320 q += len;
321 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700322 }
323 else {
Dmitry-Me764545e2015-05-20 10:29:24 +0300324 bool entityFound = false;
325 for( int i = 0; i < NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400326 const Entity& entity = entities[i];
327 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
328 && *( p + entity.length + 1 ) == ';' ) {
329 // Found an entity - convert.
330 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700331 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400332 p += entity.length + 2;
Dmitry-Me764545e2015-05-20 10:29:24 +0300333 entityFound = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700334 break;
335 }
336 }
Dmitry-Me764545e2015-05-20 10:29:24 +0300337 if ( !entityFound ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700338 // fixme: treat as error?
339 ++p;
340 ++q;
341 }
342 }
343 }
344 else {
345 *q = *p;
346 ++p;
347 ++q;
348 }
349 }
350 *q = 0;
351 }
352 // The loop below has plenty going on, and this
353 // is a less useful mode. Break it out.
Dmitry-Me5420e542015-05-20 10:51:26 +0300354 if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700355 CollapseWhitespace();
356 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700357 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700358 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300359 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700360 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800361}
362
Lee Thomason2c85a712012-01-31 08:24:24 -0800363
Lee Thomasone4422302012-01-20 17:59:50 -0800364
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800365
Lee Thomason56bdd022012-02-09 18:16:58 -0800366// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800367
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800368const char* XMLUtil::ReadBOM( const char* p, bool* bom )
369{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300370 TIXMLASSERT( p );
371 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700372 *bom = false;
373 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
374 // Check for BOM:
375 if ( *(pu+0) == TIXML_UTF_LEAD_0
376 && *(pu+1) == TIXML_UTF_LEAD_1
377 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
378 *bom = true;
379 p += 3;
380 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300381 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700382 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800383}
384
385
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800386void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
387{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700388 const unsigned long BYTE_MASK = 0xBF;
389 const unsigned long BYTE_MARK = 0x80;
390 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800391
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700392 if (input < 0x80) {
393 *length = 1;
394 }
395 else if ( input < 0x800 ) {
396 *length = 2;
397 }
398 else if ( input < 0x10000 ) {
399 *length = 3;
400 }
401 else if ( input < 0x200000 ) {
402 *length = 4;
403 }
404 else {
Dmitry-Me2f465c42015-03-16 11:08:23 +0300405 *length = 0; // This code won't convert this correctly anyway.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700406 return;
407 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800408
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700409 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800410
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700411 // Scary scary fall throughs.
412 switch (*length) {
413 case 4:
414 --output;
415 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
416 input >>= 6;
417 case 3:
418 --output;
419 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
420 input >>= 6;
421 case 2:
422 --output;
423 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
424 input >>= 6;
425 case 1:
426 --output;
427 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100428 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300429 default:
430 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700431 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800432}
433
434
435const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
436{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700437 // Presume an entity, and pull it out.
438 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800439
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700440 if ( *(p+1) == '#' && *(p+2) ) {
441 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300442 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700443 ptrdiff_t delta = 0;
444 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800445 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800446
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700447 if ( *(p+2) == 'x' ) {
448 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300449 const char* q = p+3;
450 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700451 return 0;
452 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800453
Lee Thomason7e67bc82015-01-12 14:05:12 -0800454 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800455
Dmitry-Me9f56e122015-01-12 10:07:54 +0300456 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700457 return 0;
458 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800459 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800460
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700461 delta = q-p;
462 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800463
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700464 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700465 unsigned int digit = 0;
466
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700467 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300468 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700469 }
470 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300471 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700472 }
473 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300474 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700475 }
476 else {
477 return 0;
478 }
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100479 TIXMLASSERT( digit < 16 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300480 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
481 const unsigned int digitScaled = mult * digit;
482 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
483 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300484 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700485 mult *= 16;
486 --q;
487 }
488 }
489 else {
490 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300491 const char* q = p+2;
492 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700493 return 0;
494 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800495
Lee Thomason7e67bc82015-01-12 14:05:12 -0800496 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800497
Dmitry-Me9f56e122015-01-12 10:07:54 +0300498 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700499 return 0;
500 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800501 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800502
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700503 delta = q-p;
504 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800505
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700506 while ( *q != '#' ) {
507 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300508 const unsigned int digit = *q - '0';
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100509 TIXMLASSERT( digit < 10 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300510 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
511 const unsigned int digitScaled = mult * digit;
512 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
513 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700514 }
515 else {
516 return 0;
517 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300518 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700519 mult *= 10;
520 --q;
521 }
522 }
523 // convert the UCS to UTF-8
524 ConvertUTF32ToUTF8( ucs, value, length );
525 return p + delta + 1;
526 }
527 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800528}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800529
530
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700531void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700532{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700533 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700534}
535
536
537void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
538{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700539 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700540}
541
542
543void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
544{
Doruk Turakde45d042016-08-28 20:47:08 +0200545 TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? "true" : "false" );
Lee Thomason21be8822012-07-15 17:27:22 -0700546}
547
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800548/*
549 ToStr() of a number is a very tricky topic.
550 https://github.com/leethomason/tinyxml2/issues/106
551*/
Lee Thomason21be8822012-07-15 17:27:22 -0700552void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
553{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800554 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700555}
556
557
558void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
559{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800560 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700561}
562
563
Lee Thomason51c12712016-06-04 20:18:49 -0700564void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize)
565{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700566 // horrible syntax trick to make the compiler happy about %lld
567 TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v);
Lee Thomason51c12712016-06-04 20:18:49 -0700568}
569
570
Lee Thomason21be8822012-07-15 17:27:22 -0700571bool XMLUtil::ToInt( const char* str, int* value )
572{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700573 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
574 return true;
575 }
576 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700577}
578
579bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
580{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700581 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
582 return true;
583 }
584 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700585}
586
587bool XMLUtil::ToBool( const char* str, bool* value )
588{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700589 int ival = 0;
590 if ( ToInt( str, &ival )) {
591 *value = (ival==0) ? false : true;
592 return true;
593 }
594 if ( StringEqual( str, "true" ) ) {
595 *value = true;
596 return true;
597 }
598 else if ( StringEqual( str, "false" ) ) {
599 *value = false;
600 return true;
601 }
602 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700603}
604
605
606bool XMLUtil::ToFloat( const char* str, float* value )
607{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700608 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
609 return true;
610 }
611 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700612}
613
Lee Thomason51c12712016-06-04 20:18:49 -0700614
Lee Thomason21be8822012-07-15 17:27:22 -0700615bool XMLUtil::ToDouble( const char* str, double* value )
616{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700617 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
618 return true;
619 }
620 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700621}
622
623
Lee Thomason51c12712016-06-04 20:18:49 -0700624bool XMLUtil::ToInt64(const char* str, int64_t* value)
625{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700626 long long v = 0; // horrible syntax trick to make the compiler happy about %lld
627 if (TIXML_SSCANF(str, "%lld", &v) == 1) {
628 *value = (int64_t)v;
Lee Thomason51c12712016-06-04 20:18:49 -0700629 return true;
630 }
631 return false;
632}
633
634
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700635char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800636{
Dmitry-Me02384662015-03-03 16:02:13 +0300637 TIXMLASSERT( node );
638 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400639 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700640 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300641 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300642 *node = 0;
643 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700644 return p;
645 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800646
Dmitry-Me962083b2015-05-26 11:38:30 +0300647 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700648 static const char* xmlHeader = { "<?" };
649 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700650 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300651 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700652 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800653
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700654 static const int xmlHeaderLen = 2;
655 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700656 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300657 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700658 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800659
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700660 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
661 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400662 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700663 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300664 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700665 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
666 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700667 p += xmlHeaderLen;
668 }
669 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300670 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700671 returnNode = new (_commentPool.Alloc()) XMLComment( this );
672 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700673 p += commentHeaderLen;
674 }
675 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300676 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700677 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700678 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700679 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700680 p += cdataHeaderLen;
681 text->SetCData( true );
682 }
683 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300684 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700685 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
686 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700687 p += dtdHeaderLen;
688 }
689 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300690 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700691 returnNode = new (_elementPool.Alloc()) XMLElement( this );
692 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700693 p += elementHeaderLen;
694 }
695 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300696 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700697 returnNode = new (_textPool.Alloc()) XMLText( this );
698 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700699 p = start; // Back it up, all the text counts.
700 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800701
Dmitry-Me02384662015-03-03 16:02:13 +0300702 TIXMLASSERT( returnNode );
703 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700704 *node = returnNode;
705 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800706}
707
708
Lee Thomason751da522012-02-10 08:50:51 -0800709bool XMLDocument::Accept( XMLVisitor* visitor ) const
710{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300711 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700712 if ( visitor->VisitEnter( *this ) ) {
713 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
714 if ( !node->Accept( visitor ) ) {
715 break;
716 }
717 }
718 }
719 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800720}
Lee Thomason56bdd022012-02-09 18:16:58 -0800721
722
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800723// --------- XMLNode ----------- //
724
725XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700726 _document( doc ),
727 _parent( 0 ),
728 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200729 _prev( 0 ), _next( 0 ),
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700730 _userData( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200731 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800732{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800733}
734
735
736XMLNode::~XMLNode()
737{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700738 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700739 if ( _parent ) {
740 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700741 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800742}
743
Michael Daumling21626882013-10-22 17:03:37 +0200744const char* XMLNode::Value() const
745{
Dmitry-Mecaa72a62016-08-10 17:34:34 +0300746 // Edge case: XMLDocuments don't have a Value. Return null.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530747 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530748 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200749 return _value.GetStr();
750}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800751
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800752void XMLNode::SetValue( const char* str, bool staticMem )
753{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700754 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700755 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700756 }
757 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700758 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700759 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800760}
761
762
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800763void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800764{
Lee Thomason624d43f2012-10-12 10:58:48 -0700765 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300766 TIXMLASSERT( _lastChild );
Dmitry-Me9cb4eca2016-08-18 18:10:59 +0300767 DeleteChild( _firstChild );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700768 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700769 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800770}
771
772
773void XMLNode::Unlink( XMLNode* child )
774{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300775 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300776 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300777 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700778 if ( child == _firstChild ) {
779 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700780 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700781 if ( child == _lastChild ) {
782 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700783 }
Lee Thomasond923c672012-01-23 08:44:25 -0800784
Lee Thomason624d43f2012-10-12 10:58:48 -0700785 if ( child->_prev ) {
786 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700787 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700788 if ( child->_next ) {
789 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700790 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700791 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800792}
793
794
U-Stream\Leeae25a442012-02-17 17:48:16 -0800795void XMLNode::DeleteChild( XMLNode* node )
796{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300797 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300798 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700799 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100800 Unlink( node );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400801 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800802}
803
804
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800805XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
806{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300807 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300808 if ( addThis->_document != _document ) {
809 TIXMLASSERT( false );
810 return 0;
811 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800812 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700813
Lee Thomason624d43f2012-10-12 10:58:48 -0700814 if ( _lastChild ) {
815 TIXMLASSERT( _firstChild );
816 TIXMLASSERT( _lastChild->_next == 0 );
817 _lastChild->_next = addThis;
818 addThis->_prev = _lastChild;
819 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800820
Lee Thomason624d43f2012-10-12 10:58:48 -0700821 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700822 }
823 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700824 TIXMLASSERT( _firstChild == 0 );
825 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800826
Lee Thomason624d43f2012-10-12 10:58:48 -0700827 addThis->_prev = 0;
828 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700829 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700830 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700831 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800832}
833
834
Lee Thomason1ff38e02012-02-14 18:18:16 -0800835XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
836{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300837 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300838 if ( addThis->_document != _document ) {
839 TIXMLASSERT( false );
840 return 0;
841 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800842 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700843
Lee Thomason624d43f2012-10-12 10:58:48 -0700844 if ( _firstChild ) {
845 TIXMLASSERT( _lastChild );
846 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800847
Lee Thomason624d43f2012-10-12 10:58:48 -0700848 _firstChild->_prev = addThis;
849 addThis->_next = _firstChild;
850 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800851
Lee Thomason624d43f2012-10-12 10:58:48 -0700852 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700853 }
854 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700855 TIXMLASSERT( _lastChild == 0 );
856 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800857
Lee Thomason624d43f2012-10-12 10:58:48 -0700858 addThis->_prev = 0;
859 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700860 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700861 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400862 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800863}
864
865
866XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
867{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300868 TIXMLASSERT( addThis );
869 if ( addThis->_document != _document ) {
870 TIXMLASSERT( false );
871 return 0;
872 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700873
Dmitry-Meabb2d042014-12-09 12:59:31 +0300874 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700875
Lee Thomason624d43f2012-10-12 10:58:48 -0700876 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300877 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700878 return 0;
879 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800880
Lee Thomason624d43f2012-10-12 10:58:48 -0700881 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700882 // The last node or the only node.
883 return InsertEndChild( addThis );
884 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800885 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700886 addThis->_prev = afterThis;
887 addThis->_next = afterThis->_next;
888 afterThis->_next->_prev = addThis;
889 afterThis->_next = addThis;
890 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700891 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800892}
893
894
895
896
Dmitry-Me886ad972015-07-22 11:00:51 +0300897const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800898{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300899 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300900 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700901 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300902 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700903 }
904 }
905 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800906}
907
908
Dmitry-Me886ad972015-07-22 11:00:51 +0300909const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800910{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300911 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300912 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700913 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300914 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700915 }
916 }
917 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800918}
919
920
Dmitry-Me886ad972015-07-22 11:00:51 +0300921const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800922{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300923 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300924 const XMLElement* element = node->ToElementWithName( name );
925 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400926 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700927 }
928 }
929 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800930}
931
932
Dmitry-Me886ad972015-07-22 11:00:51 +0300933const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800934{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300935 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300936 const XMLElement* element = node->ToElementWithName( name );
937 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400938 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700939 }
940 }
941 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800942}
943
944
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800945char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800946{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700947 // This is a recursive method, but thinking about it "at the current level"
948 // it is a pretty simple flat list:
949 // <foo/>
950 // <!-- comment -->
951 //
952 // With a special case:
953 // <foo>
954 // </foo>
955 // <!-- comment -->
956 //
957 // Where the closing element (/foo) *must* be the next thing after the opening
958 // element, and the names must match. BUT the tricky bit is that the closing
959 // element will be read by the child.
960 //
961 // 'endTag' is the end tag for this node, it is returned by a call to a child.
962 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800963
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700964 while( p && *p ) {
965 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800966
Lee Thomason624d43f2012-10-12 10:58:48 -0700967 p = _document->Identify( p, &node );
Dmitry-Me43364312016-11-07 18:48:50 +0300968 TIXMLASSERT( p );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300969 if ( node == 0 ) {
970 break;
971 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800972
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700973 StrPair endTag;
974 p = node->ParseDeep( p, &endTag );
975 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400976 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700977 if ( !_document->Error() ) {
978 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700979 }
980 break;
981 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800982
Sarat Addepalli3df007e2015-05-20 10:43:51 +0530983 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530984 if ( decl ) {
Dmitry-Me446c3bc2016-11-11 10:34:56 +0300985 // Declarations are only allowed at document level
986 bool wellLocated = ( ToDocument() != 0 );
987 if ( wellLocated ) {
988 // Multiple declarations are allowed but all declarations
989 // must occur before anything else
990 for ( const XMLNode* existingNode = _document->FirstChild(); existingNode; existingNode = existingNode->NextSibling() ) {
991 if ( !existingNode->ToDeclaration() ) {
992 wellLocated = false;
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530993 break;
Dmitry-Me446c3bc2016-11-11 10:34:56 +0300994 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530995 }
Dmitry-Me446c3bc2016-11-11 10:34:56 +0300996 }
997 if ( !wellLocated ) {
998 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0 );
999 DeleteNode( node );
1000 break;
1001 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301002 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301003
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001004 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001005 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -05001006 // We read the end tag. Return it to the parent.
1007 if ( ele->ClosingType() == XMLElement::CLOSING ) {
1008 if ( parentEnd ) {
1009 ele->_value.TransferTo( parentEnd );
1010 }
1011 node->_memPool->SetTracked(); // created and then immediately deleted.
1012 DeleteNode( node );
1013 return p;
1014 }
1015
1016 // Handle an end tag returned to this level.
1017 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001018 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001019 if ( endTag.Empty() ) {
1020 if ( ele->ClosingType() == XMLElement::OPEN ) {
1021 mismatch = true;
1022 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001023 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001024 else {
1025 if ( ele->ClosingType() != XMLElement::OPEN ) {
1026 mismatch = true;
1027 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001028 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001029 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001030 }
1031 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001032 if ( mismatch ) {
Dmitry-Me886ad972015-07-22 11:00:51 +03001033 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -05001034 DeleteNode( node );
1035 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001036 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001037 }
JayXondbfdd8f2014-12-12 20:07:14 -05001038 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001039 }
1040 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001041}
1042
Dmitry-Mee3225b12014-09-03 11:03:11 +04001043void XMLNode::DeleteNode( XMLNode* node )
1044{
1045 if ( node == 0 ) {
1046 return;
1047 }
1048 MemPool* pool = node->_memPool;
1049 node->~XMLNode();
1050 pool->Free( node );
1051}
1052
Lee Thomason3cebdc42015-01-05 17:16:28 -08001053void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001054{
1055 TIXMLASSERT( insertThis );
1056 TIXMLASSERT( insertThis->_document == _document );
1057
1058 if ( insertThis->_parent )
1059 insertThis->_parent->Unlink( insertThis );
1060 else
1061 insertThis->_memPool->SetTracked();
1062}
1063
Dmitry-Meecb9b072016-10-12 16:44:59 +03001064const XMLElement* XMLNode::ToElementWithName( const char* name ) const
1065{
1066 const XMLElement* element = this->ToElement();
1067 if ( element == 0 ) {
1068 return 0;
1069 }
1070 if ( name == 0 ) {
1071 return element;
1072 }
1073 if ( XMLUtil::StringEqual( element->Name(), name ) ) {
1074 return element;
1075 }
1076 return 0;
1077}
1078
Lee Thomason5492a1c2012-01-23 15:32:10 -08001079// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001080char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001081{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001082 const char* start = p;
1083 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001084 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001085 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001086 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001087 }
1088 return p;
1089 }
1090 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001091 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1092 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001093 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001094 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001095
Lee Thomason624d43f2012-10-12 10:58:48 -07001096 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001097 if ( p && *p ) {
1098 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001099 }
1100 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +03001101 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001102 }
1103 }
1104 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001105}
1106
1107
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001108XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1109{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001110 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001111 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001112 }
1113 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1114 text->SetCData( this->CData() );
1115 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001116}
1117
1118
1119bool XMLText::ShallowEqual( const XMLNode* compare ) const
1120{
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001121 const XMLText* text = compare->ToText();
1122 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001123}
1124
1125
Lee Thomason56bdd022012-02-09 18:16:58 -08001126bool XMLText::Accept( XMLVisitor* visitor ) const
1127{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001128 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001129 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001130}
1131
1132
Lee Thomason3f57d272012-01-11 15:30:03 -08001133// --------- XMLComment ---------- //
1134
Lee Thomasone4422302012-01-20 17:59:50 -08001135XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001136{
1137}
1138
1139
Lee Thomasonce0763e2012-01-11 15:43:54 -08001140XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001141{
Lee Thomason3f57d272012-01-11 15:30:03 -08001142}
1143
1144
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001145char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -08001146{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001147 // Comment parses as text.
1148 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001149 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001150 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001151 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001152 }
1153 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001154}
1155
1156
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001157XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1158{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001159 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001160 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001161 }
1162 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1163 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001164}
1165
1166
1167bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1168{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001169 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001170 const XMLComment* comment = compare->ToComment();
1171 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001172}
1173
1174
Lee Thomason751da522012-02-10 08:50:51 -08001175bool XMLComment::Accept( XMLVisitor* visitor ) const
1176{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001177 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001178 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001179}
Lee Thomason56bdd022012-02-09 18:16:58 -08001180
1181
Lee Thomason50f97b22012-02-11 16:33:40 -08001182// --------- XMLDeclaration ---------- //
1183
1184XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1185{
1186}
1187
1188
1189XMLDeclaration::~XMLDeclaration()
1190{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001191 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001192}
1193
1194
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001195char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001196{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001197 // Declaration parses as text.
1198 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001199 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001200 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001201 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001202 }
1203 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001204}
1205
1206
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001207XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1208{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001209 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001210 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001211 }
1212 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1213 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001214}
1215
1216
1217bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1218{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001219 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001220 const XMLDeclaration* declaration = compare->ToDeclaration();
1221 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001222}
1223
1224
1225
Lee Thomason50f97b22012-02-11 16:33:40 -08001226bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1227{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001228 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001229 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001230}
1231
1232// --------- XMLUnknown ---------- //
1233
1234XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1235{
1236}
1237
1238
1239XMLUnknown::~XMLUnknown()
1240{
1241}
1242
1243
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001244char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001245{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001246 // Unknown parses as text.
1247 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001248
Lee Thomason624d43f2012-10-12 10:58:48 -07001249 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001250 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001251 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001252 }
1253 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001254}
1255
1256
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001257XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1258{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001259 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001260 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001261 }
1262 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1263 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001264}
1265
1266
1267bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1268{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001269 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001270 const XMLUnknown* unknown = compare->ToUnknown();
1271 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001272}
1273
1274
Lee Thomason50f97b22012-02-11 16:33:40 -08001275bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1276{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001277 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001278 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001279}
1280
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001281// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001282
1283const char* XMLAttribute::Name() const
1284{
1285 return _name.GetStr();
1286}
1287
1288const char* XMLAttribute::Value() const
1289{
1290 return _value.GetStr();
1291}
1292
Lee Thomason6f381b72012-03-02 12:59:39 -08001293char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001294{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001295 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001296 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001297 if ( !p || !*p ) {
1298 return 0;
1299 }
Lee Thomason22aead12012-01-23 13:29:35 -08001300
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001301 // Skip white space before =
1302 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001303 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001304 return 0;
1305 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001306
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001307 ++p; // move up to opening quote
1308 p = XMLUtil::SkipWhiteSpace( p );
1309 if ( *p != '\"' && *p != '\'' ) {
1310 return 0;
1311 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001312
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001313 char endTag[2] = { *p, 0 };
1314 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001315
Lee Thomason624d43f2012-10-12 10:58:48 -07001316 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001317 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001318}
1319
1320
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001321void XMLAttribute::SetName( const char* n )
1322{
Lee Thomason624d43f2012-10-12 10:58:48 -07001323 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001324}
1325
1326
Lee Thomason2fa81722012-11-09 12:37:46 -08001327XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001328{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001329 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001330 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001331 }
1332 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001333}
1334
1335
Lee Thomason2fa81722012-11-09 12:37:46 -08001336XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001337{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001338 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001339 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001340 }
1341 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001342}
1343
1344
Lee Thomason51c12712016-06-04 20:18:49 -07001345XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1346{
1347 if (XMLUtil::ToInt64(Value(), value)) {
1348 return XML_SUCCESS;
1349 }
1350 return XML_WRONG_ATTRIBUTE_TYPE;
1351}
1352
1353
Lee Thomason2fa81722012-11-09 12:37:46 -08001354XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001355{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001356 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001357 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001358 }
1359 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001360}
1361
1362
Lee Thomason2fa81722012-11-09 12:37:46 -08001363XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001364{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001365 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001366 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001367 }
1368 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001369}
1370
1371
Lee Thomason2fa81722012-11-09 12:37:46 -08001372XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001373{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001374 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001375 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001376 }
1377 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001378}
1379
1380
1381void XMLAttribute::SetAttribute( const char* v )
1382{
Lee Thomason624d43f2012-10-12 10:58:48 -07001383 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001384}
1385
1386
Lee Thomason1ff38e02012-02-14 18:18:16 -08001387void XMLAttribute::SetAttribute( int v )
1388{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001389 char buf[BUF_SIZE];
1390 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001391 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001392}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001393
1394
1395void XMLAttribute::SetAttribute( unsigned v )
1396{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001397 char buf[BUF_SIZE];
1398 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001399 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001400}
1401
1402
Lee Thomason51c12712016-06-04 20:18:49 -07001403void XMLAttribute::SetAttribute(int64_t v)
1404{
1405 char buf[BUF_SIZE];
1406 XMLUtil::ToStr(v, buf, BUF_SIZE);
1407 _value.SetStr(buf);
1408}
1409
1410
1411
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001412void XMLAttribute::SetAttribute( bool v )
1413{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001414 char buf[BUF_SIZE];
1415 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001416 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001417}
1418
1419void XMLAttribute::SetAttribute( double v )
1420{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001421 char buf[BUF_SIZE];
1422 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001423 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001424}
1425
1426void XMLAttribute::SetAttribute( float v )
1427{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001428 char buf[BUF_SIZE];
1429 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001430 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001431}
1432
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001433
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001434// --------- XMLElement ---------- //
1435XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001436 _closingType( 0 ),
1437 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001438{
1439}
1440
1441
1442XMLElement::~XMLElement()
1443{
Lee Thomason624d43f2012-10-12 10:58:48 -07001444 while( _rootAttribute ) {
1445 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001446 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001447 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001448 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001449}
1450
1451
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001452const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1453{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001454 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001455 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1456 return a;
1457 }
1458 }
1459 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001460}
1461
1462
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001463const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001464{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001465 const XMLAttribute* a = FindAttribute( name );
1466 if ( !a ) {
1467 return 0;
1468 }
1469 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1470 return a->Value();
1471 }
1472 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001473}
1474
Josh Wittnercf3dd092016-10-11 18:57:17 -07001475int XMLElement::IntAttribute(const char* name, int defaultValue) const
1476{
1477 int i = defaultValue;
1478 QueryIntAttribute(name, &i);
1479 return i;
1480}
1481
1482unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
1483{
1484 unsigned i = defaultValue;
1485 QueryUnsignedAttribute(name, &i);
1486 return i;
1487}
1488
1489int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
1490{
1491 int64_t i = defaultValue;
1492 QueryInt64Attribute(name, &i);
1493 return i;
1494}
1495
1496bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
1497{
1498 bool b = defaultValue;
1499 QueryBoolAttribute(name, &b);
1500 return b;
1501}
1502
1503double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
1504{
1505 double d = defaultValue;
1506 QueryDoubleAttribute(name, &d);
1507 return d;
1508}
1509
1510float XMLElement::FloatAttribute(const char* name, float defaultValue) const
1511{
1512 float f = defaultValue;
1513 QueryFloatAttribute(name, &f);
1514 return f;
1515}
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001516
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001517const char* XMLElement::GetText() const
1518{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001519 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001520 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001521 }
1522 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001523}
1524
1525
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001526void XMLElement::SetText( const char* inText )
1527{
Uli Kusterer869bb592014-01-21 01:36:16 +01001528 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001529 FirstChild()->SetValue( inText );
1530 else {
1531 XMLText* theText = GetDocument()->NewText( inText );
1532 InsertFirstChild( theText );
1533 }
1534}
1535
Lee Thomason5bb2d802014-01-24 10:42:57 -08001536
1537void XMLElement::SetText( int v )
1538{
1539 char buf[BUF_SIZE];
1540 XMLUtil::ToStr( v, buf, BUF_SIZE );
1541 SetText( buf );
1542}
1543
1544
1545void XMLElement::SetText( unsigned v )
1546{
1547 char buf[BUF_SIZE];
1548 XMLUtil::ToStr( v, buf, BUF_SIZE );
1549 SetText( buf );
1550}
1551
1552
Lee Thomason51c12712016-06-04 20:18:49 -07001553void XMLElement::SetText(int64_t v)
1554{
1555 char buf[BUF_SIZE];
1556 XMLUtil::ToStr(v, buf, BUF_SIZE);
1557 SetText(buf);
1558}
1559
1560
1561void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001562{
1563 char buf[BUF_SIZE];
1564 XMLUtil::ToStr( v, buf, BUF_SIZE );
1565 SetText( buf );
1566}
1567
1568
1569void XMLElement::SetText( float v )
1570{
1571 char buf[BUF_SIZE];
1572 XMLUtil::ToStr( v, buf, BUF_SIZE );
1573 SetText( buf );
1574}
1575
1576
1577void XMLElement::SetText( double v )
1578{
1579 char buf[BUF_SIZE];
1580 XMLUtil::ToStr( v, buf, BUF_SIZE );
1581 SetText( buf );
1582}
1583
1584
MortenMacFly4ee49f12013-01-14 20:03:14 +01001585XMLError XMLElement::QueryIntText( int* ival ) 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::ToInt( t, ival ) ) {
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::QueryUnsignedText( unsigned* uval ) 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::ToUnsigned( t, uval ) ) {
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
Lee Thomason51c12712016-06-04 20:18:49 -07001611XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1612{
1613 if (FirstChild() && FirstChild()->ToText()) {
1614 const char* t = FirstChild()->Value();
1615 if (XMLUtil::ToInt64(t, ival)) {
1616 return XML_SUCCESS;
1617 }
1618 return XML_CAN_NOT_CONVERT_TEXT;
1619 }
1620 return XML_NO_TEXT_NODE;
1621}
1622
1623
MortenMacFly4ee49f12013-01-14 20:03:14 +01001624XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001625{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001626 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001627 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001628 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001629 return XML_SUCCESS;
1630 }
1631 return XML_CAN_NOT_CONVERT_TEXT;
1632 }
1633 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001634}
1635
1636
MortenMacFly4ee49f12013-01-14 20:03:14 +01001637XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001638{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001639 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001640 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001641 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001642 return XML_SUCCESS;
1643 }
1644 return XML_CAN_NOT_CONVERT_TEXT;
1645 }
1646 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001647}
1648
1649
MortenMacFly4ee49f12013-01-14 20:03:14 +01001650XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001651{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001652 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001653 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001654 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001655 return XML_SUCCESS;
1656 }
1657 return XML_CAN_NOT_CONVERT_TEXT;
1658 }
1659 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001660}
1661
Josh Wittnercf3dd092016-10-11 18:57:17 -07001662int XMLElement::IntText(int defaultValue) const
1663{
1664 int i = defaultValue;
1665 QueryIntText(&i);
1666 return i;
1667}
1668
1669unsigned XMLElement::UnsignedText(unsigned defaultValue) const
1670{
1671 unsigned i = defaultValue;
1672 QueryUnsignedText(&i);
1673 return i;
1674}
1675
1676int64_t XMLElement::Int64Text(int64_t defaultValue) const
1677{
1678 int64_t i = defaultValue;
1679 QueryInt64Text(&i);
1680 return i;
1681}
1682
1683bool XMLElement::BoolText(bool defaultValue) const
1684{
1685 bool b = defaultValue;
1686 QueryBoolText(&b);
1687 return b;
1688}
1689
1690double XMLElement::DoubleText(double defaultValue) const
1691{
1692 double d = defaultValue;
1693 QueryDoubleText(&d);
1694 return d;
1695}
1696
1697float XMLElement::FloatText(float defaultValue) const
1698{
1699 float f = defaultValue;
1700 QueryFloatText(&f);
1701 return f;
1702}
Lee Thomason21be8822012-07-15 17:27:22 -07001703
1704
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001705XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1706{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001707 XMLAttribute* last = 0;
1708 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001709 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001710 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001711 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001712 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1713 break;
1714 }
1715 }
1716 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001717 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001718 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1719 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001720 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001721 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001722 }
1723 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001724 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001725 }
1726 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001727 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001728 }
1729 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001730}
1731
1732
U-Stream\Leeae25a442012-02-17 17:48:16 -08001733void XMLElement::DeleteAttribute( const char* name )
1734{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001735 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001736 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001737 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1738 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001739 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001740 }
1741 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001742 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001743 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001744 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001745 break;
1746 }
1747 prev = a;
1748 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001749}
1750
1751
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001752char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001753{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001754 const char* start = p;
1755 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001756
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001757 // Read the attributes.
1758 while( p ) {
1759 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001760 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001761 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001762 return 0;
1763 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001764
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001765 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001766 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001767 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001768 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1769 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001770 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001771
Lee Thomason624d43f2012-10-12 10:58:48 -07001772 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001773 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001774 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001775 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001776 return 0;
1777 }
1778 // There is a minor bug here: if the attribute in the source xml
1779 // document is duplicated, it will not be detected and the
1780 // attribute will be doubly added. However, tracking the 'prevAttribute'
1781 // avoids re-scanning the attribute list. Preferring performance for
1782 // now, may reconsider in the future.
1783 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001784 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001785 }
1786 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001787 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001788 }
1789 prevAttribute = attrib;
1790 }
1791 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001792 else if ( *p == '>' ) {
1793 ++p;
1794 break;
1795 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001796 // end of the tag
1797 else if ( *p == '/' && *(p+1) == '>' ) {
1798 _closingType = CLOSED;
1799 return p+2; // done; sealed element.
1800 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001801 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001802 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001803 return 0;
1804 }
1805 }
1806 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001807}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001808
Dmitry-Mee3225b12014-09-03 11:03:11 +04001809void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1810{
1811 if ( attribute == 0 ) {
1812 return;
1813 }
1814 MemPool* pool = attribute->_memPool;
1815 attribute->~XMLAttribute();
1816 pool->Free( attribute );
1817}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001818
Lee Thomason67d61312012-01-24 16:01:51 -08001819//
1820// <ele></ele>
1821// <ele>foo<b>bar</b></ele>
1822//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001823char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001824{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001825 // Read the element name.
1826 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001827
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001828 // The closing element is the </element> form. It is
1829 // parsed just like a regular element then deleted from
1830 // the DOM.
1831 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001832 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001833 ++p;
1834 }
Lee Thomason67d61312012-01-24 16:01:51 -08001835
Lee Thomason624d43f2012-10-12 10:58:48 -07001836 p = _value.ParseName( p );
1837 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001838 return 0;
1839 }
Lee Thomason67d61312012-01-24 16:01:51 -08001840
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001841 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001842 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001843 return p;
1844 }
Lee Thomason67d61312012-01-24 16:01:51 -08001845
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001846 p = XMLNode::ParseDeep( p, strPair );
1847 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001848}
1849
1850
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001851
1852XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1853{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001854 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001855 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001856 }
1857 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1858 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1859 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1860 }
1861 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001862}
1863
1864
1865bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1866{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001867 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001868 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001869 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001870
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001871 const XMLAttribute* a=FirstAttribute();
1872 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001873
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001874 while ( a && b ) {
1875 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1876 return false;
1877 }
1878 a = a->Next();
1879 b = b->Next();
1880 }
1881 if ( a || b ) {
1882 // different count
1883 return false;
1884 }
1885 return true;
1886 }
1887 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001888}
1889
1890
Lee Thomason751da522012-02-10 08:50:51 -08001891bool XMLElement::Accept( XMLVisitor* visitor ) const
1892{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001893 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001894 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001895 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1896 if ( !node->Accept( visitor ) ) {
1897 break;
1898 }
1899 }
1900 }
1901 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001902}
Lee Thomason56bdd022012-02-09 18:16:58 -08001903
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001904
Lee Thomason3f57d272012-01-11 15:30:03 -08001905// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001906
1907// Warning: List must match 'enum XMLError'
1908const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1909 "XML_SUCCESS",
1910 "XML_NO_ATTRIBUTE",
1911 "XML_WRONG_ATTRIBUTE_TYPE",
1912 "XML_ERROR_FILE_NOT_FOUND",
1913 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1914 "XML_ERROR_FILE_READ_ERROR",
1915 "XML_ERROR_ELEMENT_MISMATCH",
1916 "XML_ERROR_PARSING_ELEMENT",
1917 "XML_ERROR_PARSING_ATTRIBUTE",
1918 "XML_ERROR_IDENTIFYING_TAG",
1919 "XML_ERROR_PARSING_TEXT",
1920 "XML_ERROR_PARSING_CDATA",
1921 "XML_ERROR_PARSING_COMMENT",
1922 "XML_ERROR_PARSING_DECLARATION",
1923 "XML_ERROR_PARSING_UNKNOWN",
1924 "XML_ERROR_EMPTY_DOCUMENT",
1925 "XML_ERROR_MISMATCHED_ELEMENT",
1926 "XML_ERROR_PARSING",
1927 "XML_CAN_NOT_CONVERT_TEXT",
1928 "XML_NO_TEXT_NODE"
1929};
1930
1931
Lee Thomason624d43f2012-10-12 10:58:48 -07001932XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001933 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001934 _writeBOM( false ),
1935 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07001936 _errorID(XML_SUCCESS),
Lee Thomason624d43f2012-10-12 10:58:48 -07001937 _whitespace( whitespace ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001938 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001939{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03001940 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
1941 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08001942}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001943
1944
Lee Thomason3f57d272012-01-11 15:30:03 -08001945XMLDocument::~XMLDocument()
1946{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001947 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001948}
1949
1950
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001951void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001952{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001953 DeleteChildren();
1954
Dmitry-Meab37df82014-11-28 12:08:36 +03001955#ifdef DEBUG
1956 const bool hadError = Error();
1957#endif
Dmitry-Me0d2cef02016-11-25 18:39:52 +03001958 ClearError();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001959
Lee Thomason624d43f2012-10-12 10:58:48 -07001960 delete [] _charBuffer;
1961 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001962
1963#if 0
1964 _textPool.Trace( "text" );
1965 _elementPool.Trace( "element" );
1966 _commentPool.Trace( "comment" );
1967 _attributePool.Trace( "attribute" );
1968#endif
1969
1970#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001971 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001972 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1973 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1974 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1975 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1976 }
1977#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001978}
1979
Lee Thomason3f57d272012-01-11 15:30:03 -08001980
Lee Thomason2c85a712012-01-31 08:24:24 -08001981XMLElement* XMLDocument::NewElement( const char* name )
1982{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001983 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001984 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1985 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001986 ele->SetName( name );
1987 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001988}
1989
1990
Lee Thomason1ff38e02012-02-14 18:18:16 -08001991XMLComment* XMLDocument::NewComment( const char* str )
1992{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001993 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001994 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1995 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001996 comment->SetValue( str );
1997 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001998}
1999
2000
2001XMLText* XMLDocument::NewText( const char* str )
2002{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03002003 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07002004 XMLText* text = new (_textPool.Alloc()) XMLText( this );
2005 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002006 text->SetValue( str );
2007 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08002008}
2009
2010
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002011XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2012{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03002013 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07002014 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
2015 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002016 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2017 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002018}
2019
2020
2021XMLUnknown* XMLDocument::NewUnknown( const char* str )
2022{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03002023 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07002024 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
2025 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002026 unk->SetValue( str );
2027 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002028}
2029
Dmitry-Me01578db2014-08-19 10:18:48 +04002030static FILE* callfopen( const char* filepath, const char* mode )
2031{
Dmitry-Meabb2d042014-12-09 12:59:31 +03002032 TIXMLASSERT( filepath );
2033 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04002034#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2035 FILE* fp = 0;
2036 errno_t err = fopen_s( &fp, filepath, mode );
2037 if ( err ) {
2038 return 0;
2039 }
2040#else
2041 FILE* fp = fopen( filepath, mode );
2042#endif
2043 return fp;
2044}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08002045
2046void XMLDocument::DeleteNode( XMLNode* node ) {
2047 TIXMLASSERT( node );
2048 TIXMLASSERT(node->_document == this );
2049 if (node->_parent) {
2050 node->_parent->DeleteChild( node );
2051 }
2052 else {
2053 // Isn't in the tree.
2054 // Use the parent delete.
2055 // Also, we need to mark it tracked: we 'know'
2056 // it was never used.
2057 node->_memPool->SetTracked();
2058 // Call the static XMLNode version:
2059 XMLNode::DeleteNode(node);
2060 }
2061}
2062
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002063
Lee Thomason2fa81722012-11-09 12:37:46 -08002064XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002065{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002066 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04002067 FILE* fp = callfopen( filename, "rb" );
2068 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002069 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002070 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002071 }
2072 LoadFile( fp );
2073 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002074 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002075}
2076
Dmitry-Me901fed52015-09-25 10:29:51 +03002077// This is likely overengineered template art to have a check that unsigned long value incremented
2078// by one still fits into size_t. If size_t type is larger than unsigned long type
2079// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
2080// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
2081// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
2082// types sizes relate to each other.
2083template
2084<bool = (sizeof(unsigned long) >= sizeof(size_t))>
2085struct LongFitsIntoSizeTMinusOne {
2086 static bool Fits( unsigned long value )
2087 {
2088 return value < (size_t)-1;
2089 }
2090};
2091
2092template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02002093struct LongFitsIntoSizeTMinusOne<false> {
2094 static bool Fits( unsigned long )
2095 {
2096 return true;
2097 }
2098};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002099
Lee Thomason2fa81722012-11-09 12:37:46 -08002100XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002101{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002102 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002103
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002104 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002105 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002106 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2107 return _errorID;
2108 }
2109
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002110 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002111 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002112 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002113 if ( filelength == -1L ) {
2114 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2115 return _errorID;
2116 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002117 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002118
Dmitry-Me901fed52015-09-25 10:29:51 +03002119 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002120 // Cannot handle files which won't fit in buffer together with null terminator
2121 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2122 return _errorID;
2123 }
2124
Dmitry-Me72801b82015-05-07 09:41:39 +03002125 if ( filelength == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06002126 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002127 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002128 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002129
Dmitry-Me72801b82015-05-07 09:41:39 +03002130 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002131 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002132 _charBuffer = new char[size+1];
2133 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002134 if ( read != size ) {
2135 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002136 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002137 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002138
Lee Thomason624d43f2012-10-12 10:58:48 -07002139 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002140
Dmitry-Me97476b72015-01-01 16:15:57 +03002141 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002142 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002143}
2144
2145
Lee Thomason2fa81722012-11-09 12:37:46 -08002146XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002147{
Dmitry-Me01578db2014-08-19 10:18:48 +04002148 FILE* fp = callfopen( filename, "w" );
2149 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002150 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002151 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002152 }
2153 SaveFile(fp, compact);
2154 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002155 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002156}
2157
2158
Lee Thomason2fa81722012-11-09 12:37:46 -08002159XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002160{
Ant Mitchell189198f2015-03-24 16:20:36 +00002161 // Clear any error from the last save, otherwise it will get reported
2162 // for *this* call.
Dmitry-Me0d2cef02016-11-25 18:39:52 +03002163 ClearError();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002164 XMLPrinter stream( fp, compact );
2165 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002166 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002167}
2168
Lee Thomason1ff38e02012-02-14 18:18:16 -08002169
Lee Thomason2fa81722012-11-09 12:37:46 -08002170XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002171{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002172 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002173
Lee Thomason82d32002014-02-21 22:47:18 -08002174 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002175 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002176 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002177 }
2178 if ( len == (size_t)(-1) ) {
2179 len = strlen( p );
2180 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002181 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002182 _charBuffer = new char[ len+1 ];
2183 memcpy( _charBuffer, p, len );
2184 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002185
Dmitry-Me97476b72015-01-01 16:15:57 +03002186 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002187 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002188 // clean up now essentially dangling memory.
2189 // and the parse fail can put objects in the
2190 // pools that are dead and inaccessible.
2191 DeleteChildren();
2192 _elementPool.Clear();
2193 _attributePool.Clear();
2194 _textPool.Clear();
2195 _commentPool.Clear();
2196 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002197 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002198}
2199
2200
PKEuS1c5f99e2013-07-06 11:28:39 +02002201void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002202{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002203 if ( streamer ) {
2204 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002205 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002206 else {
2207 XMLPrinter stdoutStreamer( stdout );
2208 Accept( &stdoutStreamer );
2209 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002210}
2211
2212
Lee Thomason2fa81722012-11-09 12:37:46 -08002213void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08002214{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002215 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002216 _errorID = error;
Lee Thomason584af572016-09-05 14:14:16 -07002217
2218 _errorStr1.Reset();
2219 _errorStr2.Reset();
2220
2221 if (str1)
2222 _errorStr1.SetStr(str1);
2223 if (str2)
2224 _errorStr2.SetStr(str2);
Lee Thomason67d61312012-01-24 16:01:51 -08002225}
2226
Lee Thomason331596e2014-09-11 14:56:43 -07002227const char* XMLDocument::ErrorName() const
2228{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002229 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002230 const char* errorName = _errorNames[_errorID];
2231 TIXMLASSERT( errorName && errorName[0] );
2232 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002233}
Lee Thomason5cae8972012-01-24 18:03:07 -08002234
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002235void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002236{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002237 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002238 static const int LEN = 20;
2239 char buf1[LEN] = { 0 };
2240 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002241
Lee Thomason584af572016-09-05 14:14:16 -07002242 if ( !_errorStr1.Empty() ) {
2243 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002244 }
Lee Thomason584af572016-09-05 14:14:16 -07002245 if ( !_errorStr2.Empty() ) {
2246 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002247 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002248
Dmitry-Me2ad43202015-04-16 12:18:58 +03002249 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2250 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2251 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
Lee Thomason331596e2014-09-11 14:56:43 -07002252 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
Dmitry-Me400f1192015-04-07 11:51:21 +03002253 static_cast<int>( _errorID ), ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002254 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002255}
2256
Dmitry-Me97476b72015-01-01 16:15:57 +03002257void XMLDocument::Parse()
2258{
2259 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2260 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08002261 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03002262 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03002263 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002264 if ( !*p ) {
2265 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2266 return;
2267 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08002268 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002269}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002270
PKEuS1bfb9542013-08-04 13:51:17 +02002271XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002272 _elementJustOpened( false ),
2273 _firstElement( true ),
2274 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002275 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002276 _textDepth( -1 ),
2277 _processEntities( true ),
2278 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002279{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002280 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002281 _entityFlag[i] = false;
2282 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002283 }
2284 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002285 const char entityValue = entities[i].value;
Dmitry-Mec5f1e7c2016-10-14 10:33:02 +03002286 TIXMLASSERT( ((unsigned char)entityValue) < ENTITY_RANGE );
Dmitry-Me8b67d742014-12-22 11:35:12 +03002287 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002288 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002289 _restrictedEntityFlag[(unsigned char)'&'] = true;
2290 _restrictedEntityFlag[(unsigned char)'<'] = true;
2291 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002292 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002293}
2294
2295
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002296void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002297{
2298 va_list va;
2299 va_start( va, format );
2300
Lee Thomason624d43f2012-10-12 10:58:48 -07002301 if ( _fp ) {
2302 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002303 }
2304 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002305 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002306 // Close out and re-start the va-args
2307 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002308 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002309 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002310 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002311 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002312 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002313 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002314 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002315}
2316
2317
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002318void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002319{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002320 for( int i=0; i<depth; ++i ) {
2321 Print( " " );
2322 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002323}
2324
2325
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002326void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002327{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002328 // Look for runs of bytes between entities to print.
2329 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002330
Lee Thomason624d43f2012-10-12 10:58:48 -07002331 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002332 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002333 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002334 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002335 // Remember, char is sometimes signed. (How many times has that bitten me?)
2336 if ( *q > 0 && *q < ENTITY_RANGE ) {
2337 // Check for entities. If one is found, flush
2338 // the stream up until the entity, write the
2339 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002340 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002341 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002342 const size_t delta = q - p;
2343 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002344 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002345 Print( "%.*s", toPrint, p );
2346 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002347 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002348 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002349 for( int i=0; i<NUM_ENTITIES; ++i ) {
2350 if ( entities[i].value == *q ) {
2351 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002352 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002353 break;
2354 }
2355 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002356 if ( !entityPatternPrinted ) {
2357 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2358 TIXMLASSERT( false );
2359 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002360 ++p;
2361 }
2362 }
2363 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002364 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002365 }
2366 }
2367 // Flush the remaining string. This will be the entire
2368 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002369 TIXMLASSERT( p <= q );
2370 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002371 Print( "%s", p );
2372 }
Lee Thomason857b8682012-01-25 17:50:25 -08002373}
2374
U-Stream\Leeae25a442012-02-17 17:48:16 -08002375
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002376void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002377{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002378 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002379 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 -07002380 Print( "%s", bom );
2381 }
2382 if ( writeDec ) {
2383 PushDeclaration( "xml version=\"1.0\"" );
2384 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002385}
2386
2387
Uli Kusterer593a33d2014-02-01 12:48:51 +01002388void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002389{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002390 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002391 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002392
Uli Kusterer593a33d2014-02-01 12:48:51 +01002393 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002394 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002395 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002396 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002397 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002398 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002399
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002400 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002401 _elementJustOpened = true;
2402 _firstElement = false;
2403 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002404}
2405
2406
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002407void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002408{
Lee Thomason624d43f2012-10-12 10:58:48 -07002409 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002410 Print( " %s=\"", name );
2411 PrintString( value, false );
2412 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002413}
2414
2415
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002416void XMLPrinter::PushAttribute( const char* name, int v )
2417{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002418 char buf[BUF_SIZE];
2419 XMLUtil::ToStr( v, buf, BUF_SIZE );
2420 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002421}
2422
2423
2424void XMLPrinter::PushAttribute( const char* name, unsigned v )
2425{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002426 char buf[BUF_SIZE];
2427 XMLUtil::ToStr( v, buf, BUF_SIZE );
2428 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002429}
2430
2431
Lee Thomason51c12712016-06-04 20:18:49 -07002432void XMLPrinter::PushAttribute(const char* name, int64_t v)
2433{
2434 char buf[BUF_SIZE];
2435 XMLUtil::ToStr(v, buf, BUF_SIZE);
2436 PushAttribute(name, buf);
2437}
2438
2439
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002440void XMLPrinter::PushAttribute( const char* name, bool v )
2441{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002442 char buf[BUF_SIZE];
2443 XMLUtil::ToStr( v, buf, BUF_SIZE );
2444 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002445}
2446
2447
2448void XMLPrinter::PushAttribute( const char* name, double v )
2449{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002450 char buf[BUF_SIZE];
2451 XMLUtil::ToStr( v, buf, BUF_SIZE );
2452 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002453}
2454
2455
Uli Kustererca412e82014-02-01 13:35:05 +01002456void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002457{
Lee Thomason624d43f2012-10-12 10:58:48 -07002458 --_depth;
2459 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002460
Lee Thomason624d43f2012-10-12 10:58:48 -07002461 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002462 Print( "/>" );
2463 }
2464 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002465 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002466 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002467 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002468 }
2469 Print( "</%s>", name );
2470 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002471
Lee Thomason624d43f2012-10-12 10:58:48 -07002472 if ( _textDepth == _depth ) {
2473 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002474 }
Uli Kustererca412e82014-02-01 13:35:05 +01002475 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002476 Print( "\n" );
2477 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002478 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002479}
2480
2481
Dmitry-Mea092bc12014-12-23 17:57:05 +03002482void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002483{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002484 if ( !_elementJustOpened ) {
2485 return;
2486 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002487 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002488 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002489}
2490
2491
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002492void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002493{
Lee Thomason624d43f2012-10-12 10:58:48 -07002494 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002495
Dmitry-Mea092bc12014-12-23 17:57:05 +03002496 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002497 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002498 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002499 }
2500 else {
2501 PrintString( text, true );
2502 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002503}
2504
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002505void XMLPrinter::PushText( int64_t value )
2506{
2507 char buf[BUF_SIZE];
2508 XMLUtil::ToStr( value, buf, BUF_SIZE );
2509 PushText( buf, false );
2510}
2511
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002512void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002513{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002514 char buf[BUF_SIZE];
2515 XMLUtil::ToStr( value, buf, BUF_SIZE );
2516 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002517}
2518
2519
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002520void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002521{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002522 char buf[BUF_SIZE];
2523 XMLUtil::ToStr( value, buf, BUF_SIZE );
2524 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002525}
2526
2527
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002528void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002529{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002530 char buf[BUF_SIZE];
2531 XMLUtil::ToStr( value, buf, BUF_SIZE );
2532 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002533}
2534
2535
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002536void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002537{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002538 char buf[BUF_SIZE];
2539 XMLUtil::ToStr( value, buf, BUF_SIZE );
2540 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002541}
2542
2543
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002544void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002545{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002546 char buf[BUF_SIZE];
2547 XMLUtil::ToStr( value, buf, BUF_SIZE );
2548 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002549}
2550
Lee Thomason5cae8972012-01-24 18:03:07 -08002551
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002552void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002553{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002554 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002555 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002556 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002557 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002558 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002559 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002560 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002561}
Lee Thomason751da522012-02-10 08:50:51 -08002562
2563
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002564void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002565{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002566 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002567 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002568 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002569 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002570 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002571 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002572 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002573}
2574
2575
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002576void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002577{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002578 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002579 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002580 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002581 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002582 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002583 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002584 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002585}
2586
2587
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002588bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002589{
Lee Thomason624d43f2012-10-12 10:58:48 -07002590 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002591 if ( doc.HasBOM() ) {
2592 PushHeader( true, false );
2593 }
2594 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002595}
2596
2597
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002598bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002599{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002600 const XMLElement* parentElem = 0;
2601 if ( element.Parent() ) {
2602 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002603 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002604 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002605 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002606 while ( attribute ) {
2607 PushAttribute( attribute->Name(), attribute->Value() );
2608 attribute = attribute->Next();
2609 }
2610 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002611}
2612
2613
Uli Kustererca412e82014-02-01 13:35:05 +01002614bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002615{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002616 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002617 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002618}
2619
2620
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002621bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002622{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002623 PushText( text.Value(), text.CData() );
2624 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002625}
2626
2627
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002628bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002629{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002630 PushComment( comment.Value() );
2631 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002632}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002633
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002634bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002635{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002636 PushDeclaration( declaration.Value() );
2637 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002638}
2639
2640
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002641bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002642{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002643 PushUnknown( unknown.Value() );
2644 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002645}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002646
Lee Thomason685b8952012-11-12 13:00:06 -08002647} // namespace tinyxml2
2648