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