blob: 7df844314b1483887f3adfec229aab2b5b780ad3 [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 ) {
900 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700901 if ( element ) {
Dmitry-Me886ad972015-07-22 11:00:51 +0300902 if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700903 return element;
904 }
905 }
906 }
907 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800908}
909
910
Dmitry-Me886ad972015-07-22 11:00:51 +0300911const XMLElement* XMLNode::LastChildElement( const char* name ) const
Lee Thomason56bdd022012-02-09 18:16:58 -0800912{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300913 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
914 const XMLElement* element = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700915 if ( element ) {
Dmitry-Me886ad972015-07-22 11:00:51 +0300916 if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700917 return element;
918 }
919 }
920 }
921 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800922}
923
924
Dmitry-Me886ad972015-07-22 11:00:51 +0300925const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800926{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300927 for( const XMLNode* node = _next; node; node = node->_next ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400928 const XMLElement* element = node->ToElement();
929 if ( element
Dmitry-Me886ad972015-07-22 11:00:51 +0300930 && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400931 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700932 }
933 }
934 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800935}
936
937
Dmitry-Me886ad972015-07-22 11:00:51 +0300938const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800939{
Dmitry-Me2667aab2015-04-03 10:56:59 +0300940 for( const XMLNode* node = _prev; node; node = node->_prev ) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400941 const XMLElement* element = node->ToElement();
942 if ( element
Dmitry-Me886ad972015-07-22 11:00:51 +0300943 && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400944 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700945 }
946 }
947 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800948}
949
950
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800951char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800952{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700953 // This is a recursive method, but thinking about it "at the current level"
954 // it is a pretty simple flat list:
955 // <foo/>
956 // <!-- comment -->
957 //
958 // With a special case:
959 // <foo>
960 // </foo>
961 // <!-- comment -->
962 //
963 // Where the closing element (/foo) *must* be the next thing after the opening
964 // element, and the names must match. BUT the tricky bit is that the closing
965 // element will be read by the child.
966 //
967 // 'endTag' is the end tag for this node, it is returned by a call to a child.
968 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800969
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700970 while( p && *p ) {
971 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800972
Lee Thomason624d43f2012-10-12 10:58:48 -0700973 p = _document->Identify( p, &node );
Dmitry-Me9fcb8762015-03-05 17:53:34 +0300974 if ( node == 0 ) {
975 break;
976 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800977
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700978 StrPair endTag;
979 p = node->ParseDeep( p, &endTag );
980 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400981 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700982 if ( !_document->Error() ) {
983 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700984 }
985 break;
986 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800987
Sarat Addepalli3df007e2015-05-20 10:43:51 +0530988 XMLDeclaration* decl = node->ToDeclaration();
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530989 if ( decl ) {
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530990 // A declaration can only be the first child of a document.
991 // Set error, if document already has children.
992 if ( !_document->NoChildren() ) {
993 _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0);
Dmitry-Me4de7abb2016-08-10 17:30:02 +0300994 DeleteNode( node );
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530995 break;
996 }
Sarat Addepallia0f499d2015-05-18 09:25:17 +0530997 }
Sarat Addepalli2f0d1732015-05-19 09:02:16 +0530998
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400999 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001000 if ( ele ) {
JayXone4bf6e32014-12-26 01:00:24 -05001001 // We read the end tag. Return it to the parent.
1002 if ( ele->ClosingType() == XMLElement::CLOSING ) {
1003 if ( parentEnd ) {
1004 ele->_value.TransferTo( parentEnd );
1005 }
1006 node->_memPool->SetTracked(); // created and then immediately deleted.
1007 DeleteNode( node );
1008 return p;
1009 }
1010
1011 // Handle an end tag returned to this level.
1012 // And handle a bunch of annoying errors.
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001013 bool mismatch = false;
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001014 if ( endTag.Empty() ) {
1015 if ( ele->ClosingType() == XMLElement::OPEN ) {
1016 mismatch = true;
1017 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001018 }
Dmitry-Me3ae4f3e2015-01-09 15:44:16 +03001019 else {
1020 if ( ele->ClosingType() != XMLElement::OPEN ) {
1021 mismatch = true;
1022 }
Dmitry-Me886ad972015-07-22 11:00:51 +03001023 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001024 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001025 }
1026 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001027 if ( mismatch ) {
Dmitry-Me886ad972015-07-22 11:00:51 +03001028 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -05001029 DeleteNode( node );
1030 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +04001031 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001032 }
JayXondbfdd8f2014-12-12 20:07:14 -05001033 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001034 }
1035 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -08001036}
1037
Dmitry-Mee3225b12014-09-03 11:03:11 +04001038void XMLNode::DeleteNode( XMLNode* node )
1039{
1040 if ( node == 0 ) {
1041 return;
1042 }
1043 MemPool* pool = node->_memPool;
1044 node->~XMLNode();
1045 pool->Free( node );
1046}
1047
Lee Thomason3cebdc42015-01-05 17:16:28 -08001048void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
Dmitry-Me74e39402015-01-01 16:26:17 +03001049{
1050 TIXMLASSERT( insertThis );
1051 TIXMLASSERT( insertThis->_document == _document );
1052
1053 if ( insertThis->_parent )
1054 insertThis->_parent->Unlink( insertThis );
1055 else
1056 insertThis->_memPool->SetTracked();
1057}
1058
Lee Thomason5492a1c2012-01-23 15:32:10 -08001059// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001060char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -08001061{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001062 const char* start = p;
1063 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001064 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001065 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001066 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001067 }
1068 return p;
1069 }
1070 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001071 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1072 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Dmitry-Me5420e542015-05-20 10:51:26 +03001073 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001074 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001075
Lee Thomason624d43f2012-10-12 10:58:48 -07001076 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001077 if ( p && *p ) {
1078 return p-1;
Dmitry-Me257e11b2015-01-09 15:50:47 +03001079 }
1080 if ( !p ) {
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +03001081 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001082 }
1083 }
1084 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -08001085}
1086
1087
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001088XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1089{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001090 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001091 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001092 }
1093 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1094 text->SetCData( this->CData() );
1095 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001096}
1097
1098
1099bool XMLText::ShallowEqual( const XMLNode* compare ) const
1100{
Dmitry-Me6d202ff2014-09-26 14:21:00 +04001101 const XMLText* text = compare->ToText();
1102 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001103}
1104
1105
Lee Thomason56bdd022012-02-09 18:16:58 -08001106bool XMLText::Accept( XMLVisitor* visitor ) const
1107{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001108 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001109 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -08001110}
1111
1112
Lee Thomason3f57d272012-01-11 15:30:03 -08001113// --------- XMLComment ---------- //
1114
Lee Thomasone4422302012-01-20 17:59:50 -08001115XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -08001116{
1117}
1118
1119
Lee Thomasonce0763e2012-01-11 15:43:54 -08001120XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -08001121{
Lee Thomason3f57d272012-01-11 15:30:03 -08001122}
1123
1124
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001125char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -08001126{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001127 // Comment parses as text.
1128 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001129 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001130 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001131 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001132 }
1133 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -08001134}
1135
1136
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001137XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1138{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001139 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001140 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001141 }
1142 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1143 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001144}
1145
1146
1147bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1148{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001149 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001150 const XMLComment* comment = compare->ToComment();
1151 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001152}
1153
1154
Lee Thomason751da522012-02-10 08:50:51 -08001155bool XMLComment::Accept( XMLVisitor* visitor ) const
1156{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001157 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001158 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001159}
Lee Thomason56bdd022012-02-09 18:16:58 -08001160
1161
Lee Thomason50f97b22012-02-11 16:33:40 -08001162// --------- XMLDeclaration ---------- //
1163
1164XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1165{
1166}
1167
1168
1169XMLDeclaration::~XMLDeclaration()
1170{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001171 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001172}
1173
1174
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001175char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001176{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001177 // Declaration parses as text.
1178 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001179 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001180 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001181 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001182 }
1183 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001184}
1185
1186
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001187XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1188{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001189 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001190 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001191 }
1192 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1193 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001194}
1195
1196
1197bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1198{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001199 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001200 const XMLDeclaration* declaration = compare->ToDeclaration();
1201 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001202}
1203
1204
1205
Lee Thomason50f97b22012-02-11 16:33:40 -08001206bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1207{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001208 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001209 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001210}
1211
1212// --------- XMLUnknown ---------- //
1213
1214XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1215{
1216}
1217
1218
1219XMLUnknown::~XMLUnknown()
1220{
1221}
1222
1223
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001224char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001225{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001226 // Unknown parses as text.
1227 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001228
Lee Thomason624d43f2012-10-12 10:58:48 -07001229 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001230 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001231 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001232 }
1233 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001234}
1235
1236
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001237XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1238{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001239 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001240 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001241 }
1242 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1243 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001244}
1245
1246
1247bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1248{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001249 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001250 const XMLUnknown* unknown = compare->ToUnknown();
1251 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001252}
1253
1254
Lee Thomason50f97b22012-02-11 16:33:40 -08001255bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1256{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001257 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001258 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001259}
1260
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001261// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001262
1263const char* XMLAttribute::Name() const
1264{
1265 return _name.GetStr();
1266}
1267
1268const char* XMLAttribute::Value() const
1269{
1270 return _value.GetStr();
1271}
1272
Lee Thomason6f381b72012-03-02 12:59:39 -08001273char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001274{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001275 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001276 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001277 if ( !p || !*p ) {
1278 return 0;
1279 }
Lee Thomason22aead12012-01-23 13:29:35 -08001280
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001281 // Skip white space before =
1282 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001283 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001284 return 0;
1285 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001286
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001287 ++p; // move up to opening quote
1288 p = XMLUtil::SkipWhiteSpace( p );
1289 if ( *p != '\"' && *p != '\'' ) {
1290 return 0;
1291 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001292
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001293 char endTag[2] = { *p, 0 };
1294 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001295
Lee Thomason624d43f2012-10-12 10:58:48 -07001296 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001297 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001298}
1299
1300
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001301void XMLAttribute::SetName( const char* n )
1302{
Lee Thomason624d43f2012-10-12 10:58:48 -07001303 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001304}
1305
1306
Lee Thomason2fa81722012-11-09 12:37:46 -08001307XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001308{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001309 if ( XMLUtil::ToInt( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001310 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001311 }
1312 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001313}
1314
1315
Lee Thomason2fa81722012-11-09 12:37:46 -08001316XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001317{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001318 if ( XMLUtil::ToUnsigned( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001319 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001320 }
1321 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001322}
1323
1324
Lee Thomason51c12712016-06-04 20:18:49 -07001325XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1326{
1327 if (XMLUtil::ToInt64(Value(), value)) {
1328 return XML_SUCCESS;
1329 }
1330 return XML_WRONG_ATTRIBUTE_TYPE;
1331}
1332
1333
Lee Thomason2fa81722012-11-09 12:37:46 -08001334XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001335{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001336 if ( XMLUtil::ToBool( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001337 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001338 }
1339 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001340}
1341
1342
Lee Thomason2fa81722012-11-09 12:37:46 -08001343XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001344{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001345 if ( XMLUtil::ToFloat( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001346 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001347 }
1348 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001349}
1350
1351
Lee Thomason2fa81722012-11-09 12:37:46 -08001352XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001353{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001354 if ( XMLUtil::ToDouble( Value(), value )) {
Lee Thomason85536252016-06-04 19:10:53 -07001355 return XML_SUCCESS;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001356 }
1357 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001358}
1359
1360
1361void XMLAttribute::SetAttribute( const char* v )
1362{
Lee Thomason624d43f2012-10-12 10:58:48 -07001363 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001364}
1365
1366
Lee Thomason1ff38e02012-02-14 18:18:16 -08001367void XMLAttribute::SetAttribute( int v )
1368{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001369 char buf[BUF_SIZE];
1370 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001371 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001372}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001373
1374
1375void XMLAttribute::SetAttribute( unsigned v )
1376{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001377 char buf[BUF_SIZE];
1378 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001379 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001380}
1381
1382
Lee Thomason51c12712016-06-04 20:18:49 -07001383void XMLAttribute::SetAttribute(int64_t v)
1384{
1385 char buf[BUF_SIZE];
1386 XMLUtil::ToStr(v, buf, BUF_SIZE);
1387 _value.SetStr(buf);
1388}
1389
1390
1391
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001392void XMLAttribute::SetAttribute( bool v )
1393{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001394 char buf[BUF_SIZE];
1395 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001396 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001397}
1398
1399void XMLAttribute::SetAttribute( double v )
1400{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001401 char buf[BUF_SIZE];
1402 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001403 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001404}
1405
1406void XMLAttribute::SetAttribute( float v )
1407{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001408 char buf[BUF_SIZE];
1409 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001410 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001411}
1412
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001413
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001414// --------- XMLElement ---------- //
1415XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001416 _closingType( 0 ),
1417 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001418{
1419}
1420
1421
1422XMLElement::~XMLElement()
1423{
Lee Thomason624d43f2012-10-12 10:58:48 -07001424 while( _rootAttribute ) {
1425 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001426 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001427 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001428 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001429}
1430
1431
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001432const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1433{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001434 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001435 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1436 return a;
1437 }
1438 }
1439 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001440}
1441
1442
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001443const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001444{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001445 const XMLAttribute* a = FindAttribute( name );
1446 if ( !a ) {
1447 return 0;
1448 }
1449 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1450 return a->Value();
1451 }
1452 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001453}
1454
1455
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001456const char* XMLElement::GetText() const
1457{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001458 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001459 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001460 }
1461 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001462}
1463
1464
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001465void XMLElement::SetText( const char* inText )
1466{
Uli Kusterer869bb592014-01-21 01:36:16 +01001467 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001468 FirstChild()->SetValue( inText );
1469 else {
1470 XMLText* theText = GetDocument()->NewText( inText );
1471 InsertFirstChild( theText );
1472 }
1473}
1474
Lee Thomason5bb2d802014-01-24 10:42:57 -08001475
1476void XMLElement::SetText( int v )
1477{
1478 char buf[BUF_SIZE];
1479 XMLUtil::ToStr( v, buf, BUF_SIZE );
1480 SetText( buf );
1481}
1482
1483
1484void XMLElement::SetText( unsigned v )
1485{
1486 char buf[BUF_SIZE];
1487 XMLUtil::ToStr( v, buf, BUF_SIZE );
1488 SetText( buf );
1489}
1490
1491
Lee Thomason51c12712016-06-04 20:18:49 -07001492void XMLElement::SetText(int64_t v)
1493{
1494 char buf[BUF_SIZE];
1495 XMLUtil::ToStr(v, buf, BUF_SIZE);
1496 SetText(buf);
1497}
1498
1499
1500void XMLElement::SetText( bool v )
Lee Thomason5bb2d802014-01-24 10:42:57 -08001501{
1502 char buf[BUF_SIZE];
1503 XMLUtil::ToStr( v, buf, BUF_SIZE );
1504 SetText( buf );
1505}
1506
1507
1508void XMLElement::SetText( float v )
1509{
1510 char buf[BUF_SIZE];
1511 XMLUtil::ToStr( v, buf, BUF_SIZE );
1512 SetText( buf );
1513}
1514
1515
1516void XMLElement::SetText( double v )
1517{
1518 char buf[BUF_SIZE];
1519 XMLUtil::ToStr( v, buf, BUF_SIZE );
1520 SetText( buf );
1521}
1522
1523
MortenMacFly4ee49f12013-01-14 20:03:14 +01001524XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001525{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001526 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001527 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001528 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001529 return XML_SUCCESS;
1530 }
1531 return XML_CAN_NOT_CONVERT_TEXT;
1532 }
1533 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001534}
1535
1536
MortenMacFly4ee49f12013-01-14 20:03:14 +01001537XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001538{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001539 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001540 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001541 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001542 return XML_SUCCESS;
1543 }
1544 return XML_CAN_NOT_CONVERT_TEXT;
1545 }
1546 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001547}
1548
1549
Lee Thomason51c12712016-06-04 20:18:49 -07001550XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1551{
1552 if (FirstChild() && FirstChild()->ToText()) {
1553 const char* t = FirstChild()->Value();
1554 if (XMLUtil::ToInt64(t, ival)) {
1555 return XML_SUCCESS;
1556 }
1557 return XML_CAN_NOT_CONVERT_TEXT;
1558 }
1559 return XML_NO_TEXT_NODE;
1560}
1561
1562
MortenMacFly4ee49f12013-01-14 20:03:14 +01001563XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001564{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001565 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001566 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001567 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001568 return XML_SUCCESS;
1569 }
1570 return XML_CAN_NOT_CONVERT_TEXT;
1571 }
1572 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001573}
1574
1575
MortenMacFly4ee49f12013-01-14 20:03:14 +01001576XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001577{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001578 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001579 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001580 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001581 return XML_SUCCESS;
1582 }
1583 return XML_CAN_NOT_CONVERT_TEXT;
1584 }
1585 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001586}
1587
1588
MortenMacFly4ee49f12013-01-14 20:03:14 +01001589XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001590{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001591 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001592 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001593 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001594 return XML_SUCCESS;
1595 }
1596 return XML_CAN_NOT_CONVERT_TEXT;
1597 }
1598 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001599}
1600
1601
1602
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001603XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1604{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001605 XMLAttribute* last = 0;
1606 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001607 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001608 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001609 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001610 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1611 break;
1612 }
1613 }
1614 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001615 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001616 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1617 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001618 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001619 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001620 }
1621 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001622 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001623 }
1624 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001625 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001626 }
1627 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001628}
1629
1630
U-Stream\Leeae25a442012-02-17 17:48:16 -08001631void XMLElement::DeleteAttribute( const char* name )
1632{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001633 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001634 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001635 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1636 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001637 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001638 }
1639 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001640 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001641 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001642 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001643 break;
1644 }
1645 prev = a;
1646 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001647}
1648
1649
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001650char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001651{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001652 const char* start = p;
1653 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001654
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001655 // Read the attributes.
1656 while( p ) {
1657 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001658 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001659 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001660 return 0;
1661 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001662
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001663 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001664 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001665 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001666 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1667 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001668 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001669
Lee Thomason624d43f2012-10-12 10:58:48 -07001670 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001671 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001672 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001673 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001674 return 0;
1675 }
1676 // There is a minor bug here: if the attribute in the source xml
1677 // document is duplicated, it will not be detected and the
1678 // attribute will be doubly added. However, tracking the 'prevAttribute'
1679 // avoids re-scanning the attribute list. Preferring performance for
1680 // now, may reconsider in the future.
1681 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001682 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001683 }
1684 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001685 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001686 }
1687 prevAttribute = attrib;
1688 }
1689 // end of the tag
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001690 else if ( *p == '>' ) {
1691 ++p;
1692 break;
1693 }
Dmitry-Meccd267a2015-04-10 15:42:54 +03001694 // end of the tag
1695 else if ( *p == '/' && *(p+1) == '>' ) {
1696 _closingType = CLOSED;
1697 return p+2; // done; sealed element.
1698 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001699 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001700 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001701 return 0;
1702 }
1703 }
1704 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001705}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001706
Dmitry-Mee3225b12014-09-03 11:03:11 +04001707void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1708{
1709 if ( attribute == 0 ) {
1710 return;
1711 }
1712 MemPool* pool = attribute->_memPool;
1713 attribute->~XMLAttribute();
1714 pool->Free( attribute );
1715}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001716
Lee Thomason67d61312012-01-24 16:01:51 -08001717//
1718// <ele></ele>
1719// <ele>foo<b>bar</b></ele>
1720//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001721char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001722{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001723 // Read the element name.
1724 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001725
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001726 // The closing element is the </element> form. It is
1727 // parsed just like a regular element then deleted from
1728 // the DOM.
1729 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001730 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001731 ++p;
1732 }
Lee Thomason67d61312012-01-24 16:01:51 -08001733
Lee Thomason624d43f2012-10-12 10:58:48 -07001734 p = _value.ParseName( p );
1735 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001736 return 0;
1737 }
Lee Thomason67d61312012-01-24 16:01:51 -08001738
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001739 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001740 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001741 return p;
1742 }
Lee Thomason67d61312012-01-24 16:01:51 -08001743
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001744 p = XMLNode::ParseDeep( p, strPair );
1745 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001746}
1747
1748
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001749
1750XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1751{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001752 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001753 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001754 }
1755 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1756 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1757 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1758 }
1759 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001760}
1761
1762
1763bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1764{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001765 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001766 const XMLElement* other = compare->ToElement();
Dmitry-Me886ad972015-07-22 11:00:51 +03001767 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001768
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001769 const XMLAttribute* a=FirstAttribute();
1770 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001771
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001772 while ( a && b ) {
1773 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1774 return false;
1775 }
1776 a = a->Next();
1777 b = b->Next();
1778 }
1779 if ( a || b ) {
1780 // different count
1781 return false;
1782 }
1783 return true;
1784 }
1785 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001786}
1787
1788
Lee Thomason751da522012-02-10 08:50:51 -08001789bool XMLElement::Accept( XMLVisitor* visitor ) const
1790{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001791 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001792 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001793 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1794 if ( !node->Accept( visitor ) ) {
1795 break;
1796 }
1797 }
1798 }
1799 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001800}
Lee Thomason56bdd022012-02-09 18:16:58 -08001801
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001802
Lee Thomason3f57d272012-01-11 15:30:03 -08001803// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001804
1805// Warning: List must match 'enum XMLError'
1806const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1807 "XML_SUCCESS",
1808 "XML_NO_ATTRIBUTE",
1809 "XML_WRONG_ATTRIBUTE_TYPE",
1810 "XML_ERROR_FILE_NOT_FOUND",
1811 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1812 "XML_ERROR_FILE_READ_ERROR",
1813 "XML_ERROR_ELEMENT_MISMATCH",
1814 "XML_ERROR_PARSING_ELEMENT",
1815 "XML_ERROR_PARSING_ATTRIBUTE",
1816 "XML_ERROR_IDENTIFYING_TAG",
1817 "XML_ERROR_PARSING_TEXT",
1818 "XML_ERROR_PARSING_CDATA",
1819 "XML_ERROR_PARSING_COMMENT",
1820 "XML_ERROR_PARSING_DECLARATION",
1821 "XML_ERROR_PARSING_UNKNOWN",
1822 "XML_ERROR_EMPTY_DOCUMENT",
1823 "XML_ERROR_MISMATCHED_ELEMENT",
1824 "XML_ERROR_PARSING",
1825 "XML_CAN_NOT_CONVERT_TEXT",
1826 "XML_NO_TEXT_NODE"
1827};
1828
1829
Lee Thomason624d43f2012-10-12 10:58:48 -07001830XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001831 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001832 _writeBOM( false ),
1833 _processEntities( processEntities ),
Lee Thomason85536252016-06-04 19:10:53 -07001834 _errorID(XML_SUCCESS),
Lee Thomason624d43f2012-10-12 10:58:48 -07001835 _whitespace( whitespace ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001836 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001837{
Dmitry-Me8dd493b2015-07-02 13:59:30 +03001838 // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
1839 _document = this;
U-Lama\Lee560bd472011-12-28 19:42:49 -08001840}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001841
1842
Lee Thomason3f57d272012-01-11 15:30:03 -08001843XMLDocument::~XMLDocument()
1844{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001845 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001846}
1847
1848
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001849void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001850{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001851 DeleteChildren();
1852
Dmitry-Meab37df82014-11-28 12:08:36 +03001853#ifdef DEBUG
1854 const bool hadError = Error();
1855#endif
Lee Thomason85536252016-06-04 19:10:53 -07001856 _errorID = XML_SUCCESS;
Lee Thomason584af572016-09-05 14:14:16 -07001857 _errorStr1.Reset();
1858 _errorStr2.Reset();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001859
Lee Thomason624d43f2012-10-12 10:58:48 -07001860 delete [] _charBuffer;
1861 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001862
1863#if 0
1864 _textPool.Trace( "text" );
1865 _elementPool.Trace( "element" );
1866 _commentPool.Trace( "comment" );
1867 _attributePool.Trace( "attribute" );
1868#endif
1869
1870#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001871 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001872 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1873 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1874 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1875 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1876 }
1877#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001878}
1879
Lee Thomason3f57d272012-01-11 15:30:03 -08001880
Lee Thomason2c85a712012-01-31 08:24:24 -08001881XMLElement* XMLDocument::NewElement( const char* name )
1882{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001883 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001884 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1885 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001886 ele->SetName( name );
1887 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001888}
1889
1890
Lee Thomason1ff38e02012-02-14 18:18:16 -08001891XMLComment* XMLDocument::NewComment( const char* str )
1892{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001893 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001894 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1895 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001896 comment->SetValue( str );
1897 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001898}
1899
1900
1901XMLText* XMLDocument::NewText( const char* str )
1902{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001903 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001904 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1905 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001906 text->SetValue( str );
1907 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001908}
1909
1910
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001911XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1912{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001913 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001914 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1915 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001916 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1917 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001918}
1919
1920
1921XMLUnknown* XMLDocument::NewUnknown( const char* str )
1922{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001923 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001924 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1925 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001926 unk->SetValue( str );
1927 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001928}
1929
Dmitry-Me01578db2014-08-19 10:18:48 +04001930static FILE* callfopen( const char* filepath, const char* mode )
1931{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001932 TIXMLASSERT( filepath );
1933 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001934#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1935 FILE* fp = 0;
1936 errno_t err = fopen_s( &fp, filepath, mode );
1937 if ( err ) {
1938 return 0;
1939 }
1940#else
1941 FILE* fp = fopen( filepath, mode );
1942#endif
1943 return fp;
1944}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001945
1946void XMLDocument::DeleteNode( XMLNode* node ) {
1947 TIXMLASSERT( node );
1948 TIXMLASSERT(node->_document == this );
1949 if (node->_parent) {
1950 node->_parent->DeleteChild( node );
1951 }
1952 else {
1953 // Isn't in the tree.
1954 // Use the parent delete.
1955 // Also, we need to mark it tracked: we 'know'
1956 // it was never used.
1957 node->_memPool->SetTracked();
1958 // Call the static XMLNode version:
1959 XMLNode::DeleteNode(node);
1960 }
1961}
1962
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001963
Lee Thomason2fa81722012-11-09 12:37:46 -08001964XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001965{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001966 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001967 FILE* fp = callfopen( filename, "rb" );
1968 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001969 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001970 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001971 }
1972 LoadFile( fp );
1973 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001974 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001975}
1976
Dmitry-Me901fed52015-09-25 10:29:51 +03001977// This is likely overengineered template art to have a check that unsigned long value incremented
1978// by one still fits into size_t. If size_t type is larger than unsigned long type
1979// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
1980// -Wtype-limits warning. This piece makes the compiler select code with a check when a check
1981// is useful and code with no check when a check is redundant depending on how size_t and unsigned long
1982// types sizes relate to each other.
1983template
1984<bool = (sizeof(unsigned long) >= sizeof(size_t))>
1985struct LongFitsIntoSizeTMinusOne {
1986 static bool Fits( unsigned long value )
1987 {
1988 return value < (size_t)-1;
1989 }
1990};
1991
1992template <>
Manlio Morini0f45b242016-07-11 12:14:59 +02001993struct LongFitsIntoSizeTMinusOne<false> {
1994 static bool Fits( unsigned long )
1995 {
1996 return true;
1997 }
1998};
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001999
Lee Thomason2fa81722012-11-09 12:37:46 -08002000XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002001{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002002 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002003
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002004 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04002005 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01002006 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2007 return _errorID;
2008 }
2009
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002010 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002011 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002012 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04002013 if ( filelength == -1L ) {
2014 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2015 return _errorID;
2016 }
Dmitry-Me96b110d2016-02-09 15:12:40 +03002017 TIXMLASSERT( filelength >= 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002018
Dmitry-Me901fed52015-09-25 10:29:51 +03002019 if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
Dmitry-Me2a8b1f52015-04-30 14:58:57 +03002020 // Cannot handle files which won't fit in buffer together with null terminator
2021 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2022 return _errorID;
2023 }
2024
Dmitry-Me72801b82015-05-07 09:41:39 +03002025 if ( filelength == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06002026 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002027 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002028 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002029
Dmitry-Me72801b82015-05-07 09:41:39 +03002030 const size_t size = filelength;
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002031 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002032 _charBuffer = new char[size+1];
2033 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002034 if ( read != size ) {
2035 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002036 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002037 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002038
Lee Thomason624d43f2012-10-12 10:58:48 -07002039 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002040
Dmitry-Me97476b72015-01-01 16:15:57 +03002041 Parse();
Lee Thomason624d43f2012-10-12 10:58:48 -07002042 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002043}
2044
2045
Lee Thomason2fa81722012-11-09 12:37:46 -08002046XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002047{
Dmitry-Me01578db2014-08-19 10:18:48 +04002048 FILE* fp = callfopen( filename, "w" );
2049 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002050 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002051 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002052 }
2053 SaveFile(fp, compact);
2054 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07002055 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05002056}
2057
2058
Lee Thomason2fa81722012-11-09 12:37:46 -08002059XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05002060{
Ant Mitchell189198f2015-03-24 16:20:36 +00002061 // Clear any error from the last save, otherwise it will get reported
2062 // for *this* call.
Lee Thomason85536252016-06-04 19:10:53 -07002063 SetError(XML_SUCCESS, 0, 0);
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002064 XMLPrinter stream( fp, compact );
2065 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07002066 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002067}
2068
Lee Thomason1ff38e02012-02-14 18:18:16 -08002069
Lee Thomason2fa81722012-11-09 12:37:46 -08002070XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08002071{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02002072 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08002073
Lee Thomason82d32002014-02-21 22:47:18 -08002074 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002075 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002076 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002077 }
2078 if ( len == (size_t)(-1) ) {
2079 len = strlen( p );
2080 }
Dmitry-Me96f38cc2015-08-10 16:45:12 +03002081 TIXMLASSERT( _charBuffer == 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07002082 _charBuffer = new char[ len+1 ];
2083 memcpy( _charBuffer, p, len );
2084 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07002085
Dmitry-Me97476b72015-01-01 16:15:57 +03002086 Parse();
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002087 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07002088 // clean up now essentially dangling memory.
2089 // and the parse fail can put objects in the
2090 // pools that are dead and inaccessible.
2091 DeleteChildren();
2092 _elementPool.Clear();
2093 _attributePool.Clear();
2094 _textPool.Clear();
2095 _commentPool.Clear();
2096 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002097 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08002098}
2099
2100
PKEuS1c5f99e2013-07-06 11:28:39 +02002101void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08002102{
Dmitry-Me67c429e2015-05-08 18:08:18 +03002103 if ( streamer ) {
2104 Accept( streamer );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002105 }
Dmitry-Me67c429e2015-05-08 18:08:18 +03002106 else {
2107 XMLPrinter stdoutStreamer( stdout );
2108 Accept( &stdoutStreamer );
2109 }
Lee Thomason3f57d272012-01-11 15:30:03 -08002110}
2111
2112
Lee Thomason2fa81722012-11-09 12:37:46 -08002113void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08002114{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002115 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07002116 _errorID = error;
Lee Thomason584af572016-09-05 14:14:16 -07002117
2118 _errorStr1.Reset();
2119 _errorStr2.Reset();
2120
2121 if (str1)
2122 _errorStr1.SetStr(str1);
2123 if (str2)
2124 _errorStr2.SetStr(str2);
Lee Thomason67d61312012-01-24 16:01:51 -08002125}
2126
Lee Thomason331596e2014-09-11 14:56:43 -07002127const char* XMLDocument::ErrorName() const
2128{
Dmitry-Me66d2a842014-11-08 15:24:52 +03002129 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002130 const char* errorName = _errorNames[_errorID];
2131 TIXMLASSERT( errorName && errorName[0] );
2132 return errorName;
Lee Thomason331596e2014-09-11 14:56:43 -07002133}
Lee Thomason5cae8972012-01-24 18:03:07 -08002134
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002135void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002136{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03002137 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002138 static const int LEN = 20;
2139 char buf1[LEN] = { 0 };
2140 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002141
Lee Thomason584af572016-09-05 14:14:16 -07002142 if ( !_errorStr1.Empty() ) {
2143 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002144 }
Lee Thomason584af572016-09-05 14:14:16 -07002145 if ( !_errorStr2.Empty() ) {
2146 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2.GetStr() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002147 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002148
Dmitry-Me2ad43202015-04-16 12:18:58 +03002149 // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2150 // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2151 TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
Lee Thomason331596e2014-09-11 14:56:43 -07002152 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
Dmitry-Me400f1192015-04-07 11:51:21 +03002153 static_cast<int>( _errorID ), ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002154 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002155}
2156
Dmitry-Me97476b72015-01-01 16:15:57 +03002157void XMLDocument::Parse()
2158{
2159 TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2160 TIXMLASSERT( _charBuffer );
Lee Thomason3cebdc42015-01-05 17:16:28 -08002161 char* p = _charBuffer;
Dmitry-Me97476b72015-01-01 16:15:57 +03002162 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mee28be752015-01-09 14:59:30 +03002163 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
Dmitry-Me97476b72015-01-01 16:15:57 +03002164 if ( !*p ) {
2165 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2166 return;
2167 }
Lee Thomason3cebdc42015-01-05 17:16:28 -08002168 ParseDeep(p, 0 );
Dmitry-Me97476b72015-01-01 16:15:57 +03002169}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002170
PKEuS1bfb9542013-08-04 13:51:17 +02002171XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07002172 _elementJustOpened( false ),
2173 _firstElement( true ),
2174 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02002175 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07002176 _textDepth( -1 ),
2177 _processEntities( true ),
2178 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08002179{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002180 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002181 _entityFlag[i] = false;
2182 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002183 }
2184 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03002185 const char entityValue = entities[i].value;
Kevin Wojniak318252a2016-10-07 10:37:02 -07002186 // cast to explicit signed because char may be unsigned (on PowerPC)
2187 TIXMLASSERT( 0 <= static_cast<signed char>(entityValue) && entityValue < ENTITY_RANGE );
Dmitry-Me8b67d742014-12-22 11:35:12 +03002188 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002189 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03002190 _restrictedEntityFlag[(unsigned char)'&'] = true;
2191 _restrictedEntityFlag[(unsigned char)'<'] = true;
2192 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07002193 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08002194}
2195
2196
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002197void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08002198{
2199 va_list va;
2200 va_start( va, format );
2201
Lee Thomason624d43f2012-10-12 10:58:48 -07002202 if ( _fp ) {
2203 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002204 }
2205 else {
Dmitry-Me1d32e582015-07-27 17:11:51 +03002206 const int len = TIXML_VSCPRINTF( format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002207 // Close out and re-start the va-args
2208 va_end( va );
Dmitry-Me1d32e582015-07-27 17:11:51 +03002209 TIXMLASSERT( len >= 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002210 va_start( va, format );
Dmitry-Me30bdc972015-01-14 08:32:23 +03002211 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
Lee Thomasona0744c82014-03-16 10:32:27 -07002212 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
pffang1527cf42015-06-09 13:57:11 +08002213 TIXML_VSNPRINTF( p, len+1, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002214 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002215 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002216}
2217
2218
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002219void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002220{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002221 for( int i=0; i<depth; ++i ) {
2222 Print( " " );
2223 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002224}
2225
2226
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002227void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002228{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002229 // Look for runs of bytes between entities to print.
2230 const char* q = p;
Lee Thomason857b8682012-01-25 17:50:25 -08002231
Lee Thomason624d43f2012-10-12 10:58:48 -07002232 if ( _processEntities ) {
Dmitry-Me6acc9a52015-01-15 13:27:47 +03002233 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002234 while ( *q ) {
Dmitry-Me69d521d2015-04-20 18:05:53 +03002235 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002236 // Remember, char is sometimes signed. (How many times has that bitten me?)
2237 if ( *q > 0 && *q < ENTITY_RANGE ) {
2238 // Check for entities. If one is found, flush
2239 // the stream up until the entity, write the
2240 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002241 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002242 while ( p < q ) {
Dmitry-Med95172b2015-03-30 08:11:18 +03002243 const size_t delta = q - p;
2244 // %.*s accepts type int as "precision"
Ross Bencinae7fa0e12015-07-22 16:58:05 +10002245 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
Dmitry-Med95172b2015-03-30 08:11:18 +03002246 Print( "%.*s", toPrint, p );
2247 p += toPrint;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002248 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002249 bool entityPatternPrinted = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002250 for( int i=0; i<NUM_ENTITIES; ++i ) {
2251 if ( entities[i].value == *q ) {
2252 Print( "&%s;", entities[i].pattern );
Dmitry-Me39c399a2015-05-28 15:32:27 +03002253 entityPatternPrinted = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002254 break;
2255 }
2256 }
Dmitry-Me39c399a2015-05-28 15:32:27 +03002257 if ( !entityPatternPrinted ) {
2258 // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2259 TIXMLASSERT( false );
2260 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002261 ++p;
2262 }
2263 }
2264 ++q;
Dmitry-Me69d521d2015-04-20 18:05:53 +03002265 TIXMLASSERT( p <= q );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002266 }
2267 }
2268 // Flush the remaining string. This will be the entire
2269 // string if an entity wasn't found.
Dmitry-Me69d521d2015-04-20 18:05:53 +03002270 TIXMLASSERT( p <= q );
2271 if ( !_processEntities || ( p < q ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002272 Print( "%s", p );
2273 }
Lee Thomason857b8682012-01-25 17:50:25 -08002274}
2275
U-Stream\Leeae25a442012-02-17 17:48:16 -08002276
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002277void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002278{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002279 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002280 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 -07002281 Print( "%s", bom );
2282 }
2283 if ( writeDec ) {
2284 PushDeclaration( "xml version=\"1.0\"" );
2285 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002286}
2287
2288
Uli Kusterer593a33d2014-02-01 12:48:51 +01002289void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002290{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002291 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002292 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002293
Uli Kusterer593a33d2014-02-01 12:48:51 +01002294 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002295 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002296 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002297 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002298 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002299 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002300
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002301 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002302 _elementJustOpened = true;
2303 _firstElement = false;
2304 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002305}
2306
2307
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002308void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002309{
Lee Thomason624d43f2012-10-12 10:58:48 -07002310 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002311 Print( " %s=\"", name );
2312 PrintString( value, false );
2313 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002314}
2315
2316
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002317void XMLPrinter::PushAttribute( const char* name, int v )
2318{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002319 char buf[BUF_SIZE];
2320 XMLUtil::ToStr( v, buf, BUF_SIZE );
2321 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002322}
2323
2324
2325void XMLPrinter::PushAttribute( const char* name, unsigned v )
2326{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002327 char buf[BUF_SIZE];
2328 XMLUtil::ToStr( v, buf, BUF_SIZE );
2329 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002330}
2331
2332
Lee Thomason51c12712016-06-04 20:18:49 -07002333void XMLPrinter::PushAttribute(const char* name, int64_t v)
2334{
2335 char buf[BUF_SIZE];
2336 XMLUtil::ToStr(v, buf, BUF_SIZE);
2337 PushAttribute(name, buf);
2338}
2339
2340
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002341void XMLPrinter::PushAttribute( const char* name, bool v )
2342{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002343 char buf[BUF_SIZE];
2344 XMLUtil::ToStr( v, buf, BUF_SIZE );
2345 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002346}
2347
2348
2349void XMLPrinter::PushAttribute( const char* name, double v )
2350{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002351 char buf[BUF_SIZE];
2352 XMLUtil::ToStr( v, buf, BUF_SIZE );
2353 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002354}
2355
2356
Uli Kustererca412e82014-02-01 13:35:05 +01002357void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002358{
Lee Thomason624d43f2012-10-12 10:58:48 -07002359 --_depth;
2360 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002361
Lee Thomason624d43f2012-10-12 10:58:48 -07002362 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002363 Print( "/>" );
2364 }
2365 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002366 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002367 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002368 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002369 }
2370 Print( "</%s>", name );
2371 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002372
Lee Thomason624d43f2012-10-12 10:58:48 -07002373 if ( _textDepth == _depth ) {
2374 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002375 }
Uli Kustererca412e82014-02-01 13:35:05 +01002376 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002377 Print( "\n" );
2378 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002379 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002380}
2381
2382
Dmitry-Mea092bc12014-12-23 17:57:05 +03002383void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002384{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002385 if ( !_elementJustOpened ) {
2386 return;
2387 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002388 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002389 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002390}
2391
2392
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002393void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002394{
Lee Thomason624d43f2012-10-12 10:58:48 -07002395 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002396
Dmitry-Mea092bc12014-12-23 17:57:05 +03002397 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002398 if ( cdata ) {
Dmitry-Me6a79c172015-03-31 12:18:17 +03002399 Print( "<![CDATA[%s]]>", text );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002400 }
2401 else {
2402 PrintString( text, true );
2403 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002404}
2405
Stefan Asbecke1a82c12016-08-04 09:12:45 +02002406void XMLPrinter::PushText( int64_t value )
2407{
2408 char buf[BUF_SIZE];
2409 XMLUtil::ToStr( value, buf, BUF_SIZE );
2410 PushText( buf, false );
2411}
2412
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002413void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002414{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002415 char buf[BUF_SIZE];
2416 XMLUtil::ToStr( value, buf, BUF_SIZE );
2417 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002418}
2419
2420
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002421void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002422{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002423 char buf[BUF_SIZE];
2424 XMLUtil::ToStr( value, buf, BUF_SIZE );
2425 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002426}
2427
2428
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002429void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002430{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002431 char buf[BUF_SIZE];
2432 XMLUtil::ToStr( value, buf, BUF_SIZE );
2433 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002434}
2435
2436
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002437void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002438{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002439 char buf[BUF_SIZE];
2440 XMLUtil::ToStr( value, buf, BUF_SIZE );
2441 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002442}
2443
2444
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002445void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002446{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002447 char buf[BUF_SIZE];
2448 XMLUtil::ToStr( value, buf, BUF_SIZE );
2449 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002450}
2451
Lee Thomason5cae8972012-01-24 18:03:07 -08002452
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002453void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002454{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002455 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002456 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002457 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002458 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002459 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002460 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002461 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002462}
Lee Thomason751da522012-02-10 08:50:51 -08002463
2464
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002465void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002466{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002467 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002468 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002469 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002470 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002471 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002472 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002473 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002474}
2475
2476
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002477void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002478{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002479 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002480 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002481 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002482 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002483 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002484 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002485 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002486}
2487
2488
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002489bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002490{
Lee Thomason624d43f2012-10-12 10:58:48 -07002491 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002492 if ( doc.HasBOM() ) {
2493 PushHeader( true, false );
2494 }
2495 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002496}
2497
2498
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002499bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002500{
Dmitry-Mee76b8512015-04-08 13:41:40 +03002501 const XMLElement* parentElem = 0;
2502 if ( element.Parent() ) {
2503 parentElem = element.Parent()->ToElement();
Ant Mitchell7e744772015-03-24 14:33:28 +00002504 }
Dmitry-Mee76b8512015-04-08 13:41:40 +03002505 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002506 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002507 while ( attribute ) {
2508 PushAttribute( attribute->Name(), attribute->Value() );
2509 attribute = attribute->Next();
2510 }
2511 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002512}
2513
2514
Uli Kustererca412e82014-02-01 13:35:05 +01002515bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002516{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002517 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002518 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002519}
2520
2521
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002522bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002523{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002524 PushText( text.Value(), text.CData() );
2525 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002526}
2527
2528
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002529bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002530{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002531 PushComment( comment.Value() );
2532 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002533}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002534
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002535bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002536{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002537 PushDeclaration( declaration.Value() );
2538 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002539}
2540
2541
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002542bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002543{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002544 PushUnknown( unknown.Value() );
2545 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002546}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002547
Lee Thomason685b8952012-11-12 13:00:06 -08002548} // namespace tinyxml2
2549