blob: 4bb4d1fa9871879af64ce7e9ab9d19b1daeb5c0c [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
U-Lama\Lee560bd472011-12-28 19:42:49 -080024#include "tinyxml2.h"
25
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070026#include <new> // yes, this one new style header, is in the Android SDK.
Anton Indrawanf59e2d62014-11-18 20:50:42 +010027#if defined(ANDROID_NDK) || defined(__QNXNTO__)
Lee Thomasona9cf3f92012-10-11 16:56:51 -070028# include <stddef.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070029#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070030# include <cstddef>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070031#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080032
Lee Thomasone4422302012-01-20 17:59:50 -080033static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -080034static const char LF = LINE_FEED;
35static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
36static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -080037static const char SINGLE_QUOTE = '\'';
38static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -080039
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080040// Bunch of unicode info at:
41// http://www.unicode.org/faq/utf_bom.html
42// ef bb bf (Microsoft "lead bytes") - designates UTF-8
43
44static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
45static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
46static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080047
Kevin Wojniak04c22d22012-11-08 11:02:22 -080048namespace tinyxml2
49{
50
Lee Thomason8ee79892012-01-25 17:44:30 -080051struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -070052 const char* pattern;
53 int length;
54 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -080055};
56
57static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070058static const Entity entities[NUM_ENTITIES] = {
59 { "quot", 4, DOUBLE_QUOTE },
60 { "amp", 3, '&' },
61 { "apos", 4, SINGLE_QUOTE },
62 { "lt", 2, '<' },
63 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -080064};
65
Lee Thomasonfde6a752012-01-14 18:08:12 -080066
Lee Thomason1a1d4a72012-02-15 09:09:25 -080067StrPair::~StrPair()
68{
Lee Thomasona9cf3f92012-10-11 16:56:51 -070069 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -080070}
71
72
Lee Thomason29658802014-11-27 22:31:11 -080073void StrPair::TransferTo( StrPair* other )
Dmitry-Me08b40dd2014-11-10 11:17:21 +030074{
Lee Thomason29658802014-11-27 22:31:11 -080075 if ( this == other ) {
Dmitry-Me08b40dd2014-11-10 11:17:21 +030076 return;
77 }
78 // This in effect implements the assignment operator by "moving"
79 // ownership (as in auto_ptr).
80
Lee Thomason29658802014-11-27 22:31:11 -080081 TIXMLASSERT( other->_flags == 0 );
82 TIXMLASSERT( other->_start == 0 );
83 TIXMLASSERT( other->_end == 0 );
Dmitry-Me08b40dd2014-11-10 11:17:21 +030084
Lee Thomason29658802014-11-27 22:31:11 -080085 other->Reset();
Dmitry-Me08b40dd2014-11-10 11:17:21 +030086
Lee Thomason29658802014-11-27 22:31:11 -080087 other->_flags = _flags;
88 other->_start = _start;
89 other->_end = _end;
Dmitry-Me08b40dd2014-11-10 11:17:21 +030090
91 _flags = 0;
92 _start = 0;
93 _end = 0;
94}
95
Lee Thomason1a1d4a72012-02-15 09:09:25 -080096void StrPair::Reset()
97{
Lee Thomason120b3a62012-10-12 10:06:59 -070098 if ( _flags & NEEDS_DELETE ) {
99 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700100 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700101 _flags = 0;
102 _start = 0;
103 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800104}
105
106
107void StrPair::SetStr( const char* str, int flags )
108{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700109 Reset();
110 size_t len = strlen( str );
Lee Thomason120b3a62012-10-12 10:06:59 -0700111 _start = new char[ len+1 ];
112 memcpy( _start, str, len+1 );
113 _end = _start + len;
114 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800115}
116
117
118char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
119{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700120 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800121
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400122 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700123 char endChar = *endTag;
124 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800125
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700126 // Inner loop of text parsing.
127 while ( *p ) {
128 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
129 Set( start, p, strFlags );
130 return p + length;
131 }
132 ++p;
133 }
134 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800135}
136
137
138char* StrPair::ParseName( char* p )
139{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400140 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700141 return 0;
142 }
JayXonee525db2014-12-24 04:01:42 -0500143 if ( !XMLUtil::IsNameStartChar( *p ) ) {
144 return 0;
145 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800146
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400147 char* const start = p;
JayXonee525db2014-12-24 04:01:42 -0500148 ++p;
149 while ( *p && XMLUtil::IsNameChar( *p ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700150 ++p;
151 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800152
JayXonee525db2014-12-24 04:01:42 -0500153 Set( start, p, 0 );
154 return p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800155}
156
157
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700158void StrPair::CollapseWhitespace()
159{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400160 // Adjusting _start would cause undefined behavior on delete[]
161 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700162 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700163 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700164
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300165 if ( *_start ) {
Lee Thomason120b3a62012-10-12 10:06:59 -0700166 char* p = _start; // the read pointer
167 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700168
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700169 while( *p ) {
170 if ( XMLUtil::IsWhiteSpace( *p )) {
171 p = XMLUtil::SkipWhiteSpace( p );
172 if ( *p == 0 ) {
173 break; // don't write to q; this trims the trailing space.
174 }
175 *q = ' ';
176 ++q;
177 }
178 *q = *p;
179 ++q;
180 ++p;
181 }
182 *q = 0;
183 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700184}
185
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800186
Lee Thomasone4422302012-01-20 17:59:50 -0800187const char* StrPair::GetStr()
188{
Lee Thomason120b3a62012-10-12 10:06:59 -0700189 if ( _flags & NEEDS_FLUSH ) {
190 *_end = 0;
191 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800192
Lee Thomason120b3a62012-10-12 10:06:59 -0700193 if ( _flags ) {
194 char* p = _start; // the read pointer
195 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800196
Lee Thomason120b3a62012-10-12 10:06:59 -0700197 while( p < _end ) {
198 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700199 // CR-LF pair becomes LF
200 // CR alone becomes LF
201 // LF-CR becomes LF
202 if ( *(p+1) == LF ) {
203 p += 2;
204 }
205 else {
206 ++p;
207 }
208 *q++ = LF;
209 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700210 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700211 if ( *(p+1) == CR ) {
212 p += 2;
213 }
214 else {
215 ++p;
216 }
217 *q++ = LF;
218 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700219 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700220 // Entities handled by tinyXML2:
221 // - special entities in the entity table [in/out]
222 // - numeric character reference [in]
223 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800224
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700225 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400226 const int buflen = 10;
227 char buf[buflen] = { 0 };
228 int len = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700229 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
Dmitry-Me63f3de12014-08-21 12:33:19 +0400230 TIXMLASSERT( 0 <= len && len <= buflen );
231 TIXMLASSERT( q + len <= p );
232 memcpy( q, buf, len );
233 q += len;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700234 }
235 else {
236 int i=0;
237 for(; i<NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400238 const Entity& entity = entities[i];
239 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
240 && *( p + entity.length + 1 ) == ';' ) {
241 // Found an entity - convert.
242 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700243 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400244 p += entity.length + 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700245 break;
246 }
247 }
248 if ( i == NUM_ENTITIES ) {
249 // fixme: treat as error?
250 ++p;
251 ++q;
252 }
253 }
254 }
255 else {
256 *q = *p;
257 ++p;
258 ++q;
259 }
260 }
261 *q = 0;
262 }
263 // The loop below has plenty going on, and this
264 // is a less useful mode. Break it out.
Lee Thomason120b3a62012-10-12 10:06:59 -0700265 if ( _flags & COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700266 CollapseWhitespace();
267 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700268 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700269 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700270 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800271}
272
Lee Thomason2c85a712012-01-31 08:24:24 -0800273
Lee Thomasone4422302012-01-20 17:59:50 -0800274
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800275
Lee Thomason56bdd022012-02-09 18:16:58 -0800276// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800277
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800278const char* XMLUtil::ReadBOM( const char* p, bool* bom )
279{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300280 TIXMLASSERT( p );
281 TIXMLASSERT( bom );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700282 *bom = false;
283 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
284 // Check for BOM:
285 if ( *(pu+0) == TIXML_UTF_LEAD_0
286 && *(pu+1) == TIXML_UTF_LEAD_1
287 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
288 *bom = true;
289 p += 3;
290 }
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300291 TIXMLASSERT( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700292 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800293}
294
295
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800296void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
297{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700298 const unsigned long BYTE_MASK = 0xBF;
299 const unsigned long BYTE_MARK = 0x80;
300 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800301
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700302 if (input < 0x80) {
303 *length = 1;
304 }
305 else if ( input < 0x800 ) {
306 *length = 2;
307 }
308 else if ( input < 0x10000 ) {
309 *length = 3;
310 }
311 else if ( input < 0x200000 ) {
312 *length = 4;
313 }
314 else {
315 *length = 0; // This code won't covert this correctly anyway.
316 return;
317 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800318
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700319 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800320
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700321 // Scary scary fall throughs.
322 switch (*length) {
323 case 4:
324 --output;
325 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
326 input >>= 6;
327 case 3:
328 --output;
329 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
330 input >>= 6;
331 case 2:
332 --output;
333 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
334 input >>= 6;
335 case 1:
336 --output;
337 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100338 default:
339 break;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700340 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800341}
342
343
344const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
345{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700346 // Presume an entity, and pull it out.
347 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800348
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700349 if ( *(p+1) == '#' && *(p+2) ) {
350 unsigned long ucs = 0;
351 ptrdiff_t delta = 0;
352 unsigned mult = 1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800353
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700354 if ( *(p+2) == 'x' ) {
355 // Hexadecimal.
356 if ( !*(p+3) ) {
357 return 0;
358 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800359
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700360 const char* q = p+3;
361 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800362
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700363 if ( !q || !*q ) {
364 return 0;
365 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800366
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700367 delta = q-p;
368 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800369
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700370 while ( *q != 'x' ) {
371 if ( *q >= '0' && *q <= '9' ) {
372 ucs += mult * (*q - '0');
373 }
374 else if ( *q >= 'a' && *q <= 'f' ) {
375 ucs += mult * (*q - 'a' + 10);
376 }
377 else if ( *q >= 'A' && *q <= 'F' ) {
378 ucs += mult * (*q - 'A' + 10 );
379 }
380 else {
381 return 0;
382 }
383 mult *= 16;
384 --q;
385 }
386 }
387 else {
388 // Decimal.
389 if ( !*(p+2) ) {
390 return 0;
391 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800392
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700393 const char* q = p+2;
394 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800395
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700396 if ( !q || !*q ) {
397 return 0;
398 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800399
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700400 delta = q-p;
401 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800402
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700403 while ( *q != '#' ) {
404 if ( *q >= '0' && *q <= '9' ) {
405 ucs += mult * (*q - '0');
406 }
407 else {
408 return 0;
409 }
410 mult *= 10;
411 --q;
412 }
413 }
414 // convert the UCS to UTF-8
415 ConvertUTF32ToUTF8( ucs, value, length );
416 return p + delta + 1;
417 }
418 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800419}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800420
421
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700422void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700423{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700424 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700425}
426
427
428void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
429{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700430 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700431}
432
433
434void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
435{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700436 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700437}
438
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800439/*
440 ToStr() of a number is a very tricky topic.
441 https://github.com/leethomason/tinyxml2/issues/106
442*/
Lee Thomason21be8822012-07-15 17:27:22 -0700443void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
444{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800445 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700446}
447
448
449void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
450{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800451 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700452}
453
454
455bool XMLUtil::ToInt( const char* str, int* value )
456{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700457 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
458 return true;
459 }
460 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700461}
462
463bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
464{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700465 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
466 return true;
467 }
468 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700469}
470
471bool XMLUtil::ToBool( const char* str, bool* value )
472{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700473 int ival = 0;
474 if ( ToInt( str, &ival )) {
475 *value = (ival==0) ? false : true;
476 return true;
477 }
478 if ( StringEqual( str, "true" ) ) {
479 *value = true;
480 return true;
481 }
482 else if ( StringEqual( str, "false" ) ) {
483 *value = false;
484 return true;
485 }
486 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700487}
488
489
490bool XMLUtil::ToFloat( const char* str, float* value )
491{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700492 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
493 return true;
494 }
495 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700496}
497
498bool XMLUtil::ToDouble( const char* str, double* value )
499{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700500 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
501 return true;
502 }
503 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700504}
505
506
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700507char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800508{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400509 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700510 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300511 if( !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700512 return p;
513 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800514
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700515 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800516 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700517 static const char* xmlHeader = { "<?" };
518 static const char* commentHeader = { "<!--" };
519 static const char* dtdHeader = { "<!" };
520 static const char* cdataHeader = { "<![CDATA[" };
521 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800522
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700523 static const int xmlHeaderLen = 2;
524 static const int commentHeaderLen = 4;
525 static const int dtdHeaderLen = 2;
526 static const int cdataHeaderLen = 9;
527 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800528
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700529 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
530 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400531 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700532 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300533 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700534 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
535 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700536 p += xmlHeaderLen;
537 }
538 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300539 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700540 returnNode = new (_commentPool.Alloc()) XMLComment( this );
541 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700542 p += commentHeaderLen;
543 }
544 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300545 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700546 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700547 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700548 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700549 p += cdataHeaderLen;
550 text->SetCData( true );
551 }
552 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300553 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700554 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
555 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700556 p += dtdHeaderLen;
557 }
558 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300559 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700560 returnNode = new (_elementPool.Alloc()) XMLElement( this );
561 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700562 p += elementHeaderLen;
563 }
564 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300565 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700566 returnNode = new (_textPool.Alloc()) XMLText( this );
567 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700568 p = start; // Back it up, all the text counts.
569 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800570
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700571 *node = returnNode;
572 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800573}
574
575
Lee Thomason751da522012-02-10 08:50:51 -0800576bool XMLDocument::Accept( XMLVisitor* visitor ) const
577{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700578 if ( visitor->VisitEnter( *this ) ) {
579 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
580 if ( !node->Accept( visitor ) ) {
581 break;
582 }
583 }
584 }
585 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800586}
Lee Thomason56bdd022012-02-09 18:16:58 -0800587
588
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800589// --------- XMLNode ----------- //
590
591XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700592 _document( doc ),
593 _parent( 0 ),
594 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200595 _prev( 0 ), _next( 0 ),
596 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800597{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800598}
599
600
601XMLNode::~XMLNode()
602{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700603 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700604 if ( _parent ) {
605 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700606 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800607}
608
Michael Daumling21626882013-10-22 17:03:37 +0200609const char* XMLNode::Value() const
610{
611 return _value.GetStr();
612}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800613
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800614void XMLNode::SetValue( const char* str, bool staticMem )
615{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700616 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700617 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700618 }
619 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700620 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700621 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800622}
623
624
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800625void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800626{
Lee Thomason624d43f2012-10-12 10:58:48 -0700627 while( _firstChild ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300628 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700629 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700630 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700631
Dmitry-Mee3225b12014-09-03 11:03:11 +0400632 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700633 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700634 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800635}
636
637
638void XMLNode::Unlink( XMLNode* child )
639{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300640 TIXMLASSERT( child );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300641 TIXMLASSERT( child->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700642 if ( child == _firstChild ) {
643 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700644 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700645 if ( child == _lastChild ) {
646 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700647 }
Lee Thomasond923c672012-01-23 08:44:25 -0800648
Lee Thomason624d43f2012-10-12 10:58:48 -0700649 if ( child->_prev ) {
650 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700651 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700652 if ( child->_next ) {
653 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700654 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700655 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800656}
657
658
U-Stream\Leeae25a442012-02-17 17:48:16 -0800659void XMLNode::DeleteChild( XMLNode* node )
660{
Dmitry-Mebb836dc2014-12-24 11:54:05 +0300661 TIXMLASSERT( node );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300662 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700663 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400664 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800665}
666
667
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800668XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
669{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300670 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300671 if ( addThis->_document != _document ) {
672 TIXMLASSERT( false );
673 return 0;
674 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700675
Michael Daumlinged523282013-10-23 07:47:29 +0200676 if (addThis->_parent)
677 addThis->_parent->Unlink( addThis );
678 else
679 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700680
Lee Thomason624d43f2012-10-12 10:58:48 -0700681 if ( _lastChild ) {
682 TIXMLASSERT( _firstChild );
683 TIXMLASSERT( _lastChild->_next == 0 );
684 _lastChild->_next = addThis;
685 addThis->_prev = _lastChild;
686 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800687
Lee Thomason624d43f2012-10-12 10:58:48 -0700688 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700689 }
690 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700691 TIXMLASSERT( _firstChild == 0 );
692 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800693
Lee Thomason624d43f2012-10-12 10:58:48 -0700694 addThis->_prev = 0;
695 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700696 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700697 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700698 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800699}
700
701
Lee Thomason1ff38e02012-02-14 18:18:16 -0800702XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
703{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300704 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300705 if ( addThis->_document != _document ) {
706 TIXMLASSERT( false );
707 return 0;
708 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700709
Michael Daumlinged523282013-10-23 07:47:29 +0200710 if (addThis->_parent)
711 addThis->_parent->Unlink( addThis );
712 else
713 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700714
Lee Thomason624d43f2012-10-12 10:58:48 -0700715 if ( _firstChild ) {
716 TIXMLASSERT( _lastChild );
717 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800718
Lee Thomason624d43f2012-10-12 10:58:48 -0700719 _firstChild->_prev = addThis;
720 addThis->_next = _firstChild;
721 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800722
Lee Thomason624d43f2012-10-12 10:58:48 -0700723 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700724 }
725 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700726 TIXMLASSERT( _lastChild == 0 );
727 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800728
Lee Thomason624d43f2012-10-12 10:58:48 -0700729 addThis->_prev = 0;
730 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700731 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700732 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400733 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800734}
735
736
737XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
738{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300739 TIXMLASSERT( addThis );
740 if ( addThis->_document != _document ) {
741 TIXMLASSERT( false );
742 return 0;
743 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700744
Dmitry-Meabb2d042014-12-09 12:59:31 +0300745 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700746
Lee Thomason624d43f2012-10-12 10:58:48 -0700747 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300748 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700749 return 0;
750 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800751
Lee Thomason624d43f2012-10-12 10:58:48 -0700752 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700753 // The last node or the only node.
754 return InsertEndChild( addThis );
755 }
Michael Daumlinged523282013-10-23 07:47:29 +0200756 if (addThis->_parent)
757 addThis->_parent->Unlink( addThis );
758 else
759 addThis->_memPool->SetTracked();
Lee Thomason624d43f2012-10-12 10:58:48 -0700760 addThis->_prev = afterThis;
761 addThis->_next = afterThis->_next;
762 afterThis->_next->_prev = addThis;
763 afterThis->_next = addThis;
764 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700765 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800766}
767
768
769
770
Lee Thomason56bdd022012-02-09 18:16:58 -0800771const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800772{
Lee Thomason624d43f2012-10-12 10:58:48 -0700773 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700774 XMLElement* element = node->ToElement();
775 if ( element ) {
776 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
777 return element;
778 }
779 }
780 }
781 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800782}
783
784
Lee Thomason56bdd022012-02-09 18:16:58 -0800785const XMLElement* XMLNode::LastChildElement( const char* value ) const
786{
Lee Thomason624d43f2012-10-12 10:58:48 -0700787 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700788 XMLElement* element = node->ToElement();
789 if ( element ) {
790 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
791 return element;
792 }
793 }
794 }
795 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800796}
797
798
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800799const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
800{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400801 for( XMLNode* node=this->_next; node; node = node->_next ) {
802 const XMLElement* element = node->ToElement();
803 if ( element
804 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
805 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700806 }
807 }
808 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800809}
810
811
812const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
813{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400814 for( XMLNode* node=_prev; node; node = node->_prev ) {
815 const XMLElement* element = node->ToElement();
816 if ( element
817 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
818 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700819 }
820 }
821 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800822}
823
824
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800825char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800826{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700827 // This is a recursive method, but thinking about it "at the current level"
828 // it is a pretty simple flat list:
829 // <foo/>
830 // <!-- comment -->
831 //
832 // With a special case:
833 // <foo>
834 // </foo>
835 // <!-- comment -->
836 //
837 // Where the closing element (/foo) *must* be the next thing after the opening
838 // element, and the names must match. BUT the tricky bit is that the closing
839 // element will be read by the child.
840 //
841 // 'endTag' is the end tag for this node, it is returned by a call to a child.
842 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800843
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700844 while( p && *p ) {
845 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800846
Lee Thomason624d43f2012-10-12 10:58:48 -0700847 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700848 if ( p == 0 || node == 0 ) {
849 break;
850 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800851
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700852 StrPair endTag;
853 p = node->ParseDeep( p, &endTag );
854 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400855 DeleteNode( node );
Lee Thomason624d43f2012-10-12 10:58:48 -0700856 if ( !_document->Error() ) {
857 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700858 }
859 break;
860 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800861
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400862 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700863 // We read the end tag. Return it to the parent.
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400864 if ( ele && ele->ClosingType() == XMLElement::CLOSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700865 if ( parentEnd ) {
Lee Thomason29658802014-11-27 22:31:11 -0800866 ele->_value.TransferTo( parentEnd );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700867 }
Lee Thomason5b0a6772012-11-19 13:54:42 -0800868 node->_memPool->SetTracked(); // created and then immediately deleted.
Dmitry-Mee3225b12014-09-03 11:03:11 +0400869 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700870 return p;
871 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800872
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700873 // Handle an end tag returned to this level.
874 // And handle a bunch of annoying errors.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700875 if ( ele ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400876 bool mismatch = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700877 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400878 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700879 }
880 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400881 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700882 }
883 else if ( !endTag.Empty() ) {
884 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400885 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700886 }
887 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400888 if ( mismatch ) {
889 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
JayXondbfdd8f2014-12-12 20:07:14 -0500890 DeleteNode( node );
891 break;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400892 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700893 }
JayXondbfdd8f2014-12-12 20:07:14 -0500894 InsertEndChild( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700895 }
896 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800897}
898
Dmitry-Mee3225b12014-09-03 11:03:11 +0400899void XMLNode::DeleteNode( XMLNode* node )
900{
901 if ( node == 0 ) {
902 return;
903 }
904 MemPool* pool = node->_memPool;
905 node->~XMLNode();
906 pool->Free( node );
907}
908
Lee Thomason5492a1c2012-01-23 15:32:10 -0800909// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800910char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800911{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700912 const char* start = p;
913 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700914 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700915 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700916 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700917 }
918 return p;
919 }
920 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700921 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
922 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700923 flags |= StrPair::COLLAPSE_WHITESPACE;
924 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700925
Lee Thomason624d43f2012-10-12 10:58:48 -0700926 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700927 if ( p && *p ) {
928 return p-1;
Dmitry-Me7a7e5dc2015-01-01 17:58:35 +0300929 } else if ( !p ) {
930 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700931 }
932 }
933 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800934}
935
936
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800937XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
938{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700939 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700940 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700941 }
942 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
943 text->SetCData( this->CData() );
944 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800945}
946
947
948bool XMLText::ShallowEqual( const XMLNode* compare ) const
949{
Dmitry-Me6d202ff2014-09-26 14:21:00 +0400950 const XMLText* text = compare->ToText();
951 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800952}
953
954
Lee Thomason56bdd022012-02-09 18:16:58 -0800955bool XMLText::Accept( XMLVisitor* visitor ) const
956{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300957 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700958 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800959}
960
961
Lee Thomason3f57d272012-01-11 15:30:03 -0800962// --------- XMLComment ---------- //
963
Lee Thomasone4422302012-01-20 17:59:50 -0800964XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800965{
966}
967
968
Lee Thomasonce0763e2012-01-11 15:43:54 -0800969XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800970{
Lee Thomason3f57d272012-01-11 15:30:03 -0800971}
972
973
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800974char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800975{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700976 // Comment parses as text.
977 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700978 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700979 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700980 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700981 }
982 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800983}
984
985
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800986XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
987{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700988 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700989 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700990 }
991 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
992 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800993}
994
995
996bool XMLComment::ShallowEqual( const XMLNode* compare ) const
997{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300998 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400999 const XMLComment* comment = compare->ToComment();
1000 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001001}
1002
1003
Lee Thomason751da522012-02-10 08:50:51 -08001004bool XMLComment::Accept( XMLVisitor* visitor ) const
1005{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001006 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001007 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001008}
Lee Thomason56bdd022012-02-09 18:16:58 -08001009
1010
Lee Thomason50f97b22012-02-11 16:33:40 -08001011// --------- XMLDeclaration ---------- //
1012
1013XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1014{
1015}
1016
1017
1018XMLDeclaration::~XMLDeclaration()
1019{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001020 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001021}
1022
1023
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001024char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001025{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001026 // Declaration parses as text.
1027 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001028 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001029 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001030 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001031 }
1032 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001033}
1034
1035
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001036XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1037{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001038 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001039 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001040 }
1041 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1042 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001043}
1044
1045
1046bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1047{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001048 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001049 const XMLDeclaration* declaration = compare->ToDeclaration();
1050 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001051}
1052
1053
1054
Lee Thomason50f97b22012-02-11 16:33:40 -08001055bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1056{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001057 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001058 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001059}
1060
1061// --------- XMLUnknown ---------- //
1062
1063XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1064{
1065}
1066
1067
1068XMLUnknown::~XMLUnknown()
1069{
1070}
1071
1072
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001073char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001074{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001075 // Unknown parses as text.
1076 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001077
Lee Thomason624d43f2012-10-12 10:58:48 -07001078 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001079 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001080 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001081 }
1082 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001083}
1084
1085
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001086XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1087{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001088 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001089 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001090 }
1091 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1092 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001093}
1094
1095
1096bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1097{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001098 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001099 const XMLUnknown* unknown = compare->ToUnknown();
1100 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001101}
1102
1103
Lee Thomason50f97b22012-02-11 16:33:40 -08001104bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1105{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001106 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001107 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001108}
1109
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001110// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001111
1112const char* XMLAttribute::Name() const
1113{
1114 return _name.GetStr();
1115}
1116
1117const char* XMLAttribute::Value() const
1118{
1119 return _value.GetStr();
1120}
1121
Lee Thomason6f381b72012-03-02 12:59:39 -08001122char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001123{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001124 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001125 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001126 if ( !p || !*p ) {
1127 return 0;
1128 }
Lee Thomason22aead12012-01-23 13:29:35 -08001129
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001130 // Skip white space before =
1131 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001132 if ( *p != '=' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001133 return 0;
1134 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001135
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001136 ++p; // move up to opening quote
1137 p = XMLUtil::SkipWhiteSpace( p );
1138 if ( *p != '\"' && *p != '\'' ) {
1139 return 0;
1140 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001141
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001142 char endTag[2] = { *p, 0 };
1143 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001144
Lee Thomason624d43f2012-10-12 10:58:48 -07001145 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001146 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001147}
1148
1149
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001150void XMLAttribute::SetName( const char* n )
1151{
Lee Thomason624d43f2012-10-12 10:58:48 -07001152 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001153}
1154
1155
Lee Thomason2fa81722012-11-09 12:37:46 -08001156XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001157{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001158 if ( XMLUtil::ToInt( Value(), value )) {
1159 return XML_NO_ERROR;
1160 }
1161 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001162}
1163
1164
Lee Thomason2fa81722012-11-09 12:37:46 -08001165XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001166{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001167 if ( XMLUtil::ToUnsigned( Value(), value )) {
1168 return XML_NO_ERROR;
1169 }
1170 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001171}
1172
1173
Lee Thomason2fa81722012-11-09 12:37:46 -08001174XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001175{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001176 if ( XMLUtil::ToBool( Value(), value )) {
1177 return XML_NO_ERROR;
1178 }
1179 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001180}
1181
1182
Lee Thomason2fa81722012-11-09 12:37:46 -08001183XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001184{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001185 if ( XMLUtil::ToFloat( Value(), value )) {
1186 return XML_NO_ERROR;
1187 }
1188 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001189}
1190
1191
Lee Thomason2fa81722012-11-09 12:37:46 -08001192XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001193{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001194 if ( XMLUtil::ToDouble( Value(), value )) {
1195 return XML_NO_ERROR;
1196 }
1197 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001198}
1199
1200
1201void XMLAttribute::SetAttribute( const char* v )
1202{
Lee Thomason624d43f2012-10-12 10:58:48 -07001203 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001204}
1205
1206
Lee Thomason1ff38e02012-02-14 18:18:16 -08001207void XMLAttribute::SetAttribute( int v )
1208{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001209 char buf[BUF_SIZE];
1210 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001211 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001212}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001213
1214
1215void XMLAttribute::SetAttribute( unsigned 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 Thomason1a1d4a72012-02-15 09:09:25 -08001220}
1221
1222
1223void XMLAttribute::SetAttribute( bool 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
1230void XMLAttribute::SetAttribute( double v )
1231{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001232 char buf[BUF_SIZE];
1233 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001234 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001235}
1236
1237void XMLAttribute::SetAttribute( float v )
1238{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001239 char buf[BUF_SIZE];
1240 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001241 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001242}
1243
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001244
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001245// --------- XMLElement ---------- //
1246XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001247 _closingType( 0 ),
1248 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001249{
1250}
1251
1252
1253XMLElement::~XMLElement()
1254{
Lee Thomason624d43f2012-10-12 10:58:48 -07001255 while( _rootAttribute ) {
1256 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001257 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001258 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001259 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001260}
1261
1262
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001263const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1264{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001265 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001266 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1267 return a;
1268 }
1269 }
1270 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001271}
1272
1273
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001274const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001275{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001276 const XMLAttribute* a = FindAttribute( name );
1277 if ( !a ) {
1278 return 0;
1279 }
1280 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1281 return a->Value();
1282 }
1283 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001284}
1285
1286
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001287const char* XMLElement::GetText() const
1288{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001289 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001290 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001291 }
1292 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001293}
1294
1295
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001296void XMLElement::SetText( const char* inText )
1297{
Uli Kusterer869bb592014-01-21 01:36:16 +01001298 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001299 FirstChild()->SetValue( inText );
1300 else {
1301 XMLText* theText = GetDocument()->NewText( inText );
1302 InsertFirstChild( theText );
1303 }
1304}
1305
Lee Thomason5bb2d802014-01-24 10:42:57 -08001306
1307void XMLElement::SetText( int v )
1308{
1309 char buf[BUF_SIZE];
1310 XMLUtil::ToStr( v, buf, BUF_SIZE );
1311 SetText( buf );
1312}
1313
1314
1315void XMLElement::SetText( unsigned v )
1316{
1317 char buf[BUF_SIZE];
1318 XMLUtil::ToStr( v, buf, BUF_SIZE );
1319 SetText( buf );
1320}
1321
1322
1323void XMLElement::SetText( bool v )
1324{
1325 char buf[BUF_SIZE];
1326 XMLUtil::ToStr( v, buf, BUF_SIZE );
1327 SetText( buf );
1328}
1329
1330
1331void XMLElement::SetText( float v )
1332{
1333 char buf[BUF_SIZE];
1334 XMLUtil::ToStr( v, buf, BUF_SIZE );
1335 SetText( buf );
1336}
1337
1338
1339void XMLElement::SetText( double v )
1340{
1341 char buf[BUF_SIZE];
1342 XMLUtil::ToStr( v, buf, BUF_SIZE );
1343 SetText( buf );
1344}
1345
1346
MortenMacFly4ee49f12013-01-14 20:03:14 +01001347XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001348{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001349 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001350 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001351 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001352 return XML_SUCCESS;
1353 }
1354 return XML_CAN_NOT_CONVERT_TEXT;
1355 }
1356 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001357}
1358
1359
MortenMacFly4ee49f12013-01-14 20:03:14 +01001360XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001361{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001362 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001363 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001364 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001365 return XML_SUCCESS;
1366 }
1367 return XML_CAN_NOT_CONVERT_TEXT;
1368 }
1369 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001370}
1371
1372
MortenMacFly4ee49f12013-01-14 20:03:14 +01001373XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001374{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001375 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001376 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001377 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001378 return XML_SUCCESS;
1379 }
1380 return XML_CAN_NOT_CONVERT_TEXT;
1381 }
1382 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001383}
1384
1385
MortenMacFly4ee49f12013-01-14 20:03:14 +01001386XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001387{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001388 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001389 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001390 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001391 return XML_SUCCESS;
1392 }
1393 return XML_CAN_NOT_CONVERT_TEXT;
1394 }
1395 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001396}
1397
1398
MortenMacFly4ee49f12013-01-14 20:03:14 +01001399XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001400{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001401 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001402 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001403 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001404 return XML_SUCCESS;
1405 }
1406 return XML_CAN_NOT_CONVERT_TEXT;
1407 }
1408 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001409}
1410
1411
1412
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001413XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1414{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001415 XMLAttribute* last = 0;
1416 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001417 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001418 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001419 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001420 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1421 break;
1422 }
1423 }
1424 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001425 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001426 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1427 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001428 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001429 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001430 }
1431 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001432 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001433 }
1434 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001435 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001436 }
1437 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001438}
1439
1440
U-Stream\Leeae25a442012-02-17 17:48:16 -08001441void XMLElement::DeleteAttribute( const char* name )
1442{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001443 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001444 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001445 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1446 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001447 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001448 }
1449 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001450 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001451 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001452 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001453 break;
1454 }
1455 prev = a;
1456 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001457}
1458
1459
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001460char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001461{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001462 const char* start = p;
1463 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001464
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001465 // Read the attributes.
1466 while( p ) {
1467 p = XMLUtil::SkipWhiteSpace( p );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001468 if ( !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001469 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001470 return 0;
1471 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001472
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001473 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001474 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001475 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001476 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1477 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001478 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001479
Lee Thomason624d43f2012-10-12 10:58:48 -07001480 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001481 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001482 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001483 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001484 return 0;
1485 }
1486 // There is a minor bug here: if the attribute in the source xml
1487 // document is duplicated, it will not be detected and the
1488 // attribute will be doubly added. However, tracking the 'prevAttribute'
1489 // avoids re-scanning the attribute list. Preferring performance for
1490 // now, may reconsider in the future.
1491 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001492 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001493 }
1494 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001495 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001496 }
1497 prevAttribute = attrib;
1498 }
1499 // end of the tag
1500 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001501 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001502 return p+2; // done; sealed element.
1503 }
1504 // end of the tag
1505 else if ( *p == '>' ) {
1506 ++p;
1507 break;
1508 }
1509 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001510 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001511 return 0;
1512 }
1513 }
1514 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001515}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001516
Dmitry-Mee3225b12014-09-03 11:03:11 +04001517void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1518{
1519 if ( attribute == 0 ) {
1520 return;
1521 }
1522 MemPool* pool = attribute->_memPool;
1523 attribute->~XMLAttribute();
1524 pool->Free( attribute );
1525}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001526
Lee Thomason67d61312012-01-24 16:01:51 -08001527//
1528// <ele></ele>
1529// <ele>foo<b>bar</b></ele>
1530//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001531char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001532{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001533 // Read the element name.
1534 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason67d61312012-01-24 16:01:51 -08001535
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001536 // The closing element is the </element> form. It is
1537 // parsed just like a regular element then deleted from
1538 // the DOM.
1539 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001540 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001541 ++p;
1542 }
Lee Thomason67d61312012-01-24 16:01:51 -08001543
Lee Thomason624d43f2012-10-12 10:58:48 -07001544 p = _value.ParseName( p );
1545 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001546 return 0;
1547 }
Lee Thomason67d61312012-01-24 16:01:51 -08001548
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001549 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001550 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001551 return p;
1552 }
Lee Thomason67d61312012-01-24 16:01:51 -08001553
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001554 p = XMLNode::ParseDeep( p, strPair );
1555 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001556}
1557
1558
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001559
1560XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1561{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001562 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001563 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001564 }
1565 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1566 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1567 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1568 }
1569 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001570}
1571
1572
1573bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1574{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001575 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001576 const XMLElement* other = compare->ToElement();
1577 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001578
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001579 const XMLAttribute* a=FirstAttribute();
1580 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001581
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001582 while ( a && b ) {
1583 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1584 return false;
1585 }
1586 a = a->Next();
1587 b = b->Next();
1588 }
1589 if ( a || b ) {
1590 // different count
1591 return false;
1592 }
1593 return true;
1594 }
1595 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001596}
1597
1598
Lee Thomason751da522012-02-10 08:50:51 -08001599bool XMLElement::Accept( XMLVisitor* visitor ) const
1600{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001601 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001602 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001603 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1604 if ( !node->Accept( visitor ) ) {
1605 break;
1606 }
1607 }
1608 }
1609 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001610}
Lee Thomason56bdd022012-02-09 18:16:58 -08001611
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001612
Lee Thomason3f57d272012-01-11 15:30:03 -08001613// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001614
1615// Warning: List must match 'enum XMLError'
1616const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1617 "XML_SUCCESS",
1618 "XML_NO_ATTRIBUTE",
1619 "XML_WRONG_ATTRIBUTE_TYPE",
1620 "XML_ERROR_FILE_NOT_FOUND",
1621 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1622 "XML_ERROR_FILE_READ_ERROR",
1623 "XML_ERROR_ELEMENT_MISMATCH",
1624 "XML_ERROR_PARSING_ELEMENT",
1625 "XML_ERROR_PARSING_ATTRIBUTE",
1626 "XML_ERROR_IDENTIFYING_TAG",
1627 "XML_ERROR_PARSING_TEXT",
1628 "XML_ERROR_PARSING_CDATA",
1629 "XML_ERROR_PARSING_COMMENT",
1630 "XML_ERROR_PARSING_DECLARATION",
1631 "XML_ERROR_PARSING_UNKNOWN",
1632 "XML_ERROR_EMPTY_DOCUMENT",
1633 "XML_ERROR_MISMATCHED_ELEMENT",
1634 "XML_ERROR_PARSING",
1635 "XML_CAN_NOT_CONVERT_TEXT",
1636 "XML_NO_TEXT_NODE"
1637};
1638
1639
Lee Thomason624d43f2012-10-12 10:58:48 -07001640XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001641 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001642 _writeBOM( false ),
1643 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001644 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001645 _whitespace( whitespace ),
1646 _errorStr1( 0 ),
1647 _errorStr2( 0 ),
1648 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001649{
Lee Thomason624d43f2012-10-12 10:58:48 -07001650 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001651}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001652
1653
Lee Thomason3f57d272012-01-11 15:30:03 -08001654XMLDocument::~XMLDocument()
1655{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001656 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001657}
1658
1659
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001660void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001661{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001662 DeleteChildren();
1663
Dmitry-Meab37df82014-11-28 12:08:36 +03001664#ifdef DEBUG
1665 const bool hadError = Error();
1666#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001667 _errorID = XML_NO_ERROR;
1668 _errorStr1 = 0;
1669 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001670
Lee Thomason624d43f2012-10-12 10:58:48 -07001671 delete [] _charBuffer;
1672 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001673
1674#if 0
1675 _textPool.Trace( "text" );
1676 _elementPool.Trace( "element" );
1677 _commentPool.Trace( "comment" );
1678 _attributePool.Trace( "attribute" );
1679#endif
1680
1681#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001682 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001683 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1684 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1685 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1686 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1687 }
1688#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001689}
1690
Lee Thomason3f57d272012-01-11 15:30:03 -08001691
Lee Thomason2c85a712012-01-31 08:24:24 -08001692XMLElement* XMLDocument::NewElement( const char* name )
1693{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001694 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001695 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1696 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001697 ele->SetName( name );
1698 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001699}
1700
1701
Lee Thomason1ff38e02012-02-14 18:18:16 -08001702XMLComment* XMLDocument::NewComment( const char* str )
1703{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001704 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001705 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1706 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001707 comment->SetValue( str );
1708 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001709}
1710
1711
1712XMLText* XMLDocument::NewText( const char* str )
1713{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001714 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001715 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1716 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001717 text->SetValue( str );
1718 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001719}
1720
1721
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001722XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1723{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001724 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001725 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1726 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001727 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1728 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001729}
1730
1731
1732XMLUnknown* XMLDocument::NewUnknown( const char* str )
1733{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001734 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001735 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1736 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001737 unk->SetValue( str );
1738 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001739}
1740
Dmitry-Me01578db2014-08-19 10:18:48 +04001741static FILE* callfopen( const char* filepath, const char* mode )
1742{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001743 TIXMLASSERT( filepath );
1744 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001745#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1746 FILE* fp = 0;
1747 errno_t err = fopen_s( &fp, filepath, mode );
1748 if ( err ) {
1749 return 0;
1750 }
1751#else
1752 FILE* fp = fopen( filepath, mode );
1753#endif
1754 return fp;
1755}
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001756
1757void XMLDocument::DeleteNode( XMLNode* node ) {
1758 TIXMLASSERT( node );
1759 TIXMLASSERT(node->_document == this );
1760 if (node->_parent) {
1761 node->_parent->DeleteChild( node );
1762 }
1763 else {
1764 // Isn't in the tree.
1765 // Use the parent delete.
1766 // Also, we need to mark it tracked: we 'know'
1767 // it was never used.
1768 node->_memPool->SetTracked();
1769 // Call the static XMLNode version:
1770 XMLNode::DeleteNode(node);
1771 }
1772}
1773
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001774
Lee Thomason2fa81722012-11-09 12:37:46 -08001775XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001776{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001777 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001778 FILE* fp = callfopen( filename, "rb" );
1779 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001780 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001781 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001782 }
1783 LoadFile( fp );
1784 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001785 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001786}
1787
1788
Lee Thomason2fa81722012-11-09 12:37:46 -08001789XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001790{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001791 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001792
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001793 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001794 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001795 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1796 return _errorID;
1797 }
1798
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001799 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001800 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001801 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001802 if ( filelength == -1L ) {
1803 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1804 return _errorID;
1805 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001806
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001807 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001808 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001809 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001810 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001811 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001812
Lee Thomason624d43f2012-10-12 10:58:48 -07001813 _charBuffer = new char[size+1];
1814 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001815 if ( read != size ) {
1816 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001817 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001818 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001819
Lee Thomason624d43f2012-10-12 10:58:48 -07001820 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001821
Lee Thomason624d43f2012-10-12 10:58:48 -07001822 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001823 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001824 p = XMLUtil::ReadBOM( p, &_writeBOM );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001825 if ( !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001826 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001827 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001828 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001829
Lee Thomason624d43f2012-10-12 10:58:48 -07001830 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1831 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001832}
1833
1834
Lee Thomason2fa81722012-11-09 12:37:46 -08001835XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001836{
Dmitry-Me01578db2014-08-19 10:18:48 +04001837 FILE* fp = callfopen( filename, "w" );
1838 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001839 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001840 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001841 }
1842 SaveFile(fp, compact);
1843 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001844 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001845}
1846
1847
Lee Thomason2fa81722012-11-09 12:37:46 -08001848XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001849{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001850 XMLPrinter stream( fp, compact );
1851 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001852 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001853}
1854
Lee Thomason1ff38e02012-02-14 18:18:16 -08001855
Lee Thomason2fa81722012-11-09 12:37:46 -08001856XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001857{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001858 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001859
Lee Thomason82d32002014-02-21 22:47:18 -08001860 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001861 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001862 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001863 }
1864 if ( len == (size_t)(-1) ) {
1865 len = strlen( p );
1866 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001867 _charBuffer = new char[ len+1 ];
1868 memcpy( _charBuffer, p, len );
1869 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001870
Dmitry-Me5b4a5162014-12-23 17:36:28 +03001871 const char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001872 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001873 p = XMLUtil::ReadBOM( p, &_writeBOM );
Dmitry-Mebb836dc2014-12-24 11:54:05 +03001874 if ( !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001875 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001876 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001877 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001878
Thomas Roß1470edc2013-05-10 15:44:12 +02001879 ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001880 ParseDeep( _charBuffer+delta, 0 );
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001881 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001882 // clean up now essentially dangling memory.
1883 // and the parse fail can put objects in the
1884 // pools that are dead and inaccessible.
1885 DeleteChildren();
1886 _elementPool.Clear();
1887 _attributePool.Clear();
1888 _textPool.Clear();
1889 _commentPool.Clear();
1890 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001891 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001892}
1893
1894
PKEuS1c5f99e2013-07-06 11:28:39 +02001895void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001896{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001897 XMLPrinter stdStreamer( stdout );
1898 if ( !streamer ) {
1899 streamer = &stdStreamer;
1900 }
1901 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001902}
1903
1904
Lee Thomason2fa81722012-11-09 12:37:46 -08001905void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001906{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001907 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07001908 _errorID = error;
1909 _errorStr1 = str1;
1910 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001911}
1912
Lee Thomason331596e2014-09-11 14:56:43 -07001913const char* XMLDocument::ErrorName() const
1914{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001915 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Lee Thomason331596e2014-09-11 14:56:43 -07001916 return _errorNames[_errorID];
1917}
Lee Thomason5cae8972012-01-24 18:03:07 -08001918
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001919void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001920{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001921 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001922 static const int LEN = 20;
1923 char buf1[LEN] = { 0 };
1924 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001925
Lee Thomason624d43f2012-10-12 10:58:48 -07001926 if ( _errorStr1 ) {
1927 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001928 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001929 if ( _errorStr2 ) {
1930 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001931 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001932
Lee Thomason331596e2014-09-11 14:56:43 -07001933 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
1934 _errorID, ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001935 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001936}
1937
1938
PKEuS1bfb9542013-08-04 13:51:17 +02001939XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001940 _elementJustOpened( false ),
1941 _firstElement( true ),
1942 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001943 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001944 _textDepth( -1 ),
1945 _processEntities( true ),
1946 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001947{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001948 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001949 _entityFlag[i] = false;
1950 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001951 }
1952 for( int i=0; i<NUM_ENTITIES; ++i ) {
Dmitry-Me8b67d742014-12-22 11:35:12 +03001953 const char entityValue = entities[i].value;
1954 TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
1955 _entityFlag[ (unsigned char)entityValue ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001956 }
Dmitry-Me8b67d742014-12-22 11:35:12 +03001957 _restrictedEntityFlag[(unsigned char)'&'] = true;
1958 _restrictedEntityFlag[(unsigned char)'<'] = true;
1959 _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
Lee Thomason624d43f2012-10-12 10:58:48 -07001960 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001961}
1962
1963
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001964void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001965{
1966 va_list va;
1967 va_start( va, format );
1968
Lee Thomason624d43f2012-10-12 10:58:48 -07001969 if ( _fp ) {
1970 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001971 }
1972 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001973#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001974 #if defined(WINCE)
1975 int len = 512;
1976 do {
1977 len = len*2;
1978 char* str = new char[len]();
1979 len = _vsnprintf(str, len, format, va);
1980 delete[] str;
1981 }while (len < 0);
1982 #else
Thomas Roß268c6832014-03-13 23:35:16 +01001983 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08001984 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001985#else
1986 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01001987#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001988 // Close out and re-start the va-args
1989 va_end( va );
1990 va_start( va, format );
Lee Thomasona0744c82014-03-16 10:32:27 -07001991 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
1992#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001993 #if defined(WINCE)
1994 _vsnprintf( p, len+1, format, va );
1995 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07001996 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08001997 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07001998#else
1999 vsnprintf( p, len+1, format, va );
2000#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002001 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08002002 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08002003}
2004
2005
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002006void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002007{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002008 for( int i=0; i<depth; ++i ) {
2009 Print( " " );
2010 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002011}
2012
2013
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002014void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002015{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002016 // Look for runs of bytes between entities to print.
2017 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07002018 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08002019
Lee Thomason624d43f2012-10-12 10:58:48 -07002020 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002021 while ( *q ) {
2022 // Remember, char is sometimes signed. (How many times has that bitten me?)
2023 if ( *q > 0 && *q < ENTITY_RANGE ) {
2024 // Check for entities. If one is found, flush
2025 // the stream up until the entity, write the
2026 // entity, and keep looking.
Dmitry-Me8b67d742014-12-22 11:35:12 +03002027 if ( flag[(unsigned char)(*q)] ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002028 while ( p < q ) {
2029 Print( "%c", *p );
2030 ++p;
2031 }
2032 for( int i=0; i<NUM_ENTITIES; ++i ) {
2033 if ( entities[i].value == *q ) {
2034 Print( "&%s;", entities[i].pattern );
2035 break;
2036 }
2037 }
2038 ++p;
2039 }
2040 }
2041 ++q;
2042 }
2043 }
2044 // Flush the remaining string. This will be the entire
2045 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07002046 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002047 Print( "%s", p );
2048 }
Lee Thomason857b8682012-01-25 17:50:25 -08002049}
2050
U-Stream\Leeae25a442012-02-17 17:48:16 -08002051
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002052void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002053{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002054 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002055 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 -07002056 Print( "%s", bom );
2057 }
2058 if ( writeDec ) {
2059 PushDeclaration( "xml version=\"1.0\"" );
2060 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002061}
2062
2063
Uli Kusterer593a33d2014-02-01 12:48:51 +01002064void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002065{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002066 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002067 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002068
Uli Kusterer593a33d2014-02-01 12:48:51 +01002069 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002070 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002071 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002072 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002073 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002074 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002075
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002076 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002077 _elementJustOpened = true;
2078 _firstElement = false;
2079 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002080}
2081
2082
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002083void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002084{
Lee Thomason624d43f2012-10-12 10:58:48 -07002085 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002086 Print( " %s=\"", name );
2087 PrintString( value, false );
2088 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002089}
2090
2091
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002092void XMLPrinter::PushAttribute( const char* name, int v )
2093{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002094 char buf[BUF_SIZE];
2095 XMLUtil::ToStr( v, buf, BUF_SIZE );
2096 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002097}
2098
2099
2100void XMLPrinter::PushAttribute( const char* name, unsigned 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, bool 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, double 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
Uli Kustererca412e82014-02-01 13:35:05 +01002124void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002125{
Lee Thomason624d43f2012-10-12 10:58:48 -07002126 --_depth;
2127 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002128
Lee Thomason624d43f2012-10-12 10:58:48 -07002129 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002130 Print( "/>" );
2131 }
2132 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002133 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002134 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002135 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002136 }
2137 Print( "</%s>", name );
2138 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002139
Lee Thomason624d43f2012-10-12 10:58:48 -07002140 if ( _textDepth == _depth ) {
2141 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002142 }
Uli Kustererca412e82014-02-01 13:35:05 +01002143 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002144 Print( "\n" );
2145 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002146 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002147}
2148
2149
Dmitry-Mea092bc12014-12-23 17:57:05 +03002150void XMLPrinter::SealElementIfJustOpened()
Lee Thomason5cae8972012-01-24 18:03:07 -08002151{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002152 if ( !_elementJustOpened ) {
2153 return;
2154 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002155 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002156 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002157}
2158
2159
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002160void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002161{
Lee Thomason624d43f2012-10-12 10:58:48 -07002162 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002163
Dmitry-Mea092bc12014-12-23 17:57:05 +03002164 SealElementIfJustOpened();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002165 if ( cdata ) {
2166 Print( "<![CDATA[" );
2167 Print( "%s", text );
2168 Print( "]]>" );
2169 }
2170 else {
2171 PrintString( text, true );
2172 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002173}
2174
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002175void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002176{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002177 char buf[BUF_SIZE];
2178 XMLUtil::ToStr( value, buf, BUF_SIZE );
2179 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002180}
2181
2182
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002183void XMLPrinter::PushText( unsigned 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( bool 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( float 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( double 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
Lee Thomason5cae8972012-01-24 18:03:07 -08002214
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002215void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002216{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002217 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002218 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002219 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002220 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002221 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002222 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002223 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002224}
Lee Thomason751da522012-02-10 08:50:51 -08002225
2226
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002227void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002228{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002229 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002230 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002231 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002232 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002233 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002234 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002235 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002236}
2237
2238
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002239void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002240{
Dmitry-Mea092bc12014-12-23 17:57:05 +03002241 SealElementIfJustOpened();
Lee Thomason624d43f2012-10-12 10:58:48 -07002242 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002243 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002244 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002245 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002246 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002247 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002248}
2249
2250
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002251bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002252{
Lee Thomason624d43f2012-10-12 10:58:48 -07002253 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002254 if ( doc.HasBOM() ) {
2255 PushHeader( true, false );
2256 }
2257 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002258}
2259
2260
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002261bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002262{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002263 const XMLElement* parentElem = element.Parent()->ToElement();
2264 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2265 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002266 while ( attribute ) {
2267 PushAttribute( attribute->Name(), attribute->Value() );
2268 attribute = attribute->Next();
2269 }
2270 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002271}
2272
2273
Uli Kustererca412e82014-02-01 13:35:05 +01002274bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002275{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002276 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002277 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002278}
2279
2280
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002281bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002282{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002283 PushText( text.Value(), text.CData() );
2284 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002285}
2286
2287
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002288bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002289{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002290 PushComment( comment.Value() );
2291 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002292}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002293
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002294bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002295{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002296 PushDeclaration( declaration.Value() );
2297 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002298}
2299
2300
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002301bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002302{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002303 PushUnknown( unknown.Value() );
2304 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002305}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002306
Lee Thomason685b8952012-11-12 13:00:06 -08002307} // namespace tinyxml2
2308