blob: cd0377203b7a111d7b55a64047295f11b4d32146 [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
U-Lama\Lee560bd472011-12-28 19:42:49 -080024#include "tinyxml2.h"
25
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070026#include <new> // yes, this one new style header, is in the Android SDK.
Wilfred van Velzen67abee52016-03-25 14:01:15 +010027#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)
Lee Thomasona9cf3f92012-10-11 16:56:51 -070028# include <stddef.h>
Philipp Kloke358202c2015-07-30 16:02:26 +020029# include <stdarg.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070030#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070031# include <cstddef>
Philipp Kloke358202c2015-07-30 16:02:26 +020032# include <cstdarg>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070033#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080034
Lee Thomason53db4a62015-06-11 22:52:08 -070035#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
Dmitry-Me1ca593c2015-06-22 12:49:32 +030036 // Microsoft Visual Studio, version 2005 and higher. Not WinCE.
Lee Thomason53db4a62015-06-11 22:52:08 -070037 /*int _snprintf_s(
38 char *buffer,
39 size_t sizeOfBuffer,
40 size_t count,
41 const char *format [,
42 argument] ...
43 );*/
PKEuScac75782015-08-15 18:17:27 +020044 static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
Lee Thomason53db4a62015-06-11 22:52:08 -070045 {
46 va_list va;
47 va_start( va, format );
48 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
49 va_end( va );
50 return result;
51 }
52
PKEuScac75782015-08-15 18:17:27 +020053 static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070054 {
55 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
56 return result;
57 }
58
59 #define TIXML_VSCPRINTF _vscprintf
60 #define TIXML_SSCANF sscanf_s
61#elif defined _MSC_VER
62 // Microsoft Visual Studio 2003 and earlier or WinCE
63 #define TIXML_SNPRINTF _snprintf
64 #define TIXML_VSNPRINTF _vsnprintf
65 #define TIXML_SSCANF sscanf
Lee Thomasonaa8566b2015-06-19 16:52:40 -070066 #if (_MSC_VER < 1400 ) && (!defined WINCE)
Lee Thomason53db4a62015-06-11 22:52:08 -070067 // Microsoft Visual Studio 2003 and not WinCE.
68 #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have.
69 #else
70 // Microsoft Visual Studio 2003 and earlier or WinCE.
PKEuScac75782015-08-15 18:17:27 +020071 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070072 {
73 int len = 512;
74 for (;;) {
75 len = len*2;
76 char* str = new char[len]();
77 const int required = _vsnprintf(str, len, format, va);
78 delete[] str;
79 if ( required != -1 ) {
Dmitry-Me1d32e582015-07-27 17:11:51 +030080 TIXMLASSERT( required >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070081 len = required;
82 break;
83 }
84 }
Dmitry-Me1d32e582015-07-27 17:11:51 +030085 TIXMLASSERT( len >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070086 return len;
87 }
88 #endif
89#else
90 // GCC version 3 and higher
91 //#warning( "Using sn* functions." )
92 #define TIXML_SNPRINTF snprintf
93 #define TIXML_VSNPRINTF vsnprintf
PKEuScac75782015-08-15 18:17:27 +020094 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
Lee Thomason53db4a62015-06-11 22:52:08 -070095 {
96 int len = vsnprintf( 0, 0, format, va );
Dmitry-Me1d32e582015-07-27 17:11:51 +030097 TIXMLASSERT( len >= 0 );
Lee Thomason53db4a62015-06-11 22:52:08 -070098 return len;
99 }
100 #define TIXML_SSCANF sscanf
101#endif
102
103
Lee Thomasone4422302012-01-20 17:59:50 -0800104static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -0800105static const char LF = LINE_FEED;
106static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
107static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -0800108static const char SINGLE_QUOTE = '\'';
109static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -0800110
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800111// Bunch of unicode info at:
112// http://www.unicode.org/faq/utf_bom.html
113// ef bb bf (Microsoft "lead bytes") - designates UTF-8
114
115static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
116static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
117static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800118
Kevin Wojniak04c22d22012-11-08 11:02:22 -0800119namespace tinyxml2
120{
121
Lee Thomason8ee79892012-01-25 17:44:30 -0800122struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700123 const char* pattern;
124 int length;
125 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -0800126};
127
128static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700129static const Entity entities[NUM_ENTITIES] = {
130 { "quot", 4, DOUBLE_QUOTE },
131 { "amp", 3, '&' },
132 { "apos", 4, SINGLE_QUOTE },
133 { "lt", 2, '<' },
134 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -0800135};
136
Lee Thomasonfde6a752012-01-14 18:08:12 -0800137
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800138StrPair::~StrPair()
139{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700140 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800141}
142
143
Lee Thomason29658802014-11-27 22:31:11 -0800144void StrPair::TransferTo( StrPair* other )
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300145{
Lee Thomason29658802014-11-27 22:31:11 -0800146 if ( this == other ) {
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300147 return;
148 }
149 // This in effect implements the assignment operator by "moving"
150 // ownership (as in auto_ptr).
151
Dmitry-Medb02b212016-08-04 17:16:05 +0300152 TIXMLASSERT( other != 0 );
Lee Thomason29658802014-11-27 22:31:11 -0800153 TIXMLASSERT( other->_flags == 0 );
154 TIXMLASSERT( other->_start == 0 );
155 TIXMLASSERT( other->_end == 0 );
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300156
Lee Thomason29658802014-11-27 22:31:11 -0800157 other->Reset();
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300158
Lee Thomason29658802014-11-27 22:31:11 -0800159 other->_flags = _flags;
160 other->_start = _start;
161 other->_end = _end;
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300162
163 _flags = 0;
164 _start = 0;
165 _end = 0;
166}
167
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800168void StrPair::Reset()
169{
Lee Thomason120b3a62012-10-12 10:06:59 -0700170 if ( _flags & NEEDS_DELETE ) {
171 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700172 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700173 _flags = 0;
174 _start = 0;
175 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800176}
177
178
179void StrPair::SetStr( const char* str, int flags )
180{
Dmitry-Me0515fa92015-12-09 11:54:06 +0300181 TIXMLASSERT( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700182 Reset();
183 size_t len = strlen( str );
Dmitry-Me96f38cc2015-08-10 16:45:12 +0300184 TIXMLASSERT( _start == 0 );
Lee Thomason120b3a62012-10-12 10:06:59 -0700185 _start = new char[ len+1 ];
186 memcpy( _start, str, len+1 );
187 _end = _start + len;
188 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800189}
190
191
192char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
193{
Dmitry-Mef9f3c3e2016-08-30 15:51:55 +0300194 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700195 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800196
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400197 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700198 char endChar = *endTag;
199 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800200
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700201 // Inner loop of text parsing.
202 while ( *p ) {
203 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
204 Set( start, p, strFlags );
205 return p + length;
206 }
207 ++p;
Dmitry-Mef9f3c3e2016-08-30 15:51:55 +0300208 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700209 }
210 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800211}
212
213
214char* StrPair::ParseName( char* p )
215{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400216 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700217 return 0;
218 }
JayXonee525db2014-12-24 04:01:42 -0500219 if ( !XMLUtil::IsNameStartChar( *p ) ) {
220 return 0;
221 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800222
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400223 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500224 ++p;
225 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700226 ++p;
227 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800228
JayXonee525db2014-12-24 04:01:42 -0500229 Set( start, p, 0 );
230 return p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800231}
232
233
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700234void StrPair::CollapseWhitespace()
235{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400236 // Adjusting _start would cause undefined behavior on delete[]
237 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700238 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700239 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700240
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300241 if ( *_start ) {
Dmitry-Me24495822016-09-02 16:53:32 +0300242 const char* p = _start; // the read pointer
Lee Thomason120b3a62012-10-12 10:06:59 -0700243 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700244
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700245 while( *p ) {
246 if ( XMLUtil::IsWhiteSpace( *p )) {
247 p = XMLUtil::SkipWhiteSpace( p );
248 if ( *p == 0 ) {
249 break; // don't write to q; this trims the trailing space.
250 }
251 *q = ' ';
252 ++q;
253 }
254 *q = *p;
255 ++q;
256 ++p;
257 }
258 *q = 0;
259 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700260}
261
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800262
Lee Thomasone4422302012-01-20 17:59:50 -0800263const char* StrPair::GetStr()
264{
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300265 TIXMLASSERT( _start );
266 TIXMLASSERT( _end );
Lee Thomason120b3a62012-10-12 10:06:59 -0700267 if ( _flags & NEEDS_FLUSH ) {
268 *_end = 0;
269 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800270
Lee Thomason120b3a62012-10-12 10:06:59 -0700271 if ( _flags ) {
Dmitry-Me24495822016-09-02 16:53:32 +0300272 const char* p = _start; // the read pointer
Lee Thomason120b3a62012-10-12 10:06:59 -0700273 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800274
Lee Thomason120b3a62012-10-12 10:06:59 -0700275 while( p < _end ) {
276 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700277 // CR-LF pair becomes LF
278 // CR alone becomes LF
279 // LF-CR becomes LF
280 if ( *(p+1) == LF ) {
281 p += 2;
282 }
283 else {
284 ++p;
285 }
Dmitry-Mefed51122016-09-06 18:08:55 +0300286 *q = LF;
287 ++q;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700288 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700289 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700290 if ( *(p+1) == CR ) {
291 p += 2;
292 }
293 else {
294 ++p;
295 }
Dmitry-Mefed51122016-09-06 18:08:55 +0300296 *q = LF;
297 ++q;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700298 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700299 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700300 // Entities handled by tinyXML2:
301 // - special entities in the entity table [in/out]
302 // - numeric character reference [in]
303 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800304
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700305 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400306 const int buflen = 10;
307 char buf[buflen] = { 0 };
308 int len = 0;
Dmitry-Me6f51c802015-03-14 13:25:03 +0300309 char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
310 if ( adjusted == 0 ) {
311 *q = *p;
312 ++p;
313 ++q;
314 }
315 else {
316 TIXMLASSERT( 0 <= len && len <= buflen );
317 TIXMLASSERT( q + len <= adjusted );
318 p = adjusted;
319 memcpy( q, buf, len );
320 q += len;
321 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700322 }
323 else {
Dmitry-Me764545e2015-05-20 10:29:24 +0300324 bool entityFound = false;
325 for( int i = 0; i < NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400326 const Entity& entity = entities[i];
327 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
328 && *( p + entity.length + 1 ) == ';' ) {
329 // Found an entity - convert.
330 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700331 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400332 p += entity.length + 2;
Dmitry-Me764545e2015-05-20 10:29:24 +0300333 entityFound = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700334 break;
335 }
336 }
Dmitry-Me764545e2015-05-20 10:29:24 +0300337 if ( !entityFound ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700338 // fixme: treat as error?
339 ++p;
340 ++q;
341 }
342 }
343 }
344 else {
345 *q = *p;
346 ++p;
347 ++q;
348 }
349 }
350 *q = 0;
351 }
352 // The loop below has plenty going on, and this
353 // is a less useful mode. Break it out.
Dmitry-Me5420e542015-05-20 10:51:26 +0300354 if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700355 CollapseWhitespace();
356 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700357 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700358 }
Dmitry-Me5ffa73e2015-01-01 17:47:40 +0300359 TIXMLASSERT( _start );
Lee Thomason120b3a62012-10-12 10:06:59 -0700360 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800361}
362
Lee Thomason2c85a712012-01-31 08:24:24 -0800363
Lee Thomasone4422302012-01-20 17:59:50 -0800364
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800365
Lee Thomason56bdd022012-02-09 18:16:58 -0800366// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800367
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800368const char* XMLUtil::ReadBOM( const char* p, bool* bom )
369{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300370 TIXMLASSERT( p );
371 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700372 *bom = false;
373 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
374 // Check for BOM:
375 if ( *(pu+0) == TIXML_UTF_LEAD_0
376 && *(pu+1) == TIXML_UTF_LEAD_1
377 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
378 *bom = true;
379 p += 3;
380 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300381 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700382 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800383}
384
385
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800386void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
387{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700388 const unsigned long BYTE_MASK = 0xBF;
389 const unsigned long BYTE_MARK = 0x80;
390 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800391
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700392 if (input < 0x80) {
393 *length = 1;
394 }
395 else if ( input < 0x800 ) {
396 *length = 2;
397 }
398 else if ( input < 0x10000 ) {
399 *length = 3;
400 }
401 else if ( input < 0x200000 ) {
402 *length = 4;
403 }
404 else {
Dmitry-Me2f465c42015-03-16 11:08:23 +0300405 *length = 0; // This code won't convert this correctly anyway.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700406 return;
407 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800408
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700409 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800410
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700411 // Scary scary fall throughs.
412 switch (*length) {
413 case 4:
414 --output;
415 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
416 input >>= 6;
417 case 3:
418 --output;
419 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
420 input >>= 6;
421 case 2:
422 --output;
423 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
424 input >>= 6;
425 case 1:
426 --output;
427 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100428 break;
Dmitry-Me33bb7642015-03-14 17:14:00 +0300429 default:
430 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700431 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800432}
433
434
435const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
436{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700437 // Presume an entity, and pull it out.
438 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800439
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700440 if ( *(p+1) == '#' && *(p+2) ) {
441 unsigned long ucs = 0;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300442 TIXMLASSERT( sizeof( ucs ) >= 4 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700443 ptrdiff_t delta = 0;
444 unsigned mult = 1;
Lee Thomason7e67bc82015-01-12 14:05:12 -0800445 static const char SEMICOLON = ';';
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800446
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700447 if ( *(p+2) == 'x' ) {
448 // Hexadecimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300449 const char* q = p+3;
450 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700451 return 0;
452 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800453
Lee Thomason7e67bc82015-01-12 14:05:12 -0800454 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800455
Dmitry-Me9f56e122015-01-12 10:07:54 +0300456 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700457 return 0;
458 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800459 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800460
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700461 delta = q-p;
462 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800463
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700464 while ( *q != 'x' ) {
Lee Thomason7265b762015-03-15 16:11:47 -0700465 unsigned int digit = 0;
466
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700467 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300468 digit = *q - '0';
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700469 }
470 else if ( *q >= 'a' && *q <= 'f' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300471 digit = *q - 'a' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700472 }
473 else if ( *q >= 'A' && *q <= 'F' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300474 digit = *q - 'A' + 10;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700475 }
476 else {
477 return 0;
478 }
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100479 TIXMLASSERT( digit < 16 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300480 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
481 const unsigned int digitScaled = mult * digit;
482 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
483 ucs += digitScaled;
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300484 TIXMLASSERT( mult <= UINT_MAX / 16 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700485 mult *= 16;
486 --q;
487 }
488 }
489 else {
490 // Decimal.
Dmitry-Me6acc9a52015-01-15 13:27:47 +0300491 const char* q = p+2;
492 if ( !(*q) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700493 return 0;
494 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800495
Lee Thomason7e67bc82015-01-12 14:05:12 -0800496 q = strchr( q, SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800497
Dmitry-Me9f56e122015-01-12 10:07:54 +0300498 if ( !q ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700499 return 0;
500 }
Lee Thomason7e67bc82015-01-12 14:05:12 -0800501 TIXMLASSERT( *q == SEMICOLON );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800502
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700503 delta = q-p;
504 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800505
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700506 while ( *q != '#' ) {
507 if ( *q >= '0' && *q <= '9' ) {
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300508 const unsigned int digit = *q - '0';
Wilfred van Velzen0aeac182016-03-25 14:14:03 +0100509 TIXMLASSERT( digit < 10 );
Dmitry-Mebab9b6d2015-03-14 16:41:46 +0300510 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
511 const unsigned int digitScaled = mult * digit;
512 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
513 ucs += digitScaled;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700514 }
515 else {
516 return 0;
517 }
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300518 TIXMLASSERT( mult <= UINT_MAX / 10 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700519 mult *= 10;
520 --q;
521 }
522 }
523 // convert the UCS to UTF-8
524 ConvertUTF32ToUTF8( ucs, value, length );
525 return p + delta + 1;
526 }
527 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800528}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800529
530
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700531void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700532{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700533 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700534}
535
536
537void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
538{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700539 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700540}
541
542
543void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
544{
Doruk Turakde45d042016-08-28 20:47:08 +0200545 TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? "true" : "false" );
Lee Thomason21be8822012-07-15 17:27:22 -0700546}
547
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800548/*
549 ToStr() of a number is a very tricky topic.
550 https://github.com/leethomason/tinyxml2/issues/106
551*/
Lee Thomason21be8822012-07-15 17:27:22 -0700552void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
553{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800554 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700555}
556
557
558void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
559{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800560 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700561}
562
563
Lee Thomason51c12712016-06-04 20:18:49 -0700564void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize)
565{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700566 // horrible syntax trick to make the compiler happy about %lld
567 TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v);
Lee Thomason51c12712016-06-04 20:18:49 -0700568}
569
570
Lee Thomason21be8822012-07-15 17:27:22 -0700571bool XMLUtil::ToInt( const char* str, int* value )
572{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700573 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
574 return true;
575 }
576 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700577}
578
579bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
580{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700581 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
582 return true;
583 }
584 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700585}
586
587bool XMLUtil::ToBool( const char* str, bool* value )
588{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700589 int ival = 0;
590 if ( ToInt( str, &ival )) {
591 *value = (ival==0) ? false : true;
592 return true;
593 }
594 if ( StringEqual( str, "true" ) ) {
595 *value = true;
596 return true;
597 }
598 else if ( StringEqual( str, "false" ) ) {
599 *value = false;
600 return true;
601 }
602 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700603}
604
605
606bool XMLUtil::ToFloat( const char* str, float* value )
607{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700608 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
609 return true;
610 }
611 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700612}
613
Lee Thomason51c12712016-06-04 20:18:49 -0700614
Lee Thomason21be8822012-07-15 17:27:22 -0700615bool XMLUtil::ToDouble( const char* str, double* value )
616{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700617 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
618 return true;
619 }
620 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700621}
622
623
Lee Thomason51c12712016-06-04 20:18:49 -0700624bool XMLUtil::ToInt64(const char* str, int64_t* value)
625{
Lee Thomason5bf60e92016-07-17 22:49:40 -0700626 long long v = 0; // horrible syntax trick to make the compiler happy about %lld
627 if (TIXML_SSCANF(str, "%lld", &v) == 1) {
628 *value = (int64_t)v;
Lee Thomason51c12712016-06-04 20:18:49 -0700629 return true;
630 }
631 return false;
632}
633
634
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700635char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800636{
Dmitry-Me02384662015-03-03 16:02:13 +0300637 TIXMLASSERT( node );
638 TIXMLASSERT( p );
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400639 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700640 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300641 if( !*p ) {
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300642 *node = 0;
643 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700644 return p;
645 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800646
Dmitry-Me962083b2015-05-26 11:38:30 +0300647 // These strings define the matching patterns:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700648 static const char* xmlHeader = { "<?" };
649 static const char* commentHeader = { "<!--" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700650 static const char* cdataHeader = { "<![CDATA[" };
Dmitry-Mec505e132015-03-30 09:54:36 +0300651 static const char* dtdHeader = { "<!" };
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700652 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800653
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700654 static const int xmlHeaderLen = 2;
655 static const int commentHeaderLen = 4;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700656 static const int cdataHeaderLen = 9;
Dmitry-Mec505e132015-03-30 09:54:36 +0300657 static const int dtdHeaderLen = 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700658 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800659
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700660 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
661 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400662 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700663 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300664 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700665 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
666 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700667 p += xmlHeaderLen;
668 }
669 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300670 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700671 returnNode = new (_commentPool.Alloc()) XMLComment( this );
672 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700673 p += commentHeaderLen;
674 }
675 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300676 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700677 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700678 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700679 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700680 p += cdataHeaderLen;
681 text->SetCData( true );
682 }
683 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300684 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700685 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
686 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700687 p += dtdHeaderLen;
688 }
689 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300690 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700691 returnNode = new (_elementPool.Alloc()) XMLElement( this );
692 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700693 p += elementHeaderLen;
694 }
695 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300696 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700697 returnNode = new (_textPool.Alloc()) XMLText( this );
698 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700699 p = start; // Back it up, all the text counts.
700 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800701
Dmitry-Me02384662015-03-03 16:02:13 +0300702 TIXMLASSERT( returnNode );
703 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700704 *node = returnNode;
705 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800706}
707
708
Lee Thomason751da522012-02-10 08:50:51 -0800709bool XMLDocument::Accept( XMLVisitor* visitor ) const
710{
Dmitry-Mebbaf1e12015-01-12 14:07:10 +0300711 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700712 if ( visitor->VisitEnter( *this ) ) {
713 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
714 if ( !node->Accept( visitor ) ) {
715 break;
716 }
717 }
718 }
719 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800720}
Lee Thomason56bdd022012-02-09 18:16:58 -0800721
722
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800723// --------- XMLNode ----------- //
724
725XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700726 _document( doc ),
727 _parent( 0 ),
728 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200729 _prev( 0 ), _next( 0 ),
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700730 _userData( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200731 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800732{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800733}
734
735
736XMLNode::~XMLNode()
737{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700738 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700739 if ( _parent ) {
740 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700741 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800742}
743
Michael Daumling21626882013-10-22 17:03:37 +0200744const char* XMLNode::Value() const
745{
Dmitry-Mecaa72a62016-08-10 17:34:34 +0300746 // Edge case: XMLDocuments don't have a Value. Return null.
Sarat Addepalli9c3122b2015-05-19 12:49:32 +0530747 if ( this->ToDocument() )
Sarat Addepalli96b43462015-05-20 10:36:06 +0530748 return 0;
Michael Daumling21626882013-10-22 17:03:37 +0200749 return _value.GetStr();
750}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800751
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800752void XMLNode::SetValue( const char* str, bool staticMem )
753{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700754 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700755 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700756 }
757 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700758 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700759 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800760}
761
762
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800763void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800764{
Lee Thomason624d43f2012-10-12 10:58:48 -0700765 while( _firstChild ) {
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300766 TIXMLASSERT( _lastChild );
Dmitry-Me9cb4eca2016-08-18 18:10:59 +0300767 DeleteChild( _firstChild );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700768 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700769 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800770}
771
772
773void XMLNode::Unlink( XMLNode* child )
774{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300775 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300776 TIXMLASSERT( child->_document == _document );
Dmitry-Me9614f8f2015-04-08 10:06:06 +0300777 TIXMLASSERT( child->_parent == this );
Lee Thomason624d43f2012-10-12 10:58:48 -0700778 if ( child == _firstChild ) {
779 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700780 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700781 if ( child == _lastChild ) {
782 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700783 }
Lee Thomasond923c672012-01-23 08:44:25 -0800784
Lee Thomason624d43f2012-10-12 10:58:48 -0700785 if ( child->_prev ) {
786 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700787 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700788 if ( child->_next ) {
789 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700790 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700791 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800792}
793
794
U-Stream\Leeae25a442012-02-17 17:48:16 -0800795void XMLNode::DeleteChild( XMLNode* node )
796{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300797 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300798 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700799 TIXMLASSERT( node->_parent == this );
Jarle Strand81abfd62015-12-27 17:30:04 +0100800 Unlink( node );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400801 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800802}
803
804
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800805XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
806{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300807 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300808 if ( addThis->_document != _document ) {
809 TIXMLASSERT( false );
810 return 0;
811 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800812 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700813
Lee Thomason624d43f2012-10-12 10:58:48 -0700814 if ( _lastChild ) {
815 TIXMLASSERT( _firstChild );
816 TIXMLASSERT( _lastChild->_next == 0 );
817 _lastChild->_next = addThis;
818 addThis->_prev = _lastChild;
819 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800820
Lee Thomason624d43f2012-10-12 10:58:48 -0700821 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700822 }
823 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700824 TIXMLASSERT( _firstChild == 0 );
825 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800826
Lee Thomason624d43f2012-10-12 10:58:48 -0700827 addThis->_prev = 0;
828 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700829 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700830 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700831 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800832}
833
834
Lee Thomason1ff38e02012-02-14 18:18:16 -0800835XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
836{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300837 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300838 if ( addThis->_document != _document ) {
839 TIXMLASSERT( false );
840 return 0;
841 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800842 InsertChildPreamble( addThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700843
Lee Thomason624d43f2012-10-12 10:58:48 -0700844 if ( _firstChild ) {
845 TIXMLASSERT( _lastChild );
846 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800847
Lee Thomason624d43f2012-10-12 10:58:48 -0700848 _firstChild->_prev = addThis;
849 addThis->_next = _firstChild;
850 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800851
Lee Thomason624d43f2012-10-12 10:58:48 -0700852 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700853 }
854 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700855 TIXMLASSERT( _lastChild == 0 );
856 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800857
Lee Thomason624d43f2012-10-12 10:58:48 -0700858 addThis->_prev = 0;
859 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700860 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700861 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400862 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800863}
864
865
866XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
867{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300868 TIXMLASSERT( addThis );
869 if ( addThis->_document != _document ) {
870 TIXMLASSERT( false );
871 return 0;
872 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700873
Dmitry-Meabb2d042014-12-09 12:59:31 +0300874 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700875
Lee Thomason624d43f2012-10-12 10:58:48 -0700876 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300877 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700878 return 0;
879 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800880
Lee Thomason624d43f2012-10-12 10:58:48 -0700881 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700882 // The last node or the only node.
883 return InsertEndChild( addThis );
884 }
Lee Thomason3cebdc42015-01-05 17:16:28 -0800885 InsertChildPreamble( addThis );
Lee Thomason624d43f2012-10-12 10:58:48 -0700886 addThis->_prev = afterThis;
887 addThis->_next = afterThis->_next;
888 afterThis->_next->_prev = addThis;
889 afterThis->_next = addThis;
890 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700891 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800892}
893
894
895
896
Dmitry-Me886ad972015-07-22 11:00:51 +0300897const XMLElement* XMLNode::FirstChildElement( const char* name ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800898{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300899 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300900 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700901 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300902 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700903 }
904 }
905 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800906}
907
908
Dmitry-Me886ad972015-07-22 11:00:51 +0300909const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800910{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300911 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300912 const XMLElement* element = node->ToElementWithName( name );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700913 if ( element ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300914 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700915 }
916 }
917 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800918}
919
920
Dmitry-Me886ad972015-07-22 11:00:51 +0300921const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800922{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300923 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300924 const XMLElement* element = node->ToElementWithName( name );
925 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400926 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700927 }
928 }
929 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800930}
931
932
Dmitry-Me886ad972015-07-22 11:00:51 +0300933const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800934{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300935 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meecb9b072016-10-12 16:44:59 +0300936 const XMLElement* element = node->ToElementWithName( name );
937 if ( element ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400938 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700939 }
940 }
941 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800942}
943
944
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800945char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800946{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700947 // This is a recursive method, but thinking about it "at the current level"
948 // it is a pretty simple flat list:
949 // <foo/>
950 // <!-- comment -->
951 //
952 // With a special case:
953 // <foo>
954 // </foo>
955 // <!-- comment -->
956 //
957 // Where the closing element (/foo) *must* be the next thing after the opening
958 // element, and the names must match. BUT the tricky bit is that the closing
959 // element will be read by the child.
960 //
961 // 'endTag' is the end tag for this node, it is returned by a call to a child.
962 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800963
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700964 while( p && *p ) {
965 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800966
Lee Thomason624d43f2012-10-12 10:58:48 -0700967 p = _document->Identify( p, &node );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300968 if ( node == 0 ) {
969 break;
970 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800971
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700972 StrPair endTag;
973 p = node->ParseDeep( p, &endTag );
974 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400975 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700976 if ( !_document->Error() ) {
977 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700978 }
979 break;
980 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800981
Sarat Addepalli3df007e2015-05-20 10:43:51 +0530982 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530983 if ( decl ) {
Dmitry-Me446c3bc2016-11-11 10:34:56 +0300984 // Declarations are only allowed at document level
985 bool wellLocated = ( ToDocument() != 0 );
986 if ( wellLocated ) {
987 // Multiple declarations are allowed but all declarations
988 // must occur before anything else
989 for ( const XMLNode* existingNode = _document->FirstChild(); existingNode; existingNode = existingNode->NextSibling() ) {
990 if ( !existingNode->ToDeclaration() ) {
991 wellLocated = false;
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530992 break;
Dmitry-Me446c3bc2016-11-11 10:34:56 +0300993 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530994 }
Dmitry-Me446c3bc2016-11-11 10:34:56 +0300995 }
996 if ( !wellLocated ) {
997 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0 );
998 DeleteNode( node );
999 break;
1000 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +05301001 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +05301002
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001003 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001004 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -05001005 // We read the end tag. Return it to the parent.
1006 if ( ele->ClosingType() == XMLElement::CLOSING ) {
1007 if ( parentEnd ) {
1008 ele->_value.TransferTo( parentEnd );
1009 }
1010 node->_memPool->SetTracked(); // created and then immediately deleted.
1011 DeleteNode( node );
1012 return p;
1013 }
1014
1015 // Handle an end tag returned to this level.
1016 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001017 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001018 if ( endTag.Empty() ) {
1019 if ( ele->ClosingType() == XMLElement::OPEN ) {
1020 mismatch = true;
1021 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001022 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001023 else {
1024 if ( ele->ClosingType() != XMLElement::OPEN ) {
1025 mismatch = true;
1026 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001027 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001028 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001029 }
1030 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001031 if ( mismatch ) {
Dmitry-Me886ad972015-07-22 11:00:51 +03001032 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -05001033 DeleteNode( node );
1034 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001035 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001036 }
JayXondbfdd8f2014-12-12 20:07:14 -05001037 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001038 }
1039 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001040}
1041
Dmitry-Mee3225b12014-09-03 11:03:11 +04001042void XMLNode::DeleteNode( XMLNode* node )
1043{
1044 if ( node == 0 ) {
1045 return;
1046 }
1047 MemPool* pool = node->_memPool;
1048 node->~XMLNode();
1049 pool->Free( node );
1050}
1051
Lee Thomason3cebdc42015-01-05 17:16:28 -08001052void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001053{
1054 TIXMLASSERT( insertThis );
1055 TIXMLASSERT( insertThis->_document == _document );
1056
1057 if ( insertThis->_parent )
1058 insertThis->_parent->Unlink( insertThis );
1059 else
1060 insertThis->_memPool->SetTracked();
1061}
1062
Dmitry-Meecb9b072016-10-12 16:44:59 +03001063const XMLElement* XMLNode::ToElementWithName( const char* name ) const
1064{
1065 const XMLElement* element = this->ToElement();
1066 if ( element == 0 ) {
1067 return 0;
1068 }
1069 if ( name == 0 ) {
1070 return element;
1071 }
1072 if ( XMLUtil::StringEqual( element->Name(), name ) ) {
1073 return element;
1074 }
1075 return 0;
1076}
1077
Lee Thomason5492a1c2012-01-23 15:32:10 -08001078// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001079char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001080{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001081 const char* start = p;
1082 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001083 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001084 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001085 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001086 }
1087 return p;
1088 }
1089 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001090 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1091 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001092 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001093 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001094
Lee Thomason624d43f2012-10-12 10:58:48 -07001095 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001096 if ( p && *p ) {
1097 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001098 }
1099 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +03001100 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001101 }
1102 }
1103 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001104}
1105
1106
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001107XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1108{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001109 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001110 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001111 }
1112 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1113 text->SetCData( this->CData() );
1114 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001115}
1116
1117
1118bool XMLText::ShallowEqual( const XMLNode* compare ) const
1119{
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001120 const XMLText* text = compare->ToText();
1121 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001122}
1123
1124
Lee Thomason56bdd022012-02-09 18:16:58 -08001125bool XMLText::Accept( XMLVisitor* visitor ) const
1126{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001127 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001128 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001129}
1130
1131
Lee Thomason3f57d272012-01-11 15:30:03 -08001132// --------- XMLComment ---------- //
1133
Lee Thomasone4422302012-01-20 17:59:50 -08001134XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001135{
1136}
1137
1138
Lee Thomasonce0763e2012-01-11 15:43:54 -08001139XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001140{
Lee Thomason3f57d272012-01-11 15:30:03 -08001141}
1142
1143
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001144char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -08001145{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001146 // Comment parses as text.
1147 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001148 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001149 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001150 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001151 }
1152 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001153}
1154
1155
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001156XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1157{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001158 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001159 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001160 }
1161 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1162 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001163}
1164
1165
1166bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1167{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001168 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001169 const XMLComment* comment = compare->ToComment();
1170 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001171}
1172
1173
Lee Thomason751da522012-02-10 08:50:51 -08001174bool XMLComment::Accept( XMLVisitor* visitor ) const
1175{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001176 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001177 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001178}
Lee Thomason56bdd022012-02-09 18:16:58 -08001179
1180
Lee Thomason50f97b22012-02-11 16:33:40 -08001181// --------- XMLDeclaration ---------- //
1182
1183XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1184{
1185}
1186
1187
1188XMLDeclaration::~XMLDeclaration()
1189{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001190 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001191}
1192
1193
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001194char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001195{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001196 // Declaration parses as text.
1197 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001198 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001199 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001200 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001201 }
1202 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001203}
1204
1205
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001206XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1207{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001208 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001209 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001210 }
1211 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1212 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001213}
1214
1215
1216bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1217{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001218 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001219 const XMLDeclaration* declaration = compare->ToDeclaration();
1220 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001221}
1222
1223
1224
Lee Thomason50f97b22012-02-11 16:33:40 -08001225bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1226{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001227 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001228 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001229}
1230
1231// --------- XMLUnknown ---------- //
1232
1233XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1234{
1235}
1236
1237
1238XMLUnknown::~XMLUnknown()
1239{
1240}
1241
1242
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001243char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001244{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001245 // Unknown parses as text.
1246 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001247
Lee Thomason624d43f2012-10-12 10:58:48 -07001248 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001249 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001250 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001251 }
1252 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001253}
1254
1255
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001256XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1257{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001258 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001259 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001260 }
1261 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1262 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001263}
1264
1265
1266bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1267{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001268 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001269 const XMLUnknown* unknown = compare->ToUnknown();
1270 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001271}
1272
1273
Lee Thomason50f97b22012-02-11 16:33:40 -08001274bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1275{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001276 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001277 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001278}
1279
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001280// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001281
1282const char* XMLAttribute::Name() const
1283{
1284 return _name.GetStr();
1285}
1286
1287const char* XMLAttribute::Value() const
1288{
1289 return _value.GetStr();
1290}
1291
Lee Thomason6f381b72012-03-02 12:59:39 -08001292char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001293{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001294 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001295 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001296 if ( !p || !*p ) {
1297 return 0;
1298 }
Lee Thomason22aead12012-01-23 13:29:35 -08001299
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001300 // Skip white space before =
1301 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001302 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001303 return 0;
1304 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001305
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001306 ++p; // move up to opening quote
1307 p = XMLUtil::SkipWhiteSpace( p );
1308 if ( *p != '\"' && *p != '\'' ) {
1309 return 0;
1310 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001311
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001312 char endTag[2] = { *p, 0 };
1313 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001314
Lee Thomason624d43f2012-10-12 10:58:48 -07001315 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001316 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001317}
1318
1319
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001320void XMLAttribute::SetName( const char* n )
1321{
Lee Thomason624d43f2012-10-12 10:58:48 -07001322 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001323}
1324
1325
Lee Thomason2fa81722012-11-09 12:37:46 -08001326XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001327{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001328 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001329 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001330 }
1331 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001332}
1333
1334
Lee Thomason2fa81722012-11-09 12:37:46 -08001335XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001336{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001337 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001338 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001339 }
1340 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001341}
1342
1343
Lee Thomason51c12712016-06-04 20:18:49 -07001344XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1345{
1346 if (XMLUtil::ToInt64(Value(), value)) {
1347 return XML_SUCCESS;
1348 }
1349 return XML_WRONG_ATTRIBUTE_TYPE;
1350}
1351
1352
Lee Thomason2fa81722012-11-09 12:37:46 -08001353XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001354{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001355 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001356 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001357 }
1358 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001359}
1360
1361
Lee Thomason2fa81722012-11-09 12:37:46 -08001362XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001363{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001364 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001365 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001366 }
1367 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001368}
1369
1370
Lee Thomason2fa81722012-11-09 12:37:46 -08001371XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001372{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001373 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001374 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001375 }
1376 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001377}
1378
1379
1380void XMLAttribute::SetAttribute( const char* v )
1381{
Lee Thomason624d43f2012-10-12 10:58:48 -07001382 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001383}
1384
1385
Lee Thomason1ff38e02012-02-14 18:18:16 -08001386void XMLAttribute::SetAttribute( int v )
1387{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001388 char buf[BUF_SIZE];
1389 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001390 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001391}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001392
1393
1394void XMLAttribute::SetAttribute( unsigned v )
1395{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001396 char buf[BUF_SIZE];
1397 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001398 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001399}
1400
1401
Lee Thomason51c12712016-06-04 20:18:49 -07001402void XMLAttribute::SetAttribute(int64_t v)
1403{
1404 char buf[BUF_SIZE];
1405 XMLUtil::ToStr(v, buf, BUF_SIZE);
1406 _value.SetStr(buf);
1407}
1408
1409
1410
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001411void XMLAttribute::SetAttribute( bool v )
1412{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001413 char buf[BUF_SIZE];
1414 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001415 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001416}
1417
1418void XMLAttribute::SetAttribute( double v )
1419{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001420 char buf[BUF_SIZE];
1421 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001422 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001423}
1424
1425void XMLAttribute::SetAttribute( float v )
1426{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001427 char buf[BUF_SIZE];
1428 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001429 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001430}
1431
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001432
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001433// --------- XMLElement ---------- //
1434XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001435 _closingType( 0 ),
1436 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001437{
1438}
1439
1440
1441XMLElement::~XMLElement()
1442{
Lee Thomason624d43f2012-10-12 10:58:48 -07001443 while( _rootAttribute ) {
1444 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001445 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001446 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001447 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001448}
1449
1450
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001451const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1452{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001453 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001454 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1455 return a;
1456 }
1457 }
1458 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001459}
1460
1461
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001462const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001463{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001464 const XMLAttribute* a = FindAttribute( name );
1465 if ( !a ) {
1466 return 0;
1467 }
1468 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1469 return a->Value();
1470 }
1471 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001472}
1473
1474
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001475const char* XMLElement::GetText() const
1476{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001477 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001478 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001479 }
1480 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001481}
1482
1483
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001484void XMLElement::SetText( const char* inText )
1485{
Uli Kusterer869bb592014-01-21 01:36:16 +01001486 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001487 FirstChild()->SetValue( inText );
1488 else {
1489 XMLText* theText = GetDocument()->NewText( inText );
1490 InsertFirstChild( theText );
1491 }
1492}
1493
Lee Thomason5bb2d802014-01-24 10:42:57 -08001494
1495void XMLElement::SetText( int v )
1496{
1497 char buf[BUF_SIZE];
1498 XMLUtil::ToStr( v, buf, BUF_SIZE );
1499 SetText( buf );
1500}
1501
1502
1503void XMLElement::SetText( unsigned v )
1504{
1505 char buf[BUF_SIZE];
1506 XMLUtil::ToStr( v, buf, BUF_SIZE );
1507 SetText( buf );
1508}
1509
1510
Lee Thomason51c12712016-06-04 20:18:49 -07001511void XMLElement::SetText(int64_t v)
1512{
1513 char buf[BUF_SIZE];
1514 XMLUtil::ToStr(v, buf, BUF_SIZE);
1515 SetText(buf);
1516}
1517
1518
1519void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001520{
1521 char buf[BUF_SIZE];
1522 XMLUtil::ToStr( v, buf, BUF_SIZE );
1523 SetText( buf );
1524}
1525
1526
1527void XMLElement::SetText( float v )
1528{
1529 char buf[BUF_SIZE];
1530 XMLUtil::ToStr( v, buf, BUF_SIZE );
1531 SetText( buf );
1532}
1533
1534
1535void XMLElement::SetText( double v )
1536{
1537 char buf[BUF_SIZE];
1538 XMLUtil::ToStr( v, buf, BUF_SIZE );
1539 SetText( buf );
1540}
1541
1542
MortenMacFly4ee49f12013-01-14 20:03:14 +01001543XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001544{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001545 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001546 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001547 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001548 return XML_SUCCESS;
1549 }
1550 return XML_CAN_NOT_CONVERT_TEXT;
1551 }
1552 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001553}
1554
1555
MortenMacFly4ee49f12013-01-14 20:03:14 +01001556XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001557{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001558 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001559 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001560 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001561 return XML_SUCCESS;
1562 }
1563 return XML_CAN_NOT_CONVERT_TEXT;
1564 }
1565 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001566}
1567
1568
Lee Thomason51c12712016-06-04 20:18:49 -07001569XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1570{
1571 if (FirstChild() && FirstChild()->ToText()) {
1572 const char* t = FirstChild()->Value();
1573 if (XMLUtil::ToInt64(t, ival)) {
1574 return XML_SUCCESS;
1575 }
1576 return XML_CAN_NOT_CONVERT_TEXT;
1577 }
1578 return XML_NO_TEXT_NODE;
1579}
1580
1581
MortenMacFly4ee49f12013-01-14 20:03:14 +01001582XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001583{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001584 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001585 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001586 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001587 return XML_SUCCESS;
1588 }
1589 return XML_CAN_NOT_CONVERT_TEXT;
1590 }
1591 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001592}
1593
1594
MortenMacFly4ee49f12013-01-14 20:03:14 +01001595XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001596{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001597 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001598 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001599 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001600 return XML_SUCCESS;
1601 }
1602 return XML_CAN_NOT_CONVERT_TEXT;
1603 }
1604 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001605}
1606
1607
MortenMacFly4ee49f12013-01-14 20:03:14 +01001608XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001609{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001610 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001611 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001612 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001613 return XML_SUCCESS;
1614 }
1615 return XML_CAN_NOT_CONVERT_TEXT;
1616 }
1617 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001618}
1619
1620
1621
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001622XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1623{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001624 XMLAttribute* last = 0;
1625 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001626 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001627 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001628 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001629 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1630 break;
1631 }
1632 }
1633 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001634 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001635 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1636 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001637 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001638 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001639 }
1640 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001641 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001642 }
1643 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001644 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001645 }
1646 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001647}
1648
1649
U-Stream\Leeae25a442012-02-17 17:48:16 -08001650void XMLElement::DeleteAttribute( const char* name )
1651{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001652 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001653 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001654 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1655 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001656 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001657 }
1658 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001659 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001660 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001661 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001662 break;
1663 }
1664 prev = a;
1665 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001666}
1667
1668
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001669char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001670{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001671 const char* start = p;
1672 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001673
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001674 // Read the attributes.
1675 while( p ) {
1676 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001677 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001678 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001679 return 0;
1680 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001681
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001682 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001683 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001684 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001685 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1686 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001687 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001688
Lee Thomason624d43f2012-10-12 10:58:48 -07001689 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001690 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001691 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001692 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001693 return 0;
1694 }
1695 // There is a minor bug here: if the attribute in the source xml
1696 // document is duplicated, it will not be detected and the
1697 // attribute will be doubly added. However, tracking the 'prevAttribute'
1698 // avoids re-scanning the attribute list. Preferring performance for
1699 // now, may reconsider in the future.
1700 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001701 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001702 }
1703 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001704 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001705 }
1706 prevAttribute = attrib;
1707 }
1708 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001709 else if ( *p == '>' ) {
1710 ++p;
1711 break;
1712 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001713 // end of the tag
1714 else if ( *p == '/' && *(p+1) == '>' ) {
1715 _closingType = CLOSED;
1716 return p+2; // done; sealed element.
1717 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001718 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001719 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001720 return 0;
1721 }
1722 }
1723 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001724}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001725
Dmitry-Mee3225b12014-09-03 11:03:11 +04001726void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1727{
1728 if ( attribute == 0 ) {
1729 return;
1730 }
1731 MemPool* pool = attribute->_memPool;
1732 attribute->~XMLAttribute();
1733 pool->Free( attribute );
1734}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001735
Lee Thomason67d61312012-01-24 16:01:51 -08001736//
1737// <ele></ele>
1738// <ele>foo<b>bar</b></ele>
1739//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001740char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001741{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001742 // Read the element name.
1743 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001744
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001745 // The closing element is the </element> form. It is
1746 // parsed just like a regular element then deleted from
1747 // the DOM.
1748 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001749 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001750 ++p;
1751 }
Lee Thomason67d61312012-01-24 16:01:51 -08001752
Lee Thomason624d43f2012-10-12 10:58:48 -07001753 p = _value.ParseName( p );
1754 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001755 return 0;
1756 }
Lee Thomason67d61312012-01-24 16:01:51 -08001757
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001758 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001759 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001760 return p;
1761 }
Lee Thomason67d61312012-01-24 16:01:51 -08001762
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001763 p = XMLNode::ParseDeep( p, strPair );
1764 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001765}
1766
1767
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001768
1769XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1770{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001771 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001772 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001773 }
1774 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1775 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1776 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1777 }
1778 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001779}
1780
1781
1782bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1783{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001784 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001785 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001786 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001787
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001788 const XMLAttribute* a=FirstAttribute();
1789 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001790
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001791 while ( a && b ) {
1792 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1793 return false;
1794 }
1795 a = a->Next();
1796 b = b->Next();
1797 }
1798 if ( a || b ) {
1799 // different count
1800 return false;
1801 }
1802 return true;
1803 }
1804 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001805}
1806
1807
Lee Thomason751da522012-02-10 08:50:51 -08001808bool XMLElement::Accept( XMLVisitor* visitor ) const
1809{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001810 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001811 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001812 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1813 if ( !node->Accept( visitor ) ) {
1814 break;
1815 }
1816 }
1817 }
1818 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001819}
Lee Thomason56bdd022012-02-09 18:16:58 -08001820
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001821
Lee Thomason3f57d272012-01-11 15:30:03 -08001822// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001823
1824// Warning: List must match 'enum XMLError'
1825const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1826 "XML_SUCCESS",
1827 "XML_NO_ATTRIBUTE",
1828 "XML_WRONG_ATTRIBUTE_TYPE",
1829 "XML_ERROR_FILE_NOT_FOUND",
1830 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1831 "XML_ERROR_FILE_READ_ERROR",
1832 "XML_ERROR_ELEMENT_MISMATCH",
1833 "XML_ERROR_PARSING_ELEMENT",
1834 "XML_ERROR_PARSING_ATTRIBUTE",
1835 "XML_ERROR_IDENTIFYING_TAG",
1836 "XML_ERROR_PARSING_TEXT",
1837 "XML_ERROR_PARSING_CDATA",
1838 "XML_ERROR_PARSING_COMMENT",
1839 "XML_ERROR_PARSING_DECLARATION",
1840 "XML_ERROR_PARSING_UNKNOWN",
1841 "XML_ERROR_EMPTY_DOCUMENT",
1842 "XML_ERROR_MISMATCHED_ELEMENT",
1843 "XML_ERROR_PARSING",
1844 "XML_CAN_NOT_CONVERT_TEXT",
1845 "XML_NO_TEXT_NODE"
1846};
1847
1848
Lee Thomason624d43f2012-10-12 10:58:48 -07001849XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001850 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001851 _writeBOM( false ),
1852 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07001853 _errorID(XML_SUCCESS),
Lee Thomason624d43f2012-10-12 10:58:48 -07001854 _whitespace( whitespace ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001855 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001856{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03001857 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
1858 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08001859}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001860
1861
Lee Thomason3f57d272012-01-11 15:30:03 -08001862XMLDocument::~XMLDocument()
1863{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001864 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001865}
1866
1867
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001868void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001869{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001870 DeleteChildren();
1871
Dmitry-Meab37df82014-11-28 12:08:36 +03001872#ifdef DEBUG
1873 const bool hadError = Error();
1874#endif
Lee Thomason85536252016-06-04 19:10:53 -07001875 _errorID = XML_SUCCESS;
Lee Thomason584af572016-09-05 14:14:16 -07001876 _errorStr1.Reset();
1877 _errorStr2.Reset();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001878
Lee Thomason624d43f2012-10-12 10:58:48 -07001879 delete [] _charBuffer;
1880 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001881
1882#if 0
1883 _textPool.Trace( "text" );
1884 _elementPool.Trace( "element" );
1885 _commentPool.Trace( "comment" );
1886 _attributePool.Trace( "attribute" );
1887#endif
1888
1889#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001890 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001891 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1892 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1893 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1894 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1895 }
1896#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001897}
1898
Lee Thomason3f57d272012-01-11 15:30:03 -08001899
Lee Thomason2c85a712012-01-31 08:24:24 -08001900XMLElement* XMLDocument::NewElement( const char* name )
1901{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001902 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001903 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1904 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001905 ele->SetName( name );
1906 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001907}
1908
1909
Lee Thomason1ff38e02012-02-14 18:18:16 -08001910XMLComment* XMLDocument::NewComment( const char* str )
1911{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001912 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001913 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1914 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001915 comment->SetValue( str );
1916 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001917}
1918
1919
1920XMLText* XMLDocument::NewText( const char* str )
1921{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001922 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001923 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1924 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001925 text->SetValue( str );
1926 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001927}
1928
1929
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001930XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1931{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001932 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001933 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1934 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001935 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1936 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001937}
1938
1939
1940XMLUnknown* XMLDocument::NewUnknown( const char* str )
1941{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001942 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001943 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1944 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001945 unk->SetValue( str );
1946 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001947}
1948
Dmitry-Me01578db2014-08-19 10:18:48 +04001949static FILE* callfopen( const char* filepath, const char* mode )
1950{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001951 TIXMLASSERT( filepath );
1952 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001953#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1954 FILE* fp = 0;
1955 errno_t err = fopen_s( &fp, filepath, mode );
1956 if ( err ) {
1957 return 0;
1958 }
1959#else
1960 FILE* fp = fopen( filepath, mode );
1961#endif
1962 return fp;
1963}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001964
1965void XMLDocument::DeleteNode( XMLNode* node ) {
1966 TIXMLASSERT( node );
1967 TIXMLASSERT(node->_document == this );
1968 if (node->_parent) {
1969 node->_parent->DeleteChild( node );
1970 }
1971 else {
1972 // Isn't in the tree.
1973 // Use the parent delete.
1974 // Also, we need to mark it tracked: we 'know'
1975 // it was never used.
1976 node->_memPool->SetTracked();
1977 // Call the static XMLNode version:
1978 XMLNode::DeleteNode(node);
1979 }
1980}
1981
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001982
Lee Thomason2fa81722012-11-09 12:37:46 -08001983XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001984{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001985 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001986 FILE* fp = callfopen( filename, "rb" );
1987 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001988 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001989 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001990 }
1991 LoadFile( fp );
1992 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001993 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001994}
1995
Dmitry-Me901fed52015-09-25 10:29:51 +03001996// This is likely overengineered template art to have a check that unsigned long value incremented
1997// by one still fits into size_t. If size_t type is larger than unsigned long type
1998// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
1999// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
2000// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
2001// types sizes relate to each other.
2002template
2003<bool = (sizeof(unsigned long) >= sizeof(size_t))>
2004struct LongFitsIntoSizeTMinusOne {
2005 static bool Fits( unsigned long value )
2006 {
2007 return value < (size_t)-1;
2008 }
2009};
2010
2011template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02002012struct LongFitsIntoSizeTMinusOne<false> {
2013 static bool Fits( unsigned long )
2014 {
2015 return true;
2016 }
2017};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002018
Lee Thomason2fa81722012-11-09 12:37:46 -08002019XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002020{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002021 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002022
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002023 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002024 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002025 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2026 return _errorID;
2027 }
2028
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002029 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002030 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002031 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002032 if ( filelength == -1L ) {
2033 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2034 return _errorID;
2035 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002036 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002037
Dmitry-Me901fed52015-09-25 10:29:51 +03002038 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002039 // Cannot handle files which won't fit in buffer together with null terminator
2040 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2041 return _errorID;
2042 }
2043
Dmitry-Me72801b82015-05-07 09:41:39 +03002044 if ( filelength == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06002045 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002046 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002047 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002048
Dmitry-Me72801b82015-05-07 09:41:39 +03002049 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002050 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002051 _charBuffer = new char[size+1];
2052 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002053 if ( read != size ) {
2054 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002055 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002056 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002057
Lee Thomason624d43f2012-10-12 10:58:48 -07002058 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002059
Dmitry-Me97476b72015-01-01 16:15:57 +03002060 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002061 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002062}
2063
2064
Lee Thomason2fa81722012-11-09 12:37:46 -08002065XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002066{
Dmitry-Me01578db2014-08-19 10:18:48 +04002067 FILE* fp = callfopen( filename, "w" );
2068 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002069 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002070 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002071 }
2072 SaveFile(fp, compact);
2073 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002074 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002075}
2076
2077
Lee Thomason2fa81722012-11-09 12:37:46 -08002078XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002079{
Ant Mitchell189198f2015-03-24 16:20:36 +00002080 // Clear any error from the last save, otherwise it will get reported
2081 // for *this* call.
Lee Thomason85536252016-06-04 19:10:53 -07002082 SetError(XML_SUCCESS, 0, 0);
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002083 XMLPrinter stream( fp, compact );
2084 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002085 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002086}
2087
Lee Thomason1ff38e02012-02-14 18:18:16 -08002088
Lee Thomason2fa81722012-11-09 12:37:46 -08002089XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002090{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002091 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002092
Lee Thomason82d32002014-02-21 22:47:18 -08002093 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002094 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002095 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002096 }
2097 if ( len == (size_t)(-1) ) {
2098 len = strlen( p );
2099 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002100 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002101 _charBuffer = new char[ len+1 ];
2102 memcpy( _charBuffer, p, len );
2103 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002104
Dmitry-Me97476b72015-01-01 16:15:57 +03002105 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002106 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002107 // clean up now essentially dangling memory.
2108 // and the parse fail can put objects in the
2109 // pools that are dead and inaccessible.
2110 DeleteChildren();
2111 _elementPool.Clear();
2112 _attributePool.Clear();
2113 _textPool.Clear();
2114 _commentPool.Clear();
2115 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002116 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002117}
2118
2119
PKEuS1c5f99e2013-07-06 11:28:39 +02002120void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002121{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002122 if ( streamer ) {
2123 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002124 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002125 else {
2126 XMLPrinter stdoutStreamer( stdout );
2127 Accept( &stdoutStreamer );
2128 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002129}
2130
2131
Lee Thomason2fa81722012-11-09 12:37:46 -08002132void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08002133{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002134 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002135 _errorID = error;
Lee Thomason584af572016-09-05 14:14:16 -07002136
2137 _errorStr1.Reset();
2138 _errorStr2.Reset();
2139
2140 if (str1)
2141 _errorStr1.SetStr(str1);
2142 if (str2)
2143 _errorStr2.SetStr(str2);
Lee Thomason67d61312012-01-24 16:01:51 -08002144}
2145
Lee Thomason331596e2014-09-11 14:56:43 -07002146const char* XMLDocument::ErrorName() const
2147{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002148 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002149 const char* errorName = _errorNames[_errorID];
2150 TIXMLASSERT( errorName && errorName[0] );
2151 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002152}
Lee Thomason5cae8972012-01-24 18:03:07 -08002153
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002154void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002155{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002156 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002157 static const int LEN = 20;
2158 char buf1[LEN] = { 0 };
2159 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002160
Lee Thomason584af572016-09-05 14:14:16 -07002161 if ( !_errorStr1.Empty() ) {
2162 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002163 }
Lee Thomason584af572016-09-05 14:14:16 -07002164 if ( !_errorStr2.Empty() ) {
2165 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002166 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002167
Dmitry-Me2ad43202015-04-16 12:18:58 +03002168 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2169 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2170 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
Lee Thomason331596e2014-09-11 14:56:43 -07002171 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
Dmitry-Me400f1192015-04-07 11:51:21 +03002172 static_cast<int>( _errorID ), ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002173 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002174}
2175
Dmitry-Me97476b72015-01-01 16:15:57 +03002176void XMLDocument::Parse()
2177{
2178 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2179 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08002180 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03002181 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03002182 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002183 if ( !*p ) {
2184 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2185 return;
2186 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08002187 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002188}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002189
PKEuS1bfb9542013-08-04 13:51:17 +02002190XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002191 _elementJustOpened( false ),
2192 _firstElement( true ),
2193 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002194 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002195 _textDepth( -1 ),
2196 _processEntities( true ),
2197 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002198{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002199 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002200 _entityFlag[i] = false;
2201 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002202 }
2203 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002204 const char entityValue = entities[i].value;
Dmitry-Mec5f1e7c2016-10-14 10:33:02 +03002205 TIXMLASSERT( ((unsigned char)entityValue) < ENTITY_RANGE );
Dmitry-Me8b67d742014-12-22 11:35:12 +03002206 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002207 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002208 _restrictedEntityFlag[(unsigned char)'&'] = true;
2209 _restrictedEntityFlag[(unsigned char)'<'] = true;
2210 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002211 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002212}
2213
2214
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002215void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002216{
2217 va_list va;
2218 va_start( va, format );
2219
Lee Thomason624d43f2012-10-12 10:58:48 -07002220 if ( _fp ) {
2221 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002222 }
2223 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002224 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002225 // Close out and re-start the va-args
2226 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002227 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002228 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002229 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002230 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002231 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002232 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002233 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002234}
2235
2236
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002237void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002238{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002239 for( int i=0; i<depth; ++i ) {
2240 Print( " " );
2241 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002242}
2243
2244
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002245void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002246{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002247 // Look for runs of bytes between entities to print.
2248 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002249
Lee Thomason624d43f2012-10-12 10:58:48 -07002250 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002251 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002252 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002253 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002254 // Remember, char is sometimes signed. (How many times has that bitten me?)
2255 if ( *q > 0 && *q < ENTITY_RANGE ) {
2256 // Check for entities. If one is found, flush
2257 // the stream up until the entity, write the
2258 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002259 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002260 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002261 const size_t delta = q - p;
2262 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002263 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002264 Print( "%.*s", toPrint, p );
2265 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002266 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002267 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002268 for( int i=0; i<NUM_ENTITIES; ++i ) {
2269 if ( entities[i].value == *q ) {
2270 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002271 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002272 break;
2273 }
2274 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002275 if ( !entityPatternPrinted ) {
2276 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2277 TIXMLASSERT( false );
2278 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002279 ++p;
2280 }
2281 }
2282 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002283 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002284 }
2285 }
2286 // Flush the remaining string. This will be the entire
2287 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002288 TIXMLASSERT( p <= q );
2289 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002290 Print( "%s", p );
2291 }
Lee Thomason857b8682012-01-25 17:50:25 -08002292}
2293
U-Stream\Leeae25a442012-02-17 17:48:16 -08002294
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002295void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002296{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002297 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002298 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 -07002299 Print( "%s", bom );
2300 }
2301 if ( writeDec ) {
2302 PushDeclaration( "xml version=\"1.0\"" );
2303 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002304}
2305
2306
Uli Kusterer593a33d2014-02-01 12:48:51 +01002307void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002308{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002309 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002310 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002311
Uli Kusterer593a33d2014-02-01 12:48:51 +01002312 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002313 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002314 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002315 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002316 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002317 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002318
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002319 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002320 _elementJustOpened = true;
2321 _firstElement = false;
2322 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002323}
2324
2325
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002326void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002327{
Lee Thomason624d43f2012-10-12 10:58:48 -07002328 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002329 Print( " %s=\"", name );
2330 PrintString( value, false );
2331 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002332}
2333
2334
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002335void XMLPrinter::PushAttribute( const char* name, int v )
2336{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002337 char buf[BUF_SIZE];
2338 XMLUtil::ToStr( v, buf, BUF_SIZE );
2339 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002340}
2341
2342
2343void XMLPrinter::PushAttribute( const char* name, unsigned v )
2344{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002345 char buf[BUF_SIZE];
2346 XMLUtil::ToStr( v, buf, BUF_SIZE );
2347 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002348}
2349
2350
Lee Thomason51c12712016-06-04 20:18:49 -07002351void XMLPrinter::PushAttribute(const char* name, int64_t v)
2352{
2353 char buf[BUF_SIZE];
2354 XMLUtil::ToStr(v, buf, BUF_SIZE);
2355 PushAttribute(name, buf);
2356}
2357
2358
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002359void XMLPrinter::PushAttribute( const char* name, bool v )
2360{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002361 char buf[BUF_SIZE];
2362 XMLUtil::ToStr( v, buf, BUF_SIZE );
2363 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002364}
2365
2366
2367void XMLPrinter::PushAttribute( const char* name, double v )
2368{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002369 char buf[BUF_SIZE];
2370 XMLUtil::ToStr( v, buf, BUF_SIZE );
2371 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002372}
2373
2374
Uli Kustererca412e82014-02-01 13:35:05 +01002375void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002376{
Lee Thomason624d43f2012-10-12 10:58:48 -07002377 --_depth;
2378 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002379
Lee Thomason624d43f2012-10-12 10:58:48 -07002380 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002381 Print( "/>" );
2382 }
2383 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002384 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002385 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002386 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002387 }
2388 Print( "</%s>", name );
2389 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002390
Lee Thomason624d43f2012-10-12 10:58:48 -07002391 if ( _textDepth == _depth ) {
2392 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002393 }
Uli Kustererca412e82014-02-01 13:35:05 +01002394 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002395 Print( "\n" );
2396 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002397 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002398}
2399
2400
Dmitry-Mea092bc12014-12-23 17:57:05 +03002401void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002402{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002403 if ( !_elementJustOpened ) {
2404 return;
2405 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002406 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002407 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002408}
2409
2410
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002411void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002412{
Lee Thomason624d43f2012-10-12 10:58:48 -07002413 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002414
Dmitry-Mea092bc12014-12-23 17:57:05 +03002415 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002416 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002417 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002418 }
2419 else {
2420 PrintString( text, true );
2421 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002422}
2423
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002424void XMLPrinter::PushText( int64_t value )
2425{
2426 char buf[BUF_SIZE];
2427 XMLUtil::ToStr( value, buf, BUF_SIZE );
2428 PushText( buf, false );
2429}
2430
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002431void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002432{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002433 char buf[BUF_SIZE];
2434 XMLUtil::ToStr( value, buf, BUF_SIZE );
2435 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002436}
2437
2438
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002439void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002440{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002441 char buf[BUF_SIZE];
2442 XMLUtil::ToStr( value, buf, BUF_SIZE );
2443 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002444}
2445
2446
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002447void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002448{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002449 char buf[BUF_SIZE];
2450 XMLUtil::ToStr( value, buf, BUF_SIZE );
2451 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002452}
2453
2454
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002455void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002456{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002457 char buf[BUF_SIZE];
2458 XMLUtil::ToStr( value, buf, BUF_SIZE );
2459 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002460}
2461
2462
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002463void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002464{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002465 char buf[BUF_SIZE];
2466 XMLUtil::ToStr( value, buf, BUF_SIZE );
2467 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002468}
2469
Lee Thomason5cae8972012-01-24 18:03:07 -08002470
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002471void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002472{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002473 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002474 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002475 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002476 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002477 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002478 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002479 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002480}
Lee Thomason751da522012-02-10 08:50:51 -08002481
2482
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002483void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002484{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002485 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002486 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002487 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002488 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002489 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002490 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002491 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002492}
2493
2494
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002495void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002496{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002497 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002498 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002499 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002500 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002501 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002502 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002503 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002504}
2505
2506
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002507bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002508{
Lee Thomason624d43f2012-10-12 10:58:48 -07002509 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002510 if ( doc.HasBOM() ) {
2511 PushHeader( true, false );
2512 }
2513 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002514}
2515
2516
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002517bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002518{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002519 const XMLElement* parentElem = 0;
2520 if ( element.Parent() ) {
2521 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002522 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002523 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002524 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002525 while ( attribute ) {
2526 PushAttribute( attribute->Name(), attribute->Value() );
2527 attribute = attribute->Next();
2528 }
2529 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002530}
2531
2532
Uli Kustererca412e82014-02-01 13:35:05 +01002533bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002534{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002535 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002536 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002537}
2538
2539
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002540bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002541{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002542 PushText( text.Value(), text.CData() );
2543 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002544}
2545
2546
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002547bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002548{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002549 PushComment( comment.Value() );
2550 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002551}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002552
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002553bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002554{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002555 PushDeclaration( declaration.Value() );
2556 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002557}
2558
2559
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002560bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002561{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002562 PushUnknown( unknown.Value() );
2563 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002564}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002565
Lee Thomason685b8952012-11-12 13:00:06 -08002566} // namespace tinyxml2
2567