blob: af27418a023b6d362372f8e88ac769aa64e77805 [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 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800143
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400144 char* const start = p;
145
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +0200146 while( *p && ( p == start ? XMLUtil::IsNameStartChar( *p ) : XMLUtil::IsNameChar( *p ) )) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700147 ++p;
148 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800149
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700150 if ( p > start ) {
151 Set( start, p, 0 );
152 return p;
153 }
154 return 0;
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 Thomason7d00b9a2012-02-27 17:54:22 -0800529#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800530#pragma warning ( push )
531#pragma warning ( disable : 4127 )
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800532#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700533 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
534 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800535#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800536#pragma warning (pop)
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800537#endif
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400538 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700539 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300540 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700541 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
542 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700543 p += xmlHeaderLen;
544 }
545 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300546 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700547 returnNode = new (_commentPool.Alloc()) XMLComment( this );
548 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700549 p += commentHeaderLen;
550 }
551 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300552 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700553 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700554 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700555 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700556 p += cdataHeaderLen;
557 text->SetCData( true );
558 }
559 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300560 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700561 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
562 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700563 p += dtdHeaderLen;
564 }
565 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300566 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700567 returnNode = new (_elementPool.Alloc()) XMLElement( this );
568 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700569 p += elementHeaderLen;
570 }
571 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300572 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700573 returnNode = new (_textPool.Alloc()) XMLText( this );
574 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700575 p = start; // Back it up, all the text counts.
576 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800577
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700578 *node = returnNode;
579 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800580}
581
582
Lee Thomason751da522012-02-10 08:50:51 -0800583bool XMLDocument::Accept( XMLVisitor* visitor ) const
584{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700585 if ( visitor->VisitEnter( *this ) ) {
586 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
587 if ( !node->Accept( visitor ) ) {
588 break;
589 }
590 }
591 }
592 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800593}
Lee Thomason56bdd022012-02-09 18:16:58 -0800594
595
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800596// --------- XMLNode ----------- //
597
598XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700599 _document( doc ),
600 _parent( 0 ),
601 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200602 _prev( 0 ), _next( 0 ),
603 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800604{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800605}
606
607
608XMLNode::~XMLNode()
609{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700610 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700611 if ( _parent ) {
612 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700613 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800614}
615
Michael Daumling21626882013-10-22 17:03:37 +0200616const char* XMLNode::Value() const
617{
618 return _value.GetStr();
619}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800620
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800621void XMLNode::SetValue( const char* str, bool staticMem )
622{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700623 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700624 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700625 }
626 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700627 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700628 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800629}
630
631
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800632void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800633{
Lee Thomason624d43f2012-10-12 10:58:48 -0700634 while( _firstChild ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300635 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700636 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700637 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700638
Dmitry-Mee3225b12014-09-03 11:03:11 +0400639 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700640 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700641 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800642}
643
644
645void XMLNode::Unlink( XMLNode* child )
646{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300647 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300648 TIXMLASSERT( child->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700649 if ( child == _firstChild ) {
650 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700651 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700652 if ( child == _lastChild ) {
653 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700654 }
Lee Thomasond923c672012-01-23 08:44:25 -0800655
Lee Thomason624d43f2012-10-12 10:58:48 -0700656 if ( child->_prev ) {
657 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700658 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700659 if ( child->_next ) {
660 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700661 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700662 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800663}
664
665
U-Stream\Leeae25a442012-02-17 17:48:16 -0800666void XMLNode::DeleteChild( XMLNode* node )
667{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300668 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300669 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700670 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400671 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800672}
673
674
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800675XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
676{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300677 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300678 if ( addThis->_document != _document ) {
679 TIXMLASSERT( false );
680 return 0;
681 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700682
Michael Daumlinged523282013-10-23 07:47:29 +0200683 if (addThis->_parent)
684 addThis->_parent->Unlink( addThis );
685 else
686 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700687
Lee Thomason624d43f2012-10-12 10:58:48 -0700688 if ( _lastChild ) {
689 TIXMLASSERT( _firstChild );
690 TIXMLASSERT( _lastChild->_next == 0 );
691 _lastChild->_next = addThis;
692 addThis->_prev = _lastChild;
693 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800694
Lee Thomason624d43f2012-10-12 10:58:48 -0700695 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700696 }
697 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700698 TIXMLASSERT( _firstChild == 0 );
699 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800700
Lee Thomason624d43f2012-10-12 10:58:48 -0700701 addThis->_prev = 0;
702 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700703 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700704 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700705 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800706}
707
708
Lee Thomason1ff38e02012-02-14 18:18:16 -0800709XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
710{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300711 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300712 if ( addThis->_document != _document ) {
713 TIXMLASSERT( false );
714 return 0;
715 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700716
Michael Daumlinged523282013-10-23 07:47:29 +0200717 if (addThis->_parent)
718 addThis->_parent->Unlink( addThis );
719 else
720 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700721
Lee Thomason624d43f2012-10-12 10:58:48 -0700722 if ( _firstChild ) {
723 TIXMLASSERT( _lastChild );
724 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800725
Lee Thomason624d43f2012-10-12 10:58:48 -0700726 _firstChild->_prev = addThis;
727 addThis->_next = _firstChild;
728 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800729
Lee Thomason624d43f2012-10-12 10:58:48 -0700730 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700731 }
732 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700733 TIXMLASSERT( _lastChild == 0 );
734 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800735
Lee Thomason624d43f2012-10-12 10:58:48 -0700736 addThis->_prev = 0;
737 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700738 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700739 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400740 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800741}
742
743
744XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
745{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300746 TIXMLASSERT( addThis );
747 if ( addThis->_document != _document ) {
748 TIXMLASSERT( false );
749 return 0;
750 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700751
Dmitry-Meabb2d042014-12-09 12:59:31 +0300752 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700753
Lee Thomason624d43f2012-10-12 10:58:48 -0700754 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300755 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700756 return 0;
757 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800758
Lee Thomason624d43f2012-10-12 10:58:48 -0700759 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700760 // The last node or the only node.
761 return InsertEndChild( addThis );
762 }
Michael Daumlinged523282013-10-23 07:47:29 +0200763 if (addThis->_parent)
764 addThis->_parent->Unlink( addThis );
765 else
766 addThis->_memPool->SetTracked();
Lee Thomason624d43f2012-10-12 10:58:48 -0700767 addThis->_prev = afterThis;
768 addThis->_next = afterThis->_next;
769 afterThis->_next->_prev = addThis;
770 afterThis->_next = addThis;
771 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700772 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800773}
774
775
776
777
Lee Thomason56bdd022012-02-09 18:16:58 -0800778const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800779{
Lee Thomason624d43f2012-10-12 10:58:48 -0700780 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700781 XMLElement* element = node->ToElement();
782 if ( element ) {
783 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
784 return element;
785 }
786 }
787 }
788 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800789}
790
791
Lee Thomason56bdd022012-02-09 18:16:58 -0800792const XMLElement* XMLNode::LastChildElement( const char* value ) const
793{
Lee Thomason624d43f2012-10-12 10:58:48 -0700794 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700795 XMLElement* element = node->ToElement();
796 if ( element ) {
797 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
798 return element;
799 }
800 }
801 }
802 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800803}
804
805
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800806const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
807{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400808 for( XMLNode* node=this->_next; node; node = node->_next ) {
809 const XMLElement* element = node->ToElement();
810 if ( element
811 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
812 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700813 }
814 }
815 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800816}
817
818
819const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
820{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400821 for( XMLNode* node=_prev; node; node = node->_prev ) {
822 const XMLElement* element = node->ToElement();
823 if ( element
824 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
825 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700826 }
827 }
828 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800829}
830
831
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800832char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800833{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700834 // This is a recursive method, but thinking about it "at the current level"
835 // it is a pretty simple flat list:
836 // <foo/>
837 // <!-- comment -->
838 //
839 // With a special case:
840 // <foo>
841 // </foo>
842 // <!-- comment -->
843 //
844 // Where the closing element (/foo) *must* be the next thing after the opening
845 // element, and the names must match. BUT the tricky bit is that the closing
846 // element will be read by the child.
847 //
848 // 'endTag' is the end tag for this node, it is returned by a call to a child.
849 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800850
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700851 while( p && *p ) {
852 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800853
Lee Thomason624d43f2012-10-12 10:58:48 -0700854 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700855 if ( p == 0 || node == 0 ) {
856 break;
857 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800858
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700859 StrPair endTag;
860 p = node->ParseDeep( p, &endTag );
861 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400862 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700863 if ( !_document->Error() ) {
864 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700865 }
866 break;
867 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800868
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400869 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700870 // We read the end tag. Return it to the parent.
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400871 if ( ele && ele->ClosingType() == XMLElement::CLOSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700872 if ( parentEnd ) {
Lee Thomason29658802014-11-27 22:31:11 -0800873 ele->_value.TransferTo( parentEnd );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700874 }
Lee Thomason5b0a6772012-11-19 13:54:42 -0800875 node->_memPool->SetTracked(); // created and then immediately deleted.
Dmitry-Mee3225b12014-09-03 11:03:11 +0400876 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700877 return p;
878 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800879
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700880 // Handle an end tag returned to this level.
881 // And handle a bunch of annoying errors.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700882 if ( ele ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400883 bool mismatch = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700884 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400885 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700886 }
887 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400888 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700889 }
890 else if ( !endTag.Empty() ) {
891 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400892 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700893 }
894 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400895 if ( mismatch ) {
896 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -0500897 DeleteNode( node );
898 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400899 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700900 }
JayXondbfdd8f2014-12-12 20:07:14 -0500901 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700902 }
903 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800904}
905
Dmitry-Mee3225b12014-09-03 11:03:11 +0400906void XMLNode::DeleteNode( XMLNode* node )
907{
908 if ( node == 0 ) {
909 return;
910 }
911 MemPool* pool = node->_memPool;
912 node->~XMLNode();
913 pool->Free( node );
914}
915
Lee Thomason5492a1c2012-01-23 15:32:10 -0800916// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800917char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800918{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700919 const char* start = p;
920 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700921 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700922 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700923 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700924 }
925 return p;
926 }
927 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700928 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
929 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700930 flags |= StrPair::COLLAPSE_WHITESPACE;
931 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700932
Lee Thomason624d43f2012-10-12 10:58:48 -0700933 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700934 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700935 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700936 }
937 if ( p && *p ) {
938 return p-1;
939 }
940 }
941 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800942}
943
944
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800945XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
946{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700947 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700948 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700949 }
950 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
951 text->SetCData( this->CData() );
952 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800953}
954
955
956bool XMLText::ShallowEqual( const XMLNode* compare ) const
957{
Dmitry-Me6d202ff2014-09-26 14:21:00 +0400958 const XMLText* text = compare->ToText();
959 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800960}
961
962
Lee Thomason56bdd022012-02-09 18:16:58 -0800963bool XMLText::Accept( XMLVisitor* visitor ) const
964{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300965 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700966 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800967}
968
969
Lee Thomason3f57d272012-01-11 15:30:03 -0800970// --------- XMLComment ---------- //
971
Lee Thomasone4422302012-01-20 17:59:50 -0800972XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800973{
974}
975
976
Lee Thomasonce0763e2012-01-11 15:43:54 -0800977XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800978{
Lee Thomason3f57d272012-01-11 15:30:03 -0800979}
980
981
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800982char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800983{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700984 // Comment parses as text.
985 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700986 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700987 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700988 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700989 }
990 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800991}
992
993
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800994XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
995{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700996 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700997 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700998 }
999 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1000 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001001}
1002
1003
1004bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1005{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001006 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001007 const XMLComment* comment = compare->ToComment();
1008 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001009}
1010
1011
Lee Thomason751da522012-02-10 08:50:51 -08001012bool XMLComment::Accept( XMLVisitor* visitor ) const
1013{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001014 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001015 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001016}
Lee Thomason56bdd022012-02-09 18:16:58 -08001017
1018
Lee Thomason50f97b22012-02-11 16:33:40 -08001019// --------- XMLDeclaration ---------- //
1020
1021XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1022{
1023}
1024
1025
1026XMLDeclaration::~XMLDeclaration()
1027{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001028 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001029}
1030
1031
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001032char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001033{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001034 // Declaration parses as text.
1035 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001036 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001037 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001038 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001039 }
1040 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001041}
1042
1043
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001044XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1045{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001046 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001047 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001048 }
1049 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1050 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001051}
1052
1053
1054bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1055{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001056 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001057 const XMLDeclaration* declaration = compare->ToDeclaration();
1058 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001059}
1060
1061
1062
Lee Thomason50f97b22012-02-11 16:33:40 -08001063bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1064{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001065 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001066 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001067}
1068
1069// --------- XMLUnknown ---------- //
1070
1071XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1072{
1073}
1074
1075
1076XMLUnknown::~XMLUnknown()
1077{
1078}
1079
1080
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001081char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001082{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001083 // Unknown parses as text.
1084 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001085
Lee Thomason624d43f2012-10-12 10:58:48 -07001086 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001087 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001088 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001089 }
1090 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001091}
1092
1093
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001094XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1095{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001096 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001097 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001098 }
1099 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1100 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001101}
1102
1103
1104bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1105{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001106 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001107 const XMLUnknown* unknown = compare->ToUnknown();
1108 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001109}
1110
1111
Lee Thomason50f97b22012-02-11 16:33:40 -08001112bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1113{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001114 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001115 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001116}
1117
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001118// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001119
1120const char* XMLAttribute::Name() const
1121{
1122 return _name.GetStr();
1123}
1124
1125const char* XMLAttribute::Value() const
1126{
1127 return _value.GetStr();
1128}
1129
Lee Thomason6f381b72012-03-02 12:59:39 -08001130char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001131{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001132 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001133 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001134 if ( !p || !*p ) {
1135 return 0;
1136 }
Lee Thomason22aead12012-01-23 13:29:35 -08001137
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001138 // Skip white space before =
1139 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001140 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001141 return 0;
1142 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001143
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001144 ++p; // move up to opening quote
1145 p = XMLUtil::SkipWhiteSpace( p );
1146 if ( *p != '\"' && *p != '\'' ) {
1147 return 0;
1148 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001149
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001150 char endTag[2] = { *p, 0 };
1151 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001152
Lee Thomason624d43f2012-10-12 10:58:48 -07001153 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001154 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001155}
1156
1157
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001158void XMLAttribute::SetName( const char* n )
1159{
Lee Thomason624d43f2012-10-12 10:58:48 -07001160 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001161}
1162
1163
Lee Thomason2fa81722012-11-09 12:37:46 -08001164XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001165{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001166 if ( XMLUtil::ToInt( Value(), value )) {
1167 return XML_NO_ERROR;
1168 }
1169 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001170}
1171
1172
Lee Thomason2fa81722012-11-09 12:37:46 -08001173XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001174{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001175 if ( XMLUtil::ToUnsigned( Value(), value )) {
1176 return XML_NO_ERROR;
1177 }
1178 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001179}
1180
1181
Lee Thomason2fa81722012-11-09 12:37:46 -08001182XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001183{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001184 if ( XMLUtil::ToBool( Value(), value )) {
1185 return XML_NO_ERROR;
1186 }
1187 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001188}
1189
1190
Lee Thomason2fa81722012-11-09 12:37:46 -08001191XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001192{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001193 if ( XMLUtil::ToFloat( Value(), value )) {
1194 return XML_NO_ERROR;
1195 }
1196 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001197}
1198
1199
Lee Thomason2fa81722012-11-09 12:37:46 -08001200XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001201{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001202 if ( XMLUtil::ToDouble( Value(), value )) {
1203 return XML_NO_ERROR;
1204 }
1205 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001206}
1207
1208
1209void XMLAttribute::SetAttribute( const char* v )
1210{
Lee Thomason624d43f2012-10-12 10:58:48 -07001211 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001212}
1213
1214
Lee Thomason1ff38e02012-02-14 18:18:16 -08001215void XMLAttribute::SetAttribute( int v )
1216{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001217 char buf[BUF_SIZE];
1218 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001219 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001220}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001221
1222
1223void XMLAttribute::SetAttribute( unsigned v )
1224{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001225 char buf[BUF_SIZE];
1226 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001227 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001228}
1229
1230
1231void XMLAttribute::SetAttribute( bool 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( double 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
1245void XMLAttribute::SetAttribute( float v )
1246{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001247 char buf[BUF_SIZE];
1248 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001249 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001250}
1251
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001252
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001253// --------- XMLElement ---------- //
1254XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001255 _closingType( 0 ),
1256 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001257{
1258}
1259
1260
1261XMLElement::~XMLElement()
1262{
Lee Thomason624d43f2012-10-12 10:58:48 -07001263 while( _rootAttribute ) {
1264 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001265 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001266 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001267 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001268}
1269
1270
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001271const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1272{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001273 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001274 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1275 return a;
1276 }
1277 }
1278 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001279}
1280
1281
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001282const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001283{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001284 const XMLAttribute* a = FindAttribute( name );
1285 if ( !a ) {
1286 return 0;
1287 }
1288 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1289 return a->Value();
1290 }
1291 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001292}
1293
1294
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001295const char* XMLElement::GetText() const
1296{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001297 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001298 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001299 }
1300 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001301}
1302
1303
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001304void XMLElement::SetText( const char* inText )
1305{
Uli Kusterer869bb592014-01-21 01:36:16 +01001306 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001307 FirstChild()->SetValue( inText );
1308 else {
1309 XMLText* theText = GetDocument()->NewText( inText );
1310 InsertFirstChild( theText );
1311 }
1312}
1313
Lee Thomason5bb2d802014-01-24 10:42:57 -08001314
1315void XMLElement::SetText( int v )
1316{
1317 char buf[BUF_SIZE];
1318 XMLUtil::ToStr( v, buf, BUF_SIZE );
1319 SetText( buf );
1320}
1321
1322
1323void XMLElement::SetText( unsigned v )
1324{
1325 char buf[BUF_SIZE];
1326 XMLUtil::ToStr( v, buf, BUF_SIZE );
1327 SetText( buf );
1328}
1329
1330
1331void XMLElement::SetText( bool v )
1332{
1333 char buf[BUF_SIZE];
1334 XMLUtil::ToStr( v, buf, BUF_SIZE );
1335 SetText( buf );
1336}
1337
1338
1339void XMLElement::SetText( float v )
1340{
1341 char buf[BUF_SIZE];
1342 XMLUtil::ToStr( v, buf, BUF_SIZE );
1343 SetText( buf );
1344}
1345
1346
1347void XMLElement::SetText( double v )
1348{
1349 char buf[BUF_SIZE];
1350 XMLUtil::ToStr( v, buf, BUF_SIZE );
1351 SetText( buf );
1352}
1353
1354
MortenMacFly4ee49f12013-01-14 20:03:14 +01001355XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001356{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001357 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001358 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001359 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001360 return XML_SUCCESS;
1361 }
1362 return XML_CAN_NOT_CONVERT_TEXT;
1363 }
1364 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001365}
1366
1367
MortenMacFly4ee49f12013-01-14 20:03:14 +01001368XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001369{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001370 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001371 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001372 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001373 return XML_SUCCESS;
1374 }
1375 return XML_CAN_NOT_CONVERT_TEXT;
1376 }
1377 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001378}
1379
1380
MortenMacFly4ee49f12013-01-14 20:03:14 +01001381XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001382{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001383 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001384 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001385 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001386 return XML_SUCCESS;
1387 }
1388 return XML_CAN_NOT_CONVERT_TEXT;
1389 }
1390 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001391}
1392
1393
MortenMacFly4ee49f12013-01-14 20:03:14 +01001394XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001395{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001396 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001397 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001398 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001399 return XML_SUCCESS;
1400 }
1401 return XML_CAN_NOT_CONVERT_TEXT;
1402 }
1403 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001404}
1405
1406
MortenMacFly4ee49f12013-01-14 20:03:14 +01001407XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001408{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001409 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001410 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001411 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001412 return XML_SUCCESS;
1413 }
1414 return XML_CAN_NOT_CONVERT_TEXT;
1415 }
1416 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001417}
1418
1419
1420
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001421XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1422{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001423 XMLAttribute* last = 0;
1424 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001425 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001426 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001427 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001428 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1429 break;
1430 }
1431 }
1432 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001433 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001434 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1435 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001436 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001437 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001438 }
1439 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001440 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001441 }
1442 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001443 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001444 }
1445 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001446}
1447
1448
U-Stream\Leeae25a442012-02-17 17:48:16 -08001449void XMLElement::DeleteAttribute( const char* name )
1450{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001451 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001452 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001453 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1454 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001455 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001456 }
1457 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001458 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001459 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001460 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001461 break;
1462 }
1463 prev = a;
1464 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001465}
1466
1467
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001468char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001469{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001470 const char* start = p;
1471 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001472
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001473 // Read the attributes.
1474 while( p ) {
1475 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001476 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001477 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001478 return 0;
1479 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001480
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001481 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001482 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001483 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001484 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1485 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001486 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001487
Lee Thomason624d43f2012-10-12 10:58:48 -07001488 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001489 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001490 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001491 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001492 return 0;
1493 }
1494 // There is a minor bug here: if the attribute in the source xml
1495 // document is duplicated, it will not be detected and the
1496 // attribute will be doubly added. However, tracking the 'prevAttribute'
1497 // avoids re-scanning the attribute list. Preferring performance for
1498 // now, may reconsider in the future.
1499 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001500 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001501 }
1502 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001503 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001504 }
1505 prevAttribute = attrib;
1506 }
1507 // end of the tag
1508 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001509 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001510 return p+2; // done; sealed element.
1511 }
1512 // end of the tag
1513 else if ( *p == '>' ) {
1514 ++p;
1515 break;
1516 }
1517 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001518 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001519 return 0;
1520 }
1521 }
1522 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001523}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001524
Dmitry-Mee3225b12014-09-03 11:03:11 +04001525void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1526{
1527 if ( attribute == 0 ) {
1528 return;
1529 }
1530 MemPool* pool = attribute->_memPool;
1531 attribute->~XMLAttribute();
1532 pool->Free( attribute );
1533}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001534
Lee Thomason67d61312012-01-24 16:01:51 -08001535//
1536// <ele></ele>
1537// <ele>foo<b>bar</b></ele>
1538//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001539char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001540{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001541 // Read the element name.
1542 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001543
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001544 // The closing element is the </element> form. It is
1545 // parsed just like a regular element then deleted from
1546 // the DOM.
1547 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001548 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001549 ++p;
1550 }
Lee Thomason67d61312012-01-24 16:01:51 -08001551
Lee Thomason624d43f2012-10-12 10:58:48 -07001552 p = _value.ParseName( p );
1553 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001554 return 0;
1555 }
Lee Thomason67d61312012-01-24 16:01:51 -08001556
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001557 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001558 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001559 return p;
1560 }
Lee Thomason67d61312012-01-24 16:01:51 -08001561
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001562 p = XMLNode::ParseDeep( p, strPair );
1563 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001564}
1565
1566
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001567
1568XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1569{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001570 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001571 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001572 }
1573 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1574 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1575 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1576 }
1577 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001578}
1579
1580
1581bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1582{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001583 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001584 const XMLElement* other = compare->ToElement();
1585 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001586
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001587 const XMLAttribute* a=FirstAttribute();
1588 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001589
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001590 while ( a && b ) {
1591 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1592 return false;
1593 }
1594 a = a->Next();
1595 b = b->Next();
1596 }
1597 if ( a || b ) {
1598 // different count
1599 return false;
1600 }
1601 return true;
1602 }
1603 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001604}
1605
1606
Lee Thomason751da522012-02-10 08:50:51 -08001607bool XMLElement::Accept( XMLVisitor* visitor ) const
1608{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001609 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001610 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001611 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1612 if ( !node->Accept( visitor ) ) {
1613 break;
1614 }
1615 }
1616 }
1617 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001618}
Lee Thomason56bdd022012-02-09 18:16:58 -08001619
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001620
Lee Thomason3f57d272012-01-11 15:30:03 -08001621// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001622
1623// Warning: List must match 'enum XMLError'
1624const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1625 "XML_SUCCESS",
1626 "XML_NO_ATTRIBUTE",
1627 "XML_WRONG_ATTRIBUTE_TYPE",
1628 "XML_ERROR_FILE_NOT_FOUND",
1629 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1630 "XML_ERROR_FILE_READ_ERROR",
1631 "XML_ERROR_ELEMENT_MISMATCH",
1632 "XML_ERROR_PARSING_ELEMENT",
1633 "XML_ERROR_PARSING_ATTRIBUTE",
1634 "XML_ERROR_IDENTIFYING_TAG",
1635 "XML_ERROR_PARSING_TEXT",
1636 "XML_ERROR_PARSING_CDATA",
1637 "XML_ERROR_PARSING_COMMENT",
1638 "XML_ERROR_PARSING_DECLARATION",
1639 "XML_ERROR_PARSING_UNKNOWN",
1640 "XML_ERROR_EMPTY_DOCUMENT",
1641 "XML_ERROR_MISMATCHED_ELEMENT",
1642 "XML_ERROR_PARSING",
1643 "XML_CAN_NOT_CONVERT_TEXT",
1644 "XML_NO_TEXT_NODE"
1645};
1646
1647
Lee Thomason624d43f2012-10-12 10:58:48 -07001648XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001649 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001650 _writeBOM( false ),
1651 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001652 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001653 _whitespace( whitespace ),
1654 _errorStr1( 0 ),
1655 _errorStr2( 0 ),
1656 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001657{
Lee Thomason624d43f2012-10-12 10:58:48 -07001658 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001659}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001660
1661
Lee Thomason3f57d272012-01-11 15:30:03 -08001662XMLDocument::~XMLDocument()
1663{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001664 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001665}
1666
1667
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001668void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001669{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001670 DeleteChildren();
1671
Dmitry-Meab37df82014-11-28 12:08:36 +03001672#ifdef DEBUG
1673 const bool hadError = Error();
1674#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001675 _errorID = XML_NO_ERROR;
1676 _errorStr1 = 0;
1677 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001678
Lee Thomason624d43f2012-10-12 10:58:48 -07001679 delete [] _charBuffer;
1680 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001681
1682#if 0
1683 _textPool.Trace( "text" );
1684 _elementPool.Trace( "element" );
1685 _commentPool.Trace( "comment" );
1686 _attributePool.Trace( "attribute" );
1687#endif
1688
1689#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001690 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001691 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1692 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1693 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1694 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1695 }
1696#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001697}
1698
Lee Thomason3f57d272012-01-11 15:30:03 -08001699
Lee Thomason2c85a712012-01-31 08:24:24 -08001700XMLElement* XMLDocument::NewElement( const char* name )
1701{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001702 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001703 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1704 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001705 ele->SetName( name );
1706 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001707}
1708
1709
Lee Thomason1ff38e02012-02-14 18:18:16 -08001710XMLComment* XMLDocument::NewComment( const char* str )
1711{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001712 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001713 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1714 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001715 comment->SetValue( str );
1716 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001717}
1718
1719
1720XMLText* XMLDocument::NewText( const char* str )
1721{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001722 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001723 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1724 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001725 text->SetValue( str );
1726 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001727}
1728
1729
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001730XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1731{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001732 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001733 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1734 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001735 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1736 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001737}
1738
1739
1740XMLUnknown* XMLDocument::NewUnknown( const char* str )
1741{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001742 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001743 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1744 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001745 unk->SetValue( str );
1746 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001747}
1748
Dmitry-Me01578db2014-08-19 10:18:48 +04001749static FILE* callfopen( const char* filepath, const char* mode )
1750{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001751 TIXMLASSERT( filepath );
1752 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001753#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1754 FILE* fp = 0;
1755 errno_t err = fopen_s( &fp, filepath, mode );
1756 if ( err ) {
1757 return 0;
1758 }
1759#else
1760 FILE* fp = fopen( filepath, mode );
1761#endif
1762 return fp;
1763}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001764
1765void XMLDocument::DeleteNode( XMLNode* node ) {
1766 TIXMLASSERT( node );
1767 TIXMLASSERT(node->_document == this );
1768 if (node->_parent) {
1769 node->_parent->DeleteChild( node );
1770 }
1771 else {
1772 // Isn't in the tree.
1773 // Use the parent delete.
1774 // Also, we need to mark it tracked: we 'know'
1775 // it was never used.
1776 node->_memPool->SetTracked();
1777 // Call the static XMLNode version:
1778 XMLNode::DeleteNode(node);
1779 }
1780}
1781
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001782
Lee Thomason2fa81722012-11-09 12:37:46 -08001783XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001784{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001785 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001786 FILE* fp = callfopen( filename, "rb" );
1787 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001788 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001789 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001790 }
1791 LoadFile( fp );
1792 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001793 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001794}
1795
1796
Lee Thomason2fa81722012-11-09 12:37:46 -08001797XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001798{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001799 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001800
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001801 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001802 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001803 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1804 return _errorID;
1805 }
1806
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001807 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001808 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001809 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001810 if ( filelength == -1L ) {
1811 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1812 return _errorID;
1813 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001814
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001815 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001816 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001817 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001818 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001819 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001820
Lee Thomason624d43f2012-10-12 10:58:48 -07001821 _charBuffer = new char[size+1];
1822 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001823 if ( read != size ) {
1824 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001825 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001826 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001827
Lee Thomason624d43f2012-10-12 10:58:48 -07001828 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001829
Lee Thomason624d43f2012-10-12 10:58:48 -07001830 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001831 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001832 p = XMLUtil::ReadBOM( p, &_writeBOM );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001833 if ( !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001834 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001835 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001836 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001837
Lee Thomason624d43f2012-10-12 10:58:48 -07001838 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1839 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001840}
1841
1842
Lee Thomason2fa81722012-11-09 12:37:46 -08001843XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001844{
Dmitry-Me01578db2014-08-19 10:18:48 +04001845 FILE* fp = callfopen( filename, "w" );
1846 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001847 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001848 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001849 }
1850 SaveFile(fp, compact);
1851 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001852 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001853}
1854
1855
Lee Thomason2fa81722012-11-09 12:37:46 -08001856XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001857{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001858 XMLPrinter stream( fp, compact );
1859 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001860 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001861}
1862
Lee Thomason1ff38e02012-02-14 18:18:16 -08001863
Lee Thomason2fa81722012-11-09 12:37:46 -08001864XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001865{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001866 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001867
Lee Thomason82d32002014-02-21 22:47:18 -08001868 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001869 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001870 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001871 }
1872 if ( len == (size_t)(-1) ) {
1873 len = strlen( p );
1874 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001875 _charBuffer = new char[ len+1 ];
1876 memcpy( _charBuffer, p, len );
1877 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001878
Dmitry-Me5b4a5162014-12-23 17:36:28 +03001879 const char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001880 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001881 p = XMLUtil::ReadBOM( p, &_writeBOM );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001882 if ( !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001883 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001884 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001885 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001886
Thomas Roß1470edc2013-05-10 15:44:12 +02001887 ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001888 ParseDeep( _charBuffer+delta, 0 );
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001889 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001890 // clean up now essentially dangling memory.
1891 // and the parse fail can put objects in the
1892 // pools that are dead and inaccessible.
1893 DeleteChildren();
1894 _elementPool.Clear();
1895 _attributePool.Clear();
1896 _textPool.Clear();
1897 _commentPool.Clear();
1898 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001899 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001900}
1901
1902
PKEuS1c5f99e2013-07-06 11:28:39 +02001903void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001904{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001905 XMLPrinter stdStreamer( stdout );
1906 if ( !streamer ) {
1907 streamer = &stdStreamer;
1908 }
1909 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001910}
1911
1912
Lee Thomason2fa81722012-11-09 12:37:46 -08001913void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001914{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001915 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07001916 _errorID = error;
1917 _errorStr1 = str1;
1918 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001919}
1920
Lee Thomason331596e2014-09-11 14:56:43 -07001921const char* XMLDocument::ErrorName() const
1922{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001923 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Lee Thomason331596e2014-09-11 14:56:43 -07001924 return _errorNames[_errorID];
1925}
Lee Thomason5cae8972012-01-24 18:03:07 -08001926
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001927void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001928{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001929 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001930 static const int LEN = 20;
1931 char buf1[LEN] = { 0 };
1932 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001933
Lee Thomason624d43f2012-10-12 10:58:48 -07001934 if ( _errorStr1 ) {
1935 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001936 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001937 if ( _errorStr2 ) {
1938 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001939 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001940
Lee Thomason331596e2014-09-11 14:56:43 -07001941 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
1942 _errorID, ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001943 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001944}
1945
1946
PKEuS1bfb9542013-08-04 13:51:17 +02001947XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001948 _elementJustOpened( false ),
1949 _firstElement( true ),
1950 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001951 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001952 _textDepth( -1 ),
1953 _processEntities( true ),
1954 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001955{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001956 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001957 _entityFlag[i] = false;
1958 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001959 }
1960 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03001961 const char entityValue = entities[i].value;
1962 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
1963 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001964 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03001965 _restrictedEntityFlag[(unsigned char)'&'] = true;
1966 _restrictedEntityFlag[(unsigned char)'<'] = true;
1967 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07001968 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001969}
1970
1971
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001972void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001973{
1974 va_list va;
1975 va_start( va, format );
1976
Lee Thomason624d43f2012-10-12 10:58:48 -07001977 if ( _fp ) {
1978 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001979 }
1980 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001981#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001982 #if defined(WINCE)
1983 int len = 512;
1984 do {
1985 len = len*2;
1986 char* str = new char[len]();
1987 len = _vsnprintf(str, len, format, va);
1988 delete[] str;
1989 }while (len < 0);
1990 #else
Thomas Roß268c6832014-03-13 23:35:16 +01001991 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08001992 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001993#else
1994 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01001995#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001996 // Close out and re-start the va-args
1997 va_end( va );
1998 va_start( va, format );
Lee Thomasona0744c82014-03-16 10:32:27 -07001999 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
2000#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08002001 #if defined(WINCE)
2002 _vsnprintf( p, len+1, format, va );
2003 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07002004 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08002005 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07002006#else
2007 vsnprintf( p, len+1, format, va );
2008#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002009 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002010 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002011}
2012
2013
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002014void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002015{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002016 for( int i=0; i<depth; ++i ) {
2017 Print( " " );
2018 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002019}
2020
2021
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002022void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002023{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002024 // Look for runs of bytes between entities to print.
2025 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07002026 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08002027
Lee Thomason624d43f2012-10-12 10:58:48 -07002028 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002029 while ( *q ) {
2030 // Remember, char is sometimes signed. (How many times has that bitten me?)
2031 if ( *q > 0 && *q < ENTITY_RANGE ) {
2032 // Check for entities. If one is found, flush
2033 // the stream up until the entity, write the
2034 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002035 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002036 while ( p < q ) {
2037 Print( "%c", *p );
2038 ++p;
2039 }
2040 for( int i=0; i<NUM_ENTITIES; ++i ) {
2041 if ( entities[i].value == *q ) {
2042 Print( "&%s;", entities[i].pattern );
2043 break;
2044 }
2045 }
2046 ++p;
2047 }
2048 }
2049 ++q;
2050 }
2051 }
2052 // Flush the remaining string. This will be the entire
2053 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07002054 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002055 Print( "%s", p );
2056 }
Lee Thomason857b8682012-01-25 17:50:25 -08002057}
2058
U-Stream\Leeae25a442012-02-17 17:48:16 -08002059
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002060void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002061{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002062 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002063 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 -07002064 Print( "%s", bom );
2065 }
2066 if ( writeDec ) {
2067 PushDeclaration( "xml version=\"1.0\"" );
2068 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002069}
2070
2071
Uli Kusterer593a33d2014-02-01 12:48:51 +01002072void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002073{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002074 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002075 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002076
Uli Kusterer593a33d2014-02-01 12:48:51 +01002077 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002078 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002079 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002080 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002081 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002082 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002083
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002084 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002085 _elementJustOpened = true;
2086 _firstElement = false;
2087 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002088}
2089
2090
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002091void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002092{
Lee Thomason624d43f2012-10-12 10:58:48 -07002093 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002094 Print( " %s=\"", name );
2095 PrintString( value, false );
2096 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002097}
2098
2099
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002100void XMLPrinter::PushAttribute( const char* name, int v )
2101{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002102 char buf[BUF_SIZE];
2103 XMLUtil::ToStr( v, buf, BUF_SIZE );
2104 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002105}
2106
2107
2108void XMLPrinter::PushAttribute( const char* name, unsigned v )
2109{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002110 char buf[BUF_SIZE];
2111 XMLUtil::ToStr( v, buf, BUF_SIZE );
2112 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002113}
2114
2115
2116void XMLPrinter::PushAttribute( const char* name, bool v )
2117{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002118 char buf[BUF_SIZE];
2119 XMLUtil::ToStr( v, buf, BUF_SIZE );
2120 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002121}
2122
2123
2124void XMLPrinter::PushAttribute( const char* name, double v )
2125{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002126 char buf[BUF_SIZE];
2127 XMLUtil::ToStr( v, buf, BUF_SIZE );
2128 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002129}
2130
2131
Uli Kustererca412e82014-02-01 13:35:05 +01002132void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002133{
Lee Thomason624d43f2012-10-12 10:58:48 -07002134 --_depth;
2135 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002136
Lee Thomason624d43f2012-10-12 10:58:48 -07002137 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002138 Print( "/>" );
2139 }
2140 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002141 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002142 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002143 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002144 }
2145 Print( "</%s>", name );
2146 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002147
Lee Thomason624d43f2012-10-12 10:58:48 -07002148 if ( _textDepth == _depth ) {
2149 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002150 }
Uli Kustererca412e82014-02-01 13:35:05 +01002151 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002152 Print( "\n" );
2153 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002154 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002155}
2156
2157
Dmitry-Mea092bc12014-12-23 17:57:05 +03002158void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002159{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002160 if ( !_elementJustOpened ) {
2161 return;
2162 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002163 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002164 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002165}
2166
2167
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002168void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002169{
Lee Thomason624d43f2012-10-12 10:58:48 -07002170 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002171
Dmitry-Mea092bc12014-12-23 17:57:05 +03002172 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002173 if ( cdata ) {
2174 Print( "<![CDATA[" );
2175 Print( "%s", text );
2176 Print( "]]>" );
2177 }
2178 else {
2179 PrintString( text, true );
2180 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002181}
2182
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002183void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002184{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002185 char buf[BUF_SIZE];
2186 XMLUtil::ToStr( value, buf, BUF_SIZE );
2187 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002188}
2189
2190
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002191void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002192{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002193 char buf[BUF_SIZE];
2194 XMLUtil::ToStr( value, buf, BUF_SIZE );
2195 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002196}
2197
2198
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002199void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002200{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002201 char buf[BUF_SIZE];
2202 XMLUtil::ToStr( value, buf, BUF_SIZE );
2203 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002204}
2205
2206
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002207void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002208{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002209 char buf[BUF_SIZE];
2210 XMLUtil::ToStr( value, buf, BUF_SIZE );
2211 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002212}
2213
2214
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002215void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002216{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002217 char buf[BUF_SIZE];
2218 XMLUtil::ToStr( value, buf, BUF_SIZE );
2219 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002220}
2221
Lee Thomason5cae8972012-01-24 18:03:07 -08002222
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002223void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002224{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002225 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002226 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002227 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002228 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002229 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002230 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002231 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002232}
Lee Thomason751da522012-02-10 08:50:51 -08002233
2234
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002235void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002236{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002237 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002238 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002239 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002240 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002241 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002242 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002243 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002244}
2245
2246
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002247void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002248{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002249 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002250 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002251 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002252 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002253 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002254 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002255 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002256}
2257
2258
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002259bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002260{
Lee Thomason624d43f2012-10-12 10:58:48 -07002261 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002262 if ( doc.HasBOM() ) {
2263 PushHeader( true, false );
2264 }
2265 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002266}
2267
2268
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002269bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002270{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002271 const XMLElement* parentElem = element.Parent()->ToElement();
2272 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2273 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002274 while ( attribute ) {
2275 PushAttribute( attribute->Name(), attribute->Value() );
2276 attribute = attribute->Next();
2277 }
2278 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002279}
2280
2281
Uli Kustererca412e82014-02-01 13:35:05 +01002282bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002283{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002284 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002285 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 XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002290{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002291 PushText( text.Value(), text.CData() );
2292 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002293}
2294
2295
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002296bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002297{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002298 PushComment( comment.Value() );
2299 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002300}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002301
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002302bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002303{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002304 PushDeclaration( declaration.Value() );
2305 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002306}
2307
2308
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002309bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002310{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002311 PushUnknown( unknown.Value() );
2312 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002313}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002314
Lee Thomason685b8952012-11-12 13:00:06 -08002315} // namespace tinyxml2
2316