blob: 42659f21bb5fc267c7b39d74759d93d3fafb813b [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.
Anton Indrawanf59e2d62014-11-18 20:50:42 +010027#if defined(ANDROID_NDK) || defined(__QNXNTO__)
Lee Thomasona9cf3f92012-10-11 16:56:51 -070028# include <stddef.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070029#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070030# include <cstddef>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070031#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080032
Lee Thomasone4422302012-01-20 17:59:50 -080033static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -080034static const char LF = LINE_FEED;
35static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
36static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -080037static const char SINGLE_QUOTE = '\'';
38static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -080039
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080040// Bunch of unicode info at:
41// http://www.unicode.org/faq/utf_bom.html
42// ef bb bf (Microsoft "lead bytes") - designates UTF-8
43
44static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
45static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
46static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080047
Kevin Wojniak04c22d22012-11-08 11:02:22 -080048namespace tinyxml2
49{
50
Lee Thomason8ee79892012-01-25 17:44:30 -080051struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -070052 const char* pattern;
53 int length;
54 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -080055};
56
57static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070058static const Entity entities[NUM_ENTITIES] = {
59 { "quot", 4, DOUBLE_QUOTE },
60 { "amp", 3, '&' },
61 { "apos", 4, SINGLE_QUOTE },
62 { "lt", 2, '<' },
63 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -080064};
65
Lee Thomasonfde6a752012-01-14 18:08:12 -080066
Lee Thomason1a1d4a72012-02-15 09:09:25 -080067StrPair::~StrPair()
68{
Lee Thomasona9cf3f92012-10-11 16:56:51 -070069 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -080070}
71
72
Lee Thomason29658802014-11-27 22:31:11 -080073void StrPair::TransferTo( StrPair* other )
Dmitry-Me08b40dd2014-11-10 11:17:21 +030074{
Lee Thomason29658802014-11-27 22:31:11 -080075 if ( this == other ) {
Dmitry-Me08b40dd2014-11-10 11:17:21 +030076 return;
77 }
78 // This in effect implements the assignment operator by "moving"
79 // ownership (as in auto_ptr).
80
Lee Thomason29658802014-11-27 22:31:11 -080081 TIXMLASSERT( other->_flags == 0 );
82 TIXMLASSERT( other->_start == 0 );
83 TIXMLASSERT( other->_end == 0 );
Dmitry-Me08b40dd2014-11-10 11:17:21 +030084
Lee Thomason29658802014-11-27 22:31:11 -080085 other->Reset();
Dmitry-Me08b40dd2014-11-10 11:17:21 +030086
Lee Thomason29658802014-11-27 22:31:11 -080087 other->_flags = _flags;
88 other->_start = _start;
89 other->_end = _end;
Dmitry-Me08b40dd2014-11-10 11:17:21 +030090
91 _flags = 0;
92 _start = 0;
93 _end = 0;
94}
95
Lee Thomason1a1d4a72012-02-15 09:09:25 -080096void StrPair::Reset()
97{
Lee Thomason120b3a62012-10-12 10:06:59 -070098 if ( _flags & NEEDS_DELETE ) {
99 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700100 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700101 _flags = 0;
102 _start = 0;
103 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800104}
105
106
107void StrPair::SetStr( const char* str, int flags )
108{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700109 Reset();
110 size_t len = strlen( str );
Lee Thomason120b3a62012-10-12 10:06:59 -0700111 _start = new char[ len+1 ];
112 memcpy( _start, str, len+1 );
113 _end = _start + len;
114 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800115}
116
117
118char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
119{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700120 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800121
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400122 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700123 char endChar = *endTag;
124 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800125
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700126 // Inner loop of text parsing.
127 while ( *p ) {
128 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
129 Set( start, p, strFlags );
130 return p + length;
131 }
132 ++p;
133 }
134 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800135}
136
137
138char* StrPair::ParseName( char* p )
139{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400140 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700141 return 0;
142 }
JayXonee525db2014-12-24 04:01:42 -0500143 if ( !XMLUtil::IsNameStartChar( *p ) ) {
144 return 0;
145 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800146
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400147 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500148 ++p;
149 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700150 ++p;
151 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800152
JayXonee525db2014-12-24 04:01:42 -0500153 Set( start, p, 0 );
154 return p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800155}
156
157
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700158void StrPair::CollapseWhitespace()
159{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400160 // Adjusting _start would cause undefined behavior on delete[]
161 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700162 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700163 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700164
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300165 if ( *_start ) {
Lee Thomason120b3a62012-10-12 10:06:59 -0700166 char* p = _start; // the read pointer
167 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700168
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700169 while( *p ) {
170 if ( XMLUtil::IsWhiteSpace( *p )) {
171 p = XMLUtil::SkipWhiteSpace( p );
172 if ( *p == 0 ) {
173 break; // don't write to q; this trims the trailing space.
174 }
175 *q = ' ';
176 ++q;
177 }
178 *q = *p;
179 ++q;
180 ++p;
181 }
182 *q = 0;
183 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700184}
185
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800186
Lee Thomasone4422302012-01-20 17:59:50 -0800187const char* StrPair::GetStr()
188{
Lee Thomason120b3a62012-10-12 10:06:59 -0700189 if ( _flags & NEEDS_FLUSH ) {
190 *_end = 0;
191 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800192
Lee Thomason120b3a62012-10-12 10:06:59 -0700193 if ( _flags ) {
194 char* p = _start; // the read pointer
195 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800196
Lee Thomason120b3a62012-10-12 10:06:59 -0700197 while( p < _end ) {
198 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700199 // CR-LF pair becomes LF
200 // CR alone becomes LF
201 // LF-CR becomes LF
202 if ( *(p+1) == LF ) {
203 p += 2;
204 }
205 else {
206 ++p;
207 }
208 *q++ = LF;
209 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700210 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700211 if ( *(p+1) == CR ) {
212 p += 2;
213 }
214 else {
215 ++p;
216 }
217 *q++ = LF;
218 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700219 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700220 // Entities handled by tinyXML2:
221 // - special entities in the entity table [in/out]
222 // - numeric character reference [in]
223 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800224
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700225 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400226 const int buflen = 10;
227 char buf[buflen] = { 0 };
228 int len = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700229 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
Dmitry-Me63f3de12014-08-21 12:33:19 +0400230 TIXMLASSERT( 0 <= len && len <= buflen );
231 TIXMLASSERT( q + len <= p );
232 memcpy( q, buf, len );
233 q += len;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700234 }
235 else {
236 int i=0;
237 for(; i<NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400238 const Entity& entity = entities[i];
239 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
240 && *( p + entity.length + 1 ) == ';' ) {
241 // Found an entity - convert.
242 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700243 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400244 p += entity.length + 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700245 break;
246 }
247 }
248 if ( i == NUM_ENTITIES ) {
249 // fixme: treat as error?
250 ++p;
251 ++q;
252 }
253 }
254 }
255 else {
256 *q = *p;
257 ++p;
258 ++q;
259 }
260 }
261 *q = 0;
262 }
263 // The loop below has plenty going on, and this
264 // is a less useful mode. Break it out.
Lee Thomason120b3a62012-10-12 10:06:59 -0700265 if ( _flags & COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700266 CollapseWhitespace();
267 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700268 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700269 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700270 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800271}
272
Lee Thomason2c85a712012-01-31 08:24:24 -0800273
Lee Thomasone4422302012-01-20 17:59:50 -0800274
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800275
Lee Thomason56bdd022012-02-09 18:16:58 -0800276// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800277
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800278const char* XMLUtil::ReadBOM( const char* p, bool* bom )
279{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300280 TIXMLASSERT( p );
281 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700282 *bom = false;
283 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
284 // Check for BOM:
285 if ( *(pu+0) == TIXML_UTF_LEAD_0
286 && *(pu+1) == TIXML_UTF_LEAD_1
287 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
288 *bom = true;
289 p += 3;
290 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300291 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700292 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800293}
294
295
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800296void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
297{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700298 const unsigned long BYTE_MASK = 0xBF;
299 const unsigned long BYTE_MARK = 0x80;
300 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800301
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700302 if (input < 0x80) {
303 *length = 1;
304 }
305 else if ( input < 0x800 ) {
306 *length = 2;
307 }
308 else if ( input < 0x10000 ) {
309 *length = 3;
310 }
311 else if ( input < 0x200000 ) {
312 *length = 4;
313 }
314 else {
315 *length = 0; // This code won't covert this correctly anyway.
316 return;
317 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800318
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700319 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800320
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700321 // Scary scary fall throughs.
322 switch (*length) {
323 case 4:
324 --output;
325 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
326 input >>= 6;
327 case 3:
328 --output;
329 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
330 input >>= 6;
331 case 2:
332 --output;
333 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
334 input >>= 6;
335 case 1:
336 --output;
337 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100338 default:
339 break;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700340 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800341}
342
343
344const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
345{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700346 // Presume an entity, and pull it out.
347 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800348
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700349 if ( *(p+1) == '#' && *(p+2) ) {
350 unsigned long ucs = 0;
351 ptrdiff_t delta = 0;
352 unsigned mult = 1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800353
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700354 if ( *(p+2) == 'x' ) {
355 // Hexadecimal.
356 if ( !*(p+3) ) {
357 return 0;
358 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800359
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700360 const char* q = p+3;
361 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800362
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700363 if ( !q || !*q ) {
364 return 0;
365 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800366
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700367 delta = q-p;
368 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800369
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700370 while ( *q != 'x' ) {
371 if ( *q >= '0' && *q <= '9' ) {
372 ucs += mult * (*q - '0');
373 }
374 else if ( *q >= 'a' && *q <= 'f' ) {
375 ucs += mult * (*q - 'a' + 10);
376 }
377 else if ( *q >= 'A' && *q <= 'F' ) {
378 ucs += mult * (*q - 'A' + 10 );
379 }
380 else {
381 return 0;
382 }
383 mult *= 16;
384 --q;
385 }
386 }
387 else {
388 // Decimal.
389 if ( !*(p+2) ) {
390 return 0;
391 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800392
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700393 const char* q = p+2;
394 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800395
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700396 if ( !q || !*q ) {
397 return 0;
398 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800399
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700400 delta = q-p;
401 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800402
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700403 while ( *q != '#' ) {
404 if ( *q >= '0' && *q <= '9' ) {
405 ucs += mult * (*q - '0');
406 }
407 else {
408 return 0;
409 }
410 mult *= 10;
411 --q;
412 }
413 }
414 // convert the UCS to UTF-8
415 ConvertUTF32ToUTF8( ucs, value, length );
416 return p + delta + 1;
417 }
418 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800419}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800420
421
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700422void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700423{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700424 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700425}
426
427
428void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
429{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700430 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700431}
432
433
434void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
435{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700436 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700437}
438
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800439/*
440 ToStr() of a number is a very tricky topic.
441 https://github.com/leethomason/tinyxml2/issues/106
442*/
Lee Thomason21be8822012-07-15 17:27:22 -0700443void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
444{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800445 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700446}
447
448
449void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
450{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800451 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700452}
453
454
455bool XMLUtil::ToInt( const char* str, int* value )
456{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700457 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
458 return true;
459 }
460 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700461}
462
463bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
464{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700465 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
466 return true;
467 }
468 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700469}
470
471bool XMLUtil::ToBool( const char* str, bool* value )
472{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700473 int ival = 0;
474 if ( ToInt( str, &ival )) {
475 *value = (ival==0) ? false : true;
476 return true;
477 }
478 if ( StringEqual( str, "true" ) ) {
479 *value = true;
480 return true;
481 }
482 else if ( StringEqual( str, "false" ) ) {
483 *value = false;
484 return true;
485 }
486 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700487}
488
489
490bool XMLUtil::ToFloat( const char* str, float* value )
491{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700492 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
493 return true;
494 }
495 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700496}
497
498bool XMLUtil::ToDouble( const char* str, double* value )
499{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700500 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
501 return true;
502 }
503 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700504}
505
506
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700507char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800508{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400509 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700510 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300511 if( !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700512 return p;
513 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800514
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700515 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800516 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700517 static const char* xmlHeader = { "<?" };
518 static const char* commentHeader = { "<!--" };
519 static const char* dtdHeader = { "<!" };
520 static const char* cdataHeader = { "<![CDATA[" };
521 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800522
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700523 static const int xmlHeaderLen = 2;
524 static const int commentHeaderLen = 4;
525 static const int dtdHeaderLen = 2;
526 static const int cdataHeaderLen = 9;
527 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800528
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700529 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
530 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400531 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700532 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300533 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700534 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
535 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700536 p += xmlHeaderLen;
537 }
538 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300539 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700540 returnNode = new (_commentPool.Alloc()) XMLComment( this );
541 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700542 p += commentHeaderLen;
543 }
544 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300545 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700546 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700547 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700548 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700549 p += cdataHeaderLen;
550 text->SetCData( true );
551 }
552 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300553 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700554 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
555 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700556 p += dtdHeaderLen;
557 }
558 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300559 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700560 returnNode = new (_elementPool.Alloc()) XMLElement( this );
561 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700562 p += elementHeaderLen;
563 }
564 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300565 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700566 returnNode = new (_textPool.Alloc()) XMLText( this );
567 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700568 p = start; // Back it up, all the text counts.
569 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800570
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700571 *node = returnNode;
572 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800573}
574
575
Lee Thomason751da522012-02-10 08:50:51 -0800576bool XMLDocument::Accept( XMLVisitor* visitor ) const
577{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700578 if ( visitor->VisitEnter( *this ) ) {
579 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
580 if ( !node->Accept( visitor ) ) {
581 break;
582 }
583 }
584 }
585 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800586}
Lee Thomason56bdd022012-02-09 18:16:58 -0800587
588
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800589// --------- XMLNode ----------- //
590
591XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700592 _document( doc ),
593 _parent( 0 ),
594 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200595 _prev( 0 ), _next( 0 ),
596 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800597{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800598}
599
600
601XMLNode::~XMLNode()
602{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700603 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700604 if ( _parent ) {
605 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700606 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800607}
608
Michael Daumling21626882013-10-22 17:03:37 +0200609const char* XMLNode::Value() const
610{
611 return _value.GetStr();
612}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800613
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800614void XMLNode::SetValue( const char* str, bool staticMem )
615{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700616 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700617 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700618 }
619 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700620 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700621 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800622}
623
624
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800625void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800626{
Lee Thomason624d43f2012-10-12 10:58:48 -0700627 while( _firstChild ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300628 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700629 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700630 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700631
Dmitry-Mee3225b12014-09-03 11:03:11 +0400632 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700633 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700634 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800635}
636
637
638void XMLNode::Unlink( XMLNode* child )
639{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300640 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300641 TIXMLASSERT( child->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700642 if ( child == _firstChild ) {
643 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700644 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700645 if ( child == _lastChild ) {
646 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700647 }
Lee Thomasond923c672012-01-23 08:44:25 -0800648
Lee Thomason624d43f2012-10-12 10:58:48 -0700649 if ( child->_prev ) {
650 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700651 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700652 if ( child->_next ) {
653 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700654 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700655 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800656}
657
658
U-Stream\Leeae25a442012-02-17 17:48:16 -0800659void XMLNode::DeleteChild( XMLNode* node )
660{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300661 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300662 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700663 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400664 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800665}
666
667
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800668XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
669{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300670 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300671 if ( addThis->_document != _document ) {
672 TIXMLASSERT( false );
673 return 0;
674 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700675
Michael Daumlinged523282013-10-23 07:47:29 +0200676 if (addThis->_parent)
677 addThis->_parent->Unlink( addThis );
678 else
679 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700680
Lee Thomason624d43f2012-10-12 10:58:48 -0700681 if ( _lastChild ) {
682 TIXMLASSERT( _firstChild );
683 TIXMLASSERT( _lastChild->_next == 0 );
684 _lastChild->_next = addThis;
685 addThis->_prev = _lastChild;
686 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800687
Lee Thomason624d43f2012-10-12 10:58:48 -0700688 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700689 }
690 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700691 TIXMLASSERT( _firstChild == 0 );
692 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800693
Lee Thomason624d43f2012-10-12 10:58:48 -0700694 addThis->_prev = 0;
695 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700696 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700697 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700698 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800699}
700
701
Lee Thomason1ff38e02012-02-14 18:18:16 -0800702XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
703{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300704 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300705 if ( addThis->_document != _document ) {
706 TIXMLASSERT( false );
707 return 0;
708 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700709
Michael Daumlinged523282013-10-23 07:47:29 +0200710 if (addThis->_parent)
711 addThis->_parent->Unlink( addThis );
712 else
713 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700714
Lee Thomason624d43f2012-10-12 10:58:48 -0700715 if ( _firstChild ) {
716 TIXMLASSERT( _lastChild );
717 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800718
Lee Thomason624d43f2012-10-12 10:58:48 -0700719 _firstChild->_prev = addThis;
720 addThis->_next = _firstChild;
721 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800722
Lee Thomason624d43f2012-10-12 10:58:48 -0700723 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700724 }
725 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700726 TIXMLASSERT( _lastChild == 0 );
727 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800728
Lee Thomason624d43f2012-10-12 10:58:48 -0700729 addThis->_prev = 0;
730 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700731 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700732 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400733 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800734}
735
736
737XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
738{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300739 TIXMLASSERT( addThis );
740 if ( addThis->_document != _document ) {
741 TIXMLASSERT( false );
742 return 0;
743 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700744
Dmitry-Meabb2d042014-12-09 12:59:31 +0300745 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700746
Lee Thomason624d43f2012-10-12 10:58:48 -0700747 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300748 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700749 return 0;
750 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800751
Lee Thomason624d43f2012-10-12 10:58:48 -0700752 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700753 // The last node or the only node.
754 return InsertEndChild( addThis );
755 }
Michael Daumlinged523282013-10-23 07:47:29 +0200756 if (addThis->_parent)
757 addThis->_parent->Unlink( addThis );
758 else
759 addThis->_memPool->SetTracked();
Lee Thomason624d43f2012-10-12 10:58:48 -0700760 addThis->_prev = afterThis;
761 addThis->_next = afterThis->_next;
762 afterThis->_next->_prev = addThis;
763 afterThis->_next = addThis;
764 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700765 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800766}
767
768
769
770
Lee Thomason56bdd022012-02-09 18:16:58 -0800771const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800772{
Lee Thomason624d43f2012-10-12 10:58:48 -0700773 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700774 XMLElement* element = node->ToElement();
775 if ( element ) {
776 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
777 return element;
778 }
779 }
780 }
781 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800782}
783
784
Lee Thomason56bdd022012-02-09 18:16:58 -0800785const XMLElement* XMLNode::LastChildElement( const char* value ) const
786{
Lee Thomason624d43f2012-10-12 10:58:48 -0700787 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700788 XMLElement* element = node->ToElement();
789 if ( element ) {
790 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
791 return element;
792 }
793 }
794 }
795 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800796}
797
798
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800799const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
800{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400801 for( XMLNode* node=this->_next; node; node = node->_next ) {
802 const XMLElement* element = node->ToElement();
803 if ( element
804 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
805 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700806 }
807 }
808 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800809}
810
811
812const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
813{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400814 for( XMLNode* node=_prev; node; node = node->_prev ) {
815 const XMLElement* element = node->ToElement();
816 if ( element
817 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
818 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700819 }
820 }
821 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800822}
823
824
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800825char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800826{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700827 // This is a recursive method, but thinking about it "at the current level"
828 // it is a pretty simple flat list:
829 // <foo/>
830 // <!-- comment -->
831 //
832 // With a special case:
833 // <foo>
834 // </foo>
835 // <!-- comment -->
836 //
837 // Where the closing element (/foo) *must* be the next thing after the opening
838 // element, and the names must match. BUT the tricky bit is that the closing
839 // element will be read by the child.
840 //
841 // 'endTag' is the end tag for this node, it is returned by a call to a child.
842 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800843
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700844 while( p && *p ) {
845 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800846
Lee Thomason624d43f2012-10-12 10:58:48 -0700847 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700848 if ( p == 0 || node == 0 ) {
849 break;
850 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800851
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700852 StrPair endTag;
853 p = node->ParseDeep( p, &endTag );
854 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400855 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700856 if ( !_document->Error() ) {
857 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700858 }
859 break;
860 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800861
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400862 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700863 // We read the end tag. Return it to the parent.
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400864 if ( ele && ele->ClosingType() == XMLElement::CLOSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700865 if ( parentEnd ) {
Lee Thomason29658802014-11-27 22:31:11 -0800866 ele->_value.TransferTo( parentEnd );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700867 }
Lee Thomason5b0a6772012-11-19 13:54:42 -0800868 node->_memPool->SetTracked(); // created and then immediately deleted.
Dmitry-Mee3225b12014-09-03 11:03:11 +0400869 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700870 return p;
871 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800872
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700873 // Handle an end tag returned to this level.
874 // And handle a bunch of annoying errors.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700875 if ( ele ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400876 bool mismatch = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700877 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400878 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700879 }
880 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400881 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700882 }
883 else if ( !endTag.Empty() ) {
884 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400885 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700886 }
887 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400888 if ( mismatch ) {
889 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -0500890 DeleteNode( node );
891 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400892 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700893 }
JayXondbfdd8f2014-12-12 20:07:14 -0500894 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700895 }
896 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800897}
898
Dmitry-Mee3225b12014-09-03 11:03:11 +0400899void XMLNode::DeleteNode( XMLNode* node )
900{
901 if ( node == 0 ) {
902 return;
903 }
904 MemPool* pool = node->_memPool;
905 node->~XMLNode();
906 pool->Free( node );
907}
908
Lee Thomason5492a1c2012-01-23 15:32:10 -0800909// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800910char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800911{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700912 const char* start = p;
913 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700914 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700915 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700916 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700917 }
918 return p;
919 }
920 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700921 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
922 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700923 flags |= StrPair::COLLAPSE_WHITESPACE;
924 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700925
Lee Thomason624d43f2012-10-12 10:58:48 -0700926 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700927 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700928 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700929 }
930 if ( p && *p ) {
931 return p-1;
932 }
933 }
934 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800935}
936
937
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800938XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
939{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700940 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700941 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700942 }
943 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
944 text->SetCData( this->CData() );
945 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800946}
947
948
949bool XMLText::ShallowEqual( const XMLNode* compare ) const
950{
Dmitry-Me6d202ff2014-09-26 14:21:00 +0400951 const XMLText* text = compare->ToText();
952 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800953}
954
955
Lee Thomason56bdd022012-02-09 18:16:58 -0800956bool XMLText::Accept( XMLVisitor* visitor ) const
957{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300958 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700959 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800960}
961
962
Lee Thomason3f57d272012-01-11 15:30:03 -0800963// --------- XMLComment ---------- //
964
Lee Thomasone4422302012-01-20 17:59:50 -0800965XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800966{
967}
968
969
Lee Thomasonce0763e2012-01-11 15:43:54 -0800970XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800971{
Lee Thomason3f57d272012-01-11 15:30:03 -0800972}
973
974
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800975char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800976{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700977 // Comment parses as text.
978 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700979 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700980 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700981 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700982 }
983 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800984}
985
986
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800987XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
988{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700989 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700990 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700991 }
992 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
993 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800994}
995
996
997bool XMLComment::ShallowEqual( const XMLNode* compare ) const
998{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300999 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001000 const XMLComment* comment = compare->ToComment();
1001 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001002}
1003
1004
Lee Thomason751da522012-02-10 08:50:51 -08001005bool XMLComment::Accept( XMLVisitor* visitor ) const
1006{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001007 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001008 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001009}
Lee Thomason56bdd022012-02-09 18:16:58 -08001010
1011
Lee Thomason50f97b22012-02-11 16:33:40 -08001012// --------- XMLDeclaration ---------- //
1013
1014XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1015{
1016}
1017
1018
1019XMLDeclaration::~XMLDeclaration()
1020{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001021 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001022}
1023
1024
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001025char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001026{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001027 // Declaration parses as text.
1028 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001029 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001030 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001031 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001032 }
1033 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001034}
1035
1036
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001037XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1038{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001039 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001040 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001041 }
1042 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1043 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001044}
1045
1046
1047bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1048{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001049 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001050 const XMLDeclaration* declaration = compare->ToDeclaration();
1051 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001052}
1053
1054
1055
Lee Thomason50f97b22012-02-11 16:33:40 -08001056bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1057{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001058 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001059 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001060}
1061
1062// --------- XMLUnknown ---------- //
1063
1064XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1065{
1066}
1067
1068
1069XMLUnknown::~XMLUnknown()
1070{
1071}
1072
1073
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001074char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001075{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001076 // Unknown parses as text.
1077 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001078
Lee Thomason624d43f2012-10-12 10:58:48 -07001079 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001080 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001081 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001082 }
1083 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001084}
1085
1086
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001087XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1088{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001089 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001090 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001091 }
1092 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1093 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001094}
1095
1096
1097bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1098{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001099 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001100 const XMLUnknown* unknown = compare->ToUnknown();
1101 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001102}
1103
1104
Lee Thomason50f97b22012-02-11 16:33:40 -08001105bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1106{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001107 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001108 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001109}
1110
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001111// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001112
1113const char* XMLAttribute::Name() const
1114{
1115 return _name.GetStr();
1116}
1117
1118const char* XMLAttribute::Value() const
1119{
1120 return _value.GetStr();
1121}
1122
Lee Thomason6f381b72012-03-02 12:59:39 -08001123char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001124{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001125 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001126 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001127 if ( !p || !*p ) {
1128 return 0;
1129 }
Lee Thomason22aead12012-01-23 13:29:35 -08001130
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001131 // Skip white space before =
1132 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001133 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001134 return 0;
1135 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001136
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001137 ++p; // move up to opening quote
1138 p = XMLUtil::SkipWhiteSpace( p );
1139 if ( *p != '\"' && *p != '\'' ) {
1140 return 0;
1141 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001142
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001143 char endTag[2] = { *p, 0 };
1144 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001145
Lee Thomason624d43f2012-10-12 10:58:48 -07001146 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001147 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001148}
1149
1150
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001151void XMLAttribute::SetName( const char* n )
1152{
Lee Thomason624d43f2012-10-12 10:58:48 -07001153 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001154}
1155
1156
Lee Thomason2fa81722012-11-09 12:37:46 -08001157XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001158{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001159 if ( XMLUtil::ToInt( Value(), value )) {
1160 return XML_NO_ERROR;
1161 }
1162 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001163}
1164
1165
Lee Thomason2fa81722012-11-09 12:37:46 -08001166XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001167{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001168 if ( XMLUtil::ToUnsigned( Value(), value )) {
1169 return XML_NO_ERROR;
1170 }
1171 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001172}
1173
1174
Lee Thomason2fa81722012-11-09 12:37:46 -08001175XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001176{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001177 if ( XMLUtil::ToBool( Value(), value )) {
1178 return XML_NO_ERROR;
1179 }
1180 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001181}
1182
1183
Lee Thomason2fa81722012-11-09 12:37:46 -08001184XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001185{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001186 if ( XMLUtil::ToFloat( Value(), value )) {
1187 return XML_NO_ERROR;
1188 }
1189 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001190}
1191
1192
Lee Thomason2fa81722012-11-09 12:37:46 -08001193XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001194{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001195 if ( XMLUtil::ToDouble( Value(), value )) {
1196 return XML_NO_ERROR;
1197 }
1198 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001199}
1200
1201
1202void XMLAttribute::SetAttribute( const char* v )
1203{
Lee Thomason624d43f2012-10-12 10:58:48 -07001204 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001205}
1206
1207
Lee Thomason1ff38e02012-02-14 18:18:16 -08001208void XMLAttribute::SetAttribute( int v )
1209{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001210 char buf[BUF_SIZE];
1211 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001212 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001213}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001214
1215
1216void XMLAttribute::SetAttribute( unsigned v )
1217{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001218 char buf[BUF_SIZE];
1219 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001220 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001221}
1222
1223
1224void XMLAttribute::SetAttribute( bool v )
1225{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001226 char buf[BUF_SIZE];
1227 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001228 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001229}
1230
1231void XMLAttribute::SetAttribute( double v )
1232{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001233 char buf[BUF_SIZE];
1234 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001235 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001236}
1237
1238void XMLAttribute::SetAttribute( float v )
1239{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001240 char buf[BUF_SIZE];
1241 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001242 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001243}
1244
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001245
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001246// --------- XMLElement ---------- //
1247XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001248 _closingType( 0 ),
1249 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001250{
1251}
1252
1253
1254XMLElement::~XMLElement()
1255{
Lee Thomason624d43f2012-10-12 10:58:48 -07001256 while( _rootAttribute ) {
1257 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001258 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001259 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001260 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001261}
1262
1263
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001264const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1265{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001266 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001267 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1268 return a;
1269 }
1270 }
1271 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001272}
1273
1274
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001275const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001276{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001277 const XMLAttribute* a = FindAttribute( name );
1278 if ( !a ) {
1279 return 0;
1280 }
1281 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1282 return a->Value();
1283 }
1284 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001285}
1286
1287
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001288const char* XMLElement::GetText() const
1289{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001290 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001291 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001292 }
1293 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001294}
1295
1296
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001297void XMLElement::SetText( const char* inText )
1298{
Uli Kusterer869bb592014-01-21 01:36:16 +01001299 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001300 FirstChild()->SetValue( inText );
1301 else {
1302 XMLText* theText = GetDocument()->NewText( inText );
1303 InsertFirstChild( theText );
1304 }
1305}
1306
Lee Thomason5bb2d802014-01-24 10:42:57 -08001307
1308void XMLElement::SetText( int v )
1309{
1310 char buf[BUF_SIZE];
1311 XMLUtil::ToStr( v, buf, BUF_SIZE );
1312 SetText( buf );
1313}
1314
1315
1316void XMLElement::SetText( unsigned v )
1317{
1318 char buf[BUF_SIZE];
1319 XMLUtil::ToStr( v, buf, BUF_SIZE );
1320 SetText( buf );
1321}
1322
1323
1324void XMLElement::SetText( bool v )
1325{
1326 char buf[BUF_SIZE];
1327 XMLUtil::ToStr( v, buf, BUF_SIZE );
1328 SetText( buf );
1329}
1330
1331
1332void XMLElement::SetText( float v )
1333{
1334 char buf[BUF_SIZE];
1335 XMLUtil::ToStr( v, buf, BUF_SIZE );
1336 SetText( buf );
1337}
1338
1339
1340void XMLElement::SetText( double v )
1341{
1342 char buf[BUF_SIZE];
1343 XMLUtil::ToStr( v, buf, BUF_SIZE );
1344 SetText( buf );
1345}
1346
1347
MortenMacFly4ee49f12013-01-14 20:03:14 +01001348XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001349{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001350 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001351 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001352 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001353 return XML_SUCCESS;
1354 }
1355 return XML_CAN_NOT_CONVERT_TEXT;
1356 }
1357 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001358}
1359
1360
MortenMacFly4ee49f12013-01-14 20:03:14 +01001361XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001362{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001363 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001364 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001365 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001366 return XML_SUCCESS;
1367 }
1368 return XML_CAN_NOT_CONVERT_TEXT;
1369 }
1370 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001371}
1372
1373
MortenMacFly4ee49f12013-01-14 20:03:14 +01001374XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001375{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001376 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001377 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001378 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001379 return XML_SUCCESS;
1380 }
1381 return XML_CAN_NOT_CONVERT_TEXT;
1382 }
1383 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001384}
1385
1386
MortenMacFly4ee49f12013-01-14 20:03:14 +01001387XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001388{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001389 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001390 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001391 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001392 return XML_SUCCESS;
1393 }
1394 return XML_CAN_NOT_CONVERT_TEXT;
1395 }
1396 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001397}
1398
1399
MortenMacFly4ee49f12013-01-14 20:03:14 +01001400XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001401{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001402 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001403 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001404 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001405 return XML_SUCCESS;
1406 }
1407 return XML_CAN_NOT_CONVERT_TEXT;
1408 }
1409 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001410}
1411
1412
1413
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001414XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1415{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001416 XMLAttribute* last = 0;
1417 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001418 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001419 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001420 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001421 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1422 break;
1423 }
1424 }
1425 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001426 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001427 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1428 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001429 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001430 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001431 }
1432 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001433 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001434 }
1435 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001436 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001437 }
1438 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001439}
1440
1441
U-Stream\Leeae25a442012-02-17 17:48:16 -08001442void XMLElement::DeleteAttribute( const char* name )
1443{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001444 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001445 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001446 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1447 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001448 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001449 }
1450 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001451 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001452 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001453 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001454 break;
1455 }
1456 prev = a;
1457 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001458}
1459
1460
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001461char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001462{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001463 const char* start = p;
1464 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001465
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001466 // Read the attributes.
1467 while( p ) {
1468 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001469 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001470 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001471 return 0;
1472 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001473
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001474 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001475 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001476 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001477 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1478 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001479 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001480
Lee Thomason624d43f2012-10-12 10:58:48 -07001481 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001482 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001483 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001484 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001485 return 0;
1486 }
1487 // There is a minor bug here: if the attribute in the source xml
1488 // document is duplicated, it will not be detected and the
1489 // attribute will be doubly added. However, tracking the 'prevAttribute'
1490 // avoids re-scanning the attribute list. Preferring performance for
1491 // now, may reconsider in the future.
1492 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001493 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001494 }
1495 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001496 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001497 }
1498 prevAttribute = attrib;
1499 }
1500 // end of the tag
1501 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001502 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001503 return p+2; // done; sealed element.
1504 }
1505 // end of the tag
1506 else if ( *p == '>' ) {
1507 ++p;
1508 break;
1509 }
1510 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001511 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001512 return 0;
1513 }
1514 }
1515 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001516}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001517
Dmitry-Mee3225b12014-09-03 11:03:11 +04001518void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1519{
1520 if ( attribute == 0 ) {
1521 return;
1522 }
1523 MemPool* pool = attribute->_memPool;
1524 attribute->~XMLAttribute();
1525 pool->Free( attribute );
1526}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001527
Lee Thomason67d61312012-01-24 16:01:51 -08001528//
1529// <ele></ele>
1530// <ele>foo<b>bar</b></ele>
1531//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001532char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001533{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001534 // Read the element name.
1535 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001536
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001537 // The closing element is the </element> form. It is
1538 // parsed just like a regular element then deleted from
1539 // the DOM.
1540 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001541 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001542 ++p;
1543 }
Lee Thomason67d61312012-01-24 16:01:51 -08001544
Lee Thomason624d43f2012-10-12 10:58:48 -07001545 p = _value.ParseName( p );
1546 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001547 return 0;
1548 }
Lee Thomason67d61312012-01-24 16:01:51 -08001549
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001550 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001551 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001552 return p;
1553 }
Lee Thomason67d61312012-01-24 16:01:51 -08001554
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001555 p = XMLNode::ParseDeep( p, strPair );
1556 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001557}
1558
1559
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001560
1561XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1562{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001563 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001564 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001565 }
1566 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1567 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1568 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1569 }
1570 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001571}
1572
1573
1574bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1575{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001576 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001577 const XMLElement* other = compare->ToElement();
1578 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001579
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001580 const XMLAttribute* a=FirstAttribute();
1581 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001582
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001583 while ( a && b ) {
1584 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1585 return false;
1586 }
1587 a = a->Next();
1588 b = b->Next();
1589 }
1590 if ( a || b ) {
1591 // different count
1592 return false;
1593 }
1594 return true;
1595 }
1596 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001597}
1598
1599
Lee Thomason751da522012-02-10 08:50:51 -08001600bool XMLElement::Accept( XMLVisitor* visitor ) const
1601{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001602 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001603 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001604 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1605 if ( !node->Accept( visitor ) ) {
1606 break;
1607 }
1608 }
1609 }
1610 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001611}
Lee Thomason56bdd022012-02-09 18:16:58 -08001612
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001613
Lee Thomason3f57d272012-01-11 15:30:03 -08001614// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001615
1616// Warning: List must match 'enum XMLError'
1617const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1618 "XML_SUCCESS",
1619 "XML_NO_ATTRIBUTE",
1620 "XML_WRONG_ATTRIBUTE_TYPE",
1621 "XML_ERROR_FILE_NOT_FOUND",
1622 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1623 "XML_ERROR_FILE_READ_ERROR",
1624 "XML_ERROR_ELEMENT_MISMATCH",
1625 "XML_ERROR_PARSING_ELEMENT",
1626 "XML_ERROR_PARSING_ATTRIBUTE",
1627 "XML_ERROR_IDENTIFYING_TAG",
1628 "XML_ERROR_PARSING_TEXT",
1629 "XML_ERROR_PARSING_CDATA",
1630 "XML_ERROR_PARSING_COMMENT",
1631 "XML_ERROR_PARSING_DECLARATION",
1632 "XML_ERROR_PARSING_UNKNOWN",
1633 "XML_ERROR_EMPTY_DOCUMENT",
1634 "XML_ERROR_MISMATCHED_ELEMENT",
1635 "XML_ERROR_PARSING",
1636 "XML_CAN_NOT_CONVERT_TEXT",
1637 "XML_NO_TEXT_NODE"
1638};
1639
1640
Lee Thomason624d43f2012-10-12 10:58:48 -07001641XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001642 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001643 _writeBOM( false ),
1644 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001645 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001646 _whitespace( whitespace ),
1647 _errorStr1( 0 ),
1648 _errorStr2( 0 ),
1649 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001650{
Lee Thomason624d43f2012-10-12 10:58:48 -07001651 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001652}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001653
1654
Lee Thomason3f57d272012-01-11 15:30:03 -08001655XMLDocument::~XMLDocument()
1656{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001657 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001658}
1659
1660
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001661void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001662{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001663 DeleteChildren();
1664
Dmitry-Meab37df82014-11-28 12:08:36 +03001665#ifdef DEBUG
1666 const bool hadError = Error();
1667#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001668 _errorID = XML_NO_ERROR;
1669 _errorStr1 = 0;
1670 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001671
Lee Thomason624d43f2012-10-12 10:58:48 -07001672 delete [] _charBuffer;
1673 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001674
1675#if 0
1676 _textPool.Trace( "text" );
1677 _elementPool.Trace( "element" );
1678 _commentPool.Trace( "comment" );
1679 _attributePool.Trace( "attribute" );
1680#endif
1681
1682#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001683 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001684 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1685 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1686 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1687 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1688 }
1689#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001690}
1691
Lee Thomason3f57d272012-01-11 15:30:03 -08001692
Lee Thomason2c85a712012-01-31 08:24:24 -08001693XMLElement* XMLDocument::NewElement( const char* name )
1694{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001695 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001696 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1697 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001698 ele->SetName( name );
1699 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001700}
1701
1702
Lee Thomason1ff38e02012-02-14 18:18:16 -08001703XMLComment* XMLDocument::NewComment( const char* str )
1704{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001705 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001706 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1707 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001708 comment->SetValue( str );
1709 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001710}
1711
1712
1713XMLText* XMLDocument::NewText( const char* str )
1714{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001715 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001716 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1717 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001718 text->SetValue( str );
1719 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001720}
1721
1722
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001723XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1724{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001725 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001726 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1727 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001728 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1729 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001730}
1731
1732
1733XMLUnknown* XMLDocument::NewUnknown( const char* str )
1734{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001735 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001736 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1737 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001738 unk->SetValue( str );
1739 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001740}
1741
Dmitry-Me01578db2014-08-19 10:18:48 +04001742static FILE* callfopen( const char* filepath, const char* mode )
1743{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001744 TIXMLASSERT( filepath );
1745 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001746#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1747 FILE* fp = 0;
1748 errno_t err = fopen_s( &fp, filepath, mode );
1749 if ( err ) {
1750 return 0;
1751 }
1752#else
1753 FILE* fp = fopen( filepath, mode );
1754#endif
1755 return fp;
1756}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001757
1758void XMLDocument::DeleteNode( XMLNode* node ) {
1759 TIXMLASSERT( node );
1760 TIXMLASSERT(node->_document == this );
1761 if (node->_parent) {
1762 node->_parent->DeleteChild( node );
1763 }
1764 else {
1765 // Isn't in the tree.
1766 // Use the parent delete.
1767 // Also, we need to mark it tracked: we 'know'
1768 // it was never used.
1769 node->_memPool->SetTracked();
1770 // Call the static XMLNode version:
1771 XMLNode::DeleteNode(node);
1772 }
1773}
1774
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001775
Lee Thomason2fa81722012-11-09 12:37:46 -08001776XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001777{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001778 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001779 FILE* fp = callfopen( filename, "rb" );
1780 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001781 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001782 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001783 }
1784 LoadFile( fp );
1785 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001786 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001787}
1788
1789
Lee Thomason2fa81722012-11-09 12:37:46 -08001790XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001791{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001792 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001793
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001794 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001795 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001796 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1797 return _errorID;
1798 }
1799
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001800 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001801 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001802 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001803 if ( filelength == -1L ) {
1804 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1805 return _errorID;
1806 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001807
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001808 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001809 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001810 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001811 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001812 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001813
Lee Thomason624d43f2012-10-12 10:58:48 -07001814 _charBuffer = new char[size+1];
1815 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001816 if ( read != size ) {
1817 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001818 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001819 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001820
Lee Thomason624d43f2012-10-12 10:58:48 -07001821 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001822
Lee Thomason624d43f2012-10-12 10:58:48 -07001823 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001824 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001825 p = XMLUtil::ReadBOM( p, &_writeBOM );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001826 if ( !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001827 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001828 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001829 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001830
Lee Thomason624d43f2012-10-12 10:58:48 -07001831 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1832 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001833}
1834
1835
Lee Thomason2fa81722012-11-09 12:37:46 -08001836XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001837{
Dmitry-Me01578db2014-08-19 10:18:48 +04001838 FILE* fp = callfopen( filename, "w" );
1839 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001840 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001841 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001842 }
1843 SaveFile(fp, compact);
1844 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001845 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001846}
1847
1848
Lee Thomason2fa81722012-11-09 12:37:46 -08001849XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001850{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001851 XMLPrinter stream( fp, compact );
1852 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001853 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001854}
1855
Lee Thomason1ff38e02012-02-14 18:18:16 -08001856
Lee Thomason2fa81722012-11-09 12:37:46 -08001857XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001858{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001859 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001860
Lee Thomason82d32002014-02-21 22:47:18 -08001861 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001862 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001863 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001864 }
1865 if ( len == (size_t)(-1) ) {
1866 len = strlen( p );
1867 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001868 _charBuffer = new char[ len+1 ];
1869 memcpy( _charBuffer, p, len );
1870 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001871
Dmitry-Me5b4a5162014-12-23 17:36:28 +03001872 const char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001873 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001874 p = XMLUtil::ReadBOM( p, &_writeBOM );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001875 if ( !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001876 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001877 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001878 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001879
Thomas Roß1470edc2013-05-10 15:44:12 +02001880 ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001881 ParseDeep( _charBuffer+delta, 0 );
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001882 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001883 // clean up now essentially dangling memory.
1884 // and the parse fail can put objects in the
1885 // pools that are dead and inaccessible.
1886 DeleteChildren();
1887 _elementPool.Clear();
1888 _attributePool.Clear();
1889 _textPool.Clear();
1890 _commentPool.Clear();
1891 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001892 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001893}
1894
1895
PKEuS1c5f99e2013-07-06 11:28:39 +02001896void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001897{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001898 XMLPrinter stdStreamer( stdout );
1899 if ( !streamer ) {
1900 streamer = &stdStreamer;
1901 }
1902 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001903}
1904
1905
Lee Thomason2fa81722012-11-09 12:37:46 -08001906void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001907{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001908 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07001909 _errorID = error;
1910 _errorStr1 = str1;
1911 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001912}
1913
Lee Thomason331596e2014-09-11 14:56:43 -07001914const char* XMLDocument::ErrorName() const
1915{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001916 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Lee Thomason331596e2014-09-11 14:56:43 -07001917 return _errorNames[_errorID];
1918}
Lee Thomason5cae8972012-01-24 18:03:07 -08001919
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001920void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001921{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001922 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001923 static const int LEN = 20;
1924 char buf1[LEN] = { 0 };
1925 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001926
Lee Thomason624d43f2012-10-12 10:58:48 -07001927 if ( _errorStr1 ) {
1928 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001929 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001930 if ( _errorStr2 ) {
1931 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001932 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001933
Lee Thomason331596e2014-09-11 14:56:43 -07001934 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
1935 _errorID, ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001936 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001937}
1938
1939
PKEuS1bfb9542013-08-04 13:51:17 +02001940XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001941 _elementJustOpened( false ),
1942 _firstElement( true ),
1943 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001944 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001945 _textDepth( -1 ),
1946 _processEntities( true ),
1947 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001948{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001949 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001950 _entityFlag[i] = false;
1951 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001952 }
1953 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03001954 const char entityValue = entities[i].value;
1955 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
1956 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001957 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03001958 _restrictedEntityFlag[(unsigned char)'&'] = true;
1959 _restrictedEntityFlag[(unsigned char)'<'] = true;
1960 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07001961 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001962}
1963
1964
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001965void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001966{
1967 va_list va;
1968 va_start( va, format );
1969
Lee Thomason624d43f2012-10-12 10:58:48 -07001970 if ( _fp ) {
1971 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001972 }
1973 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001974#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001975 #if defined(WINCE)
1976 int len = 512;
1977 do {
1978 len = len*2;
1979 char* str = new char[len]();
1980 len = _vsnprintf(str, len, format, va);
1981 delete[] str;
1982 }while (len < 0);
1983 #else
Thomas Roß268c6832014-03-13 23:35:16 +01001984 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08001985 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001986#else
1987 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01001988#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001989 // Close out and re-start the va-args
1990 va_end( va );
1991 va_start( va, format );
Lee Thomasona0744c82014-03-16 10:32:27 -07001992 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
1993#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001994 #if defined(WINCE)
1995 _vsnprintf( p, len+1, format, va );
1996 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07001997 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08001998 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07001999#else
2000 vsnprintf( p, len+1, format, va );
2001#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002002 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002003 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002004}
2005
2006
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002007void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002008{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002009 for( int i=0; i<depth; ++i ) {
2010 Print( " " );
2011 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002012}
2013
2014
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002015void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002016{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002017 // Look for runs of bytes between entities to print.
2018 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07002019 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08002020
Lee Thomason624d43f2012-10-12 10:58:48 -07002021 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002022 while ( *q ) {
2023 // Remember, char is sometimes signed. (How many times has that bitten me?)
2024 if ( *q > 0 && *q < ENTITY_RANGE ) {
2025 // Check for entities. If one is found, flush
2026 // the stream up until the entity, write the
2027 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002028 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002029 while ( p < q ) {
2030 Print( "%c", *p );
2031 ++p;
2032 }
2033 for( int i=0; i<NUM_ENTITIES; ++i ) {
2034 if ( entities[i].value == *q ) {
2035 Print( "&%s;", entities[i].pattern );
2036 break;
2037 }
2038 }
2039 ++p;
2040 }
2041 }
2042 ++q;
2043 }
2044 }
2045 // Flush the remaining string. This will be the entire
2046 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07002047 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002048 Print( "%s", p );
2049 }
Lee Thomason857b8682012-01-25 17:50:25 -08002050}
2051
U-Stream\Leeae25a442012-02-17 17:48:16 -08002052
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002053void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002054{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002055 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002056 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 -07002057 Print( "%s", bom );
2058 }
2059 if ( writeDec ) {
2060 PushDeclaration( "xml version=\"1.0\"" );
2061 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002062}
2063
2064
Uli Kusterer593a33d2014-02-01 12:48:51 +01002065void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002066{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002067 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002068 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002069
Uli Kusterer593a33d2014-02-01 12:48:51 +01002070 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002071 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002072 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002073 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002074 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002075 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002076
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002077 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002078 _elementJustOpened = true;
2079 _firstElement = false;
2080 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002081}
2082
2083
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002084void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002085{
Lee Thomason624d43f2012-10-12 10:58:48 -07002086 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002087 Print( " %s=\"", name );
2088 PrintString( value, false );
2089 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002090}
2091
2092
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002093void XMLPrinter::PushAttribute( const char* name, int v )
2094{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002095 char buf[BUF_SIZE];
2096 XMLUtil::ToStr( v, buf, BUF_SIZE );
2097 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002098}
2099
2100
2101void XMLPrinter::PushAttribute( const char* name, unsigned v )
2102{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002103 char buf[BUF_SIZE];
2104 XMLUtil::ToStr( v, buf, BUF_SIZE );
2105 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002106}
2107
2108
2109void XMLPrinter::PushAttribute( const char* name, bool v )
2110{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002111 char buf[BUF_SIZE];
2112 XMLUtil::ToStr( v, buf, BUF_SIZE );
2113 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002114}
2115
2116
2117void XMLPrinter::PushAttribute( const char* name, double v )
2118{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002119 char buf[BUF_SIZE];
2120 XMLUtil::ToStr( v, buf, BUF_SIZE );
2121 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002122}
2123
2124
Uli Kustererca412e82014-02-01 13:35:05 +01002125void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002126{
Lee Thomason624d43f2012-10-12 10:58:48 -07002127 --_depth;
2128 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002129
Lee Thomason624d43f2012-10-12 10:58:48 -07002130 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002131 Print( "/>" );
2132 }
2133 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002134 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002135 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002136 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002137 }
2138 Print( "</%s>", name );
2139 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002140
Lee Thomason624d43f2012-10-12 10:58:48 -07002141 if ( _textDepth == _depth ) {
2142 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002143 }
Uli Kustererca412e82014-02-01 13:35:05 +01002144 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002145 Print( "\n" );
2146 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002147 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002148}
2149
2150
Dmitry-Mea092bc12014-12-23 17:57:05 +03002151void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002152{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002153 if ( !_elementJustOpened ) {
2154 return;
2155 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002156 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002157 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002158}
2159
2160
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002161void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002162{
Lee Thomason624d43f2012-10-12 10:58:48 -07002163 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002164
Dmitry-Mea092bc12014-12-23 17:57:05 +03002165 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002166 if ( cdata ) {
2167 Print( "<![CDATA[" );
2168 Print( "%s", text );
2169 Print( "]]>" );
2170 }
2171 else {
2172 PrintString( text, true );
2173 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002174}
2175
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002176void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002177{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002178 char buf[BUF_SIZE];
2179 XMLUtil::ToStr( value, buf, BUF_SIZE );
2180 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002181}
2182
2183
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002184void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002185{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002186 char buf[BUF_SIZE];
2187 XMLUtil::ToStr( value, buf, BUF_SIZE );
2188 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002189}
2190
2191
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002192void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002193{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002194 char buf[BUF_SIZE];
2195 XMLUtil::ToStr( value, buf, BUF_SIZE );
2196 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002197}
2198
2199
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002200void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002201{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002202 char buf[BUF_SIZE];
2203 XMLUtil::ToStr( value, buf, BUF_SIZE );
2204 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002205}
2206
2207
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002208void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002209{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002210 char buf[BUF_SIZE];
2211 XMLUtil::ToStr( value, buf, BUF_SIZE );
2212 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002213}
2214
Lee Thomason5cae8972012-01-24 18:03:07 -08002215
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002216void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002217{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002218 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002219 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002220 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002221 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002222 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002223 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002224 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002225}
Lee Thomason751da522012-02-10 08:50:51 -08002226
2227
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002228void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002229{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002230 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002231 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002232 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002233 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002234 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002235 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002236 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002237}
2238
2239
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002240void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002241{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002242 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002243 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002244 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002245 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002246 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002247 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002248 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002249}
2250
2251
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002252bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002253{
Lee Thomason624d43f2012-10-12 10:58:48 -07002254 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002255 if ( doc.HasBOM() ) {
2256 PushHeader( true, false );
2257 }
2258 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002259}
2260
2261
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002262bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002263{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002264 const XMLElement* parentElem = element.Parent()->ToElement();
2265 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2266 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002267 while ( attribute ) {
2268 PushAttribute( attribute->Name(), attribute->Value() );
2269 attribute = attribute->Next();
2270 }
2271 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002272}
2273
2274
Uli Kustererca412e82014-02-01 13:35:05 +01002275bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002276{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002277 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002278 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002279}
2280
2281
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002282bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002283{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002284 PushText( text.Value(), text.CData() );
2285 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002286}
2287
2288
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002289bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002290{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002291 PushComment( comment.Value() );
2292 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002293}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002294
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002295bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002296{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002297 PushDeclaration( declaration.Value() );
2298 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002299}
2300
2301
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002302bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002303{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002304 PushUnknown( unknown.Value() );
2305 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002306}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002307
Lee Thomason685b8952012-11-12 13:00:06 -08002308} // namespace tinyxml2
2309