blob: ee7a16c51a12fefd00df4c3d3f7b65dc4ae24c1f [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.
Lee Thomasona9cf3f92012-10-11 16:56:51 -070027# ifdef ANDROID_NDK
28# 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
Dmitry-Me08b40dd2014-11-10 11:17:21 +030073void StrPair::TransferTo( StrPair& other )
74{
75 if ( this == &other ) {
76 return;
77 }
78 // This in effect implements the assignment operator by "moving"
79 // ownership (as in auto_ptr).
80
81 TIXMLASSERT( other._flags == 0 );
82 TIXMLASSERT( other._start == 0 );
83 TIXMLASSERT( other._end == 0 );
84
85 other.Reset();
86
87 other._flags = _flags;
88 other._start = _start;
89 other._end = _end;
90
91 _flags = 0;
92 _start = 0;
93 _end = 0;
94}
95
Lee Thomason1a1d4a72012-02-15 09:09:25 -080096void StrPair::Reset()
97{
Lee Thomason120b3a62012-10-12 10:06:59 -070098 if ( _flags & NEEDS_DELETE ) {
99 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700100 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700101 _flags = 0;
102 _start = 0;
103 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800104}
105
106
107void StrPair::SetStr( const char* str, int flags )
108{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700109 Reset();
110 size_t len = strlen( str );
Lee Thomason120b3a62012-10-12 10:06:59 -0700111 _start = new char[ len+1 ];
112 memcpy( _start, str, len+1 );
113 _end = _start + len;
114 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800115}
116
117
118char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
119{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700120 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800121
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400122 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700123 char endChar = *endTag;
124 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800125
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700126 // Inner loop of text parsing.
127 while ( *p ) {
128 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
129 Set( start, p, strFlags );
130 return p + length;
131 }
132 ++p;
133 }
134 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800135}
136
137
138char* StrPair::ParseName( char* p )
139{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400140 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700141 return 0;
142 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800143
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400144 char* const start = p;
145
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +0200146 while( *p && ( p == start ? XMLUtil::IsNameStartChar( *p ) : XMLUtil::IsNameChar( *p ) )) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700147 ++p;
148 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800149
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700150 if ( p > start ) {
151 Set( start, p, 0 );
152 return p;
153 }
154 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800155}
156
157
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700158void StrPair::CollapseWhitespace()
159{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400160 // Adjusting _start would cause undefined behavior on delete[]
161 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700162 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700163 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700164
Lee Thomason120b3a62012-10-12 10:06:59 -0700165 if ( _start && *_start ) {
166 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{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700280 *bom = false;
281 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
282 // Check for BOM:
283 if ( *(pu+0) == TIXML_UTF_LEAD_0
284 && *(pu+1) == TIXML_UTF_LEAD_1
285 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
286 *bom = true;
287 p += 3;
288 }
289 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800290}
291
292
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800293void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
294{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700295 const unsigned long BYTE_MASK = 0xBF;
296 const unsigned long BYTE_MARK = 0x80;
297 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800298
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700299 if (input < 0x80) {
300 *length = 1;
301 }
302 else if ( input < 0x800 ) {
303 *length = 2;
304 }
305 else if ( input < 0x10000 ) {
306 *length = 3;
307 }
308 else if ( input < 0x200000 ) {
309 *length = 4;
310 }
311 else {
312 *length = 0; // This code won't covert this correctly anyway.
313 return;
314 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800315
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700316 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800317
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700318 // Scary scary fall throughs.
319 switch (*length) {
320 case 4:
321 --output;
322 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
323 input >>= 6;
324 case 3:
325 --output;
326 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
327 input >>= 6;
328 case 2:
329 --output;
330 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
331 input >>= 6;
332 case 1:
333 --output;
334 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100335 default:
336 break;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700337 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800338}
339
340
341const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
342{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700343 // Presume an entity, and pull it out.
344 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800345
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700346 if ( *(p+1) == '#' && *(p+2) ) {
347 unsigned long ucs = 0;
348 ptrdiff_t delta = 0;
349 unsigned mult = 1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800350
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700351 if ( *(p+2) == 'x' ) {
352 // Hexadecimal.
353 if ( !*(p+3) ) {
354 return 0;
355 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800356
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700357 const char* q = p+3;
358 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800359
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700360 if ( !q || !*q ) {
361 return 0;
362 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800363
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700364 delta = q-p;
365 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800366
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700367 while ( *q != 'x' ) {
368 if ( *q >= '0' && *q <= '9' ) {
369 ucs += mult * (*q - '0');
370 }
371 else if ( *q >= 'a' && *q <= 'f' ) {
372 ucs += mult * (*q - 'a' + 10);
373 }
374 else if ( *q >= 'A' && *q <= 'F' ) {
375 ucs += mult * (*q - 'A' + 10 );
376 }
377 else {
378 return 0;
379 }
380 mult *= 16;
381 --q;
382 }
383 }
384 else {
385 // Decimal.
386 if ( !*(p+2) ) {
387 return 0;
388 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800389
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700390 const char* q = p+2;
391 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800392
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700393 if ( !q || !*q ) {
394 return 0;
395 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800396
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700397 delta = q-p;
398 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800399
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700400 while ( *q != '#' ) {
401 if ( *q >= '0' && *q <= '9' ) {
402 ucs += mult * (*q - '0');
403 }
404 else {
405 return 0;
406 }
407 mult *= 10;
408 --q;
409 }
410 }
411 // convert the UCS to UTF-8
412 ConvertUTF32ToUTF8( ucs, value, length );
413 return p + delta + 1;
414 }
415 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800416}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800417
418
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700419void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700420{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700421 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700422}
423
424
425void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
426{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700427 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700428}
429
430
431void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
432{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700433 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700434}
435
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800436/*
437 ToStr() of a number is a very tricky topic.
438 https://github.com/leethomason/tinyxml2/issues/106
439*/
Lee Thomason21be8822012-07-15 17:27:22 -0700440void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
441{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800442 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700443}
444
445
446void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
447{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800448 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700449}
450
451
452bool XMLUtil::ToInt( const char* str, int* value )
453{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700454 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
455 return true;
456 }
457 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700458}
459
460bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
461{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700462 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
463 return true;
464 }
465 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700466}
467
468bool XMLUtil::ToBool( const char* str, bool* value )
469{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700470 int ival = 0;
471 if ( ToInt( str, &ival )) {
472 *value = (ival==0) ? false : true;
473 return true;
474 }
475 if ( StringEqual( str, "true" ) ) {
476 *value = true;
477 return true;
478 }
479 else if ( StringEqual( str, "false" ) ) {
480 *value = false;
481 return true;
482 }
483 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700484}
485
486
487bool XMLUtil::ToFloat( const char* str, float* value )
488{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700489 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
490 return true;
491 }
492 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700493}
494
495bool XMLUtil::ToDouble( const char* str, double* value )
496{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700497 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
498 return true;
499 }
500 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700501}
502
503
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700504char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800505{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400506 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700507 p = XMLUtil::SkipWhiteSpace( p );
508 if( !p || !*p ) {
509 return p;
510 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800511
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700512 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800513 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700514 static const char* xmlHeader = { "<?" };
515 static const char* commentHeader = { "<!--" };
516 static const char* dtdHeader = { "<!" };
517 static const char* cdataHeader = { "<![CDATA[" };
518 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800519
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700520 static const int xmlHeaderLen = 2;
521 static const int commentHeaderLen = 4;
522 static const int dtdHeaderLen = 2;
523 static const int cdataHeaderLen = 9;
524 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800525
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800526#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800527#pragma warning ( push )
528#pragma warning ( disable : 4127 )
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800529#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700530 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
531 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800532#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800533#pragma warning (pop)
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800534#endif
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400535 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700536 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700537 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
538 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700539 p += xmlHeaderLen;
540 }
541 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700542 returnNode = new (_commentPool.Alloc()) XMLComment( this );
543 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700544 p += commentHeaderLen;
545 }
546 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700547 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700548 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700549 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700550 p += cdataHeaderLen;
551 text->SetCData( true );
552 }
553 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
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 ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700559 returnNode = new (_elementPool.Alloc()) XMLElement( this );
560 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700561 p += elementHeaderLen;
562 }
563 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700564 returnNode = new (_textPool.Alloc()) XMLText( this );
565 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700566 p = start; // Back it up, all the text counts.
567 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800568
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700569 *node = returnNode;
570 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800571}
572
573
Lee Thomason751da522012-02-10 08:50:51 -0800574bool XMLDocument::Accept( XMLVisitor* visitor ) const
575{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700576 if ( visitor->VisitEnter( *this ) ) {
577 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
578 if ( !node->Accept( visitor ) ) {
579 break;
580 }
581 }
582 }
583 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800584}
Lee Thomason56bdd022012-02-09 18:16:58 -0800585
586
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800587// --------- XMLNode ----------- //
588
589XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700590 _document( doc ),
591 _parent( 0 ),
592 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200593 _prev( 0 ), _next( 0 ),
594 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800595{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800596}
597
598
599XMLNode::~XMLNode()
600{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700601 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700602 if ( _parent ) {
603 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700604 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800605}
606
Michael Daumling21626882013-10-22 17:03:37 +0200607const char* XMLNode::Value() const
608{
609 return _value.GetStr();
610}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800611
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800612void XMLNode::SetValue( const char* str, bool staticMem )
613{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700614 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700615 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700616 }
617 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700618 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700619 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800620}
621
622
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800623void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800624{
Lee Thomason624d43f2012-10-12 10:58:48 -0700625 while( _firstChild ) {
626 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700627 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700628
Dmitry-Mee3225b12014-09-03 11:03:11 +0400629 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700630 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700631 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800632}
633
634
635void XMLNode::Unlink( XMLNode* child )
636{
Lee Thomason624d43f2012-10-12 10:58:48 -0700637 if ( child == _firstChild ) {
638 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700639 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700640 if ( child == _lastChild ) {
641 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700642 }
Lee Thomasond923c672012-01-23 08:44:25 -0800643
Lee Thomason624d43f2012-10-12 10:58:48 -0700644 if ( child->_prev ) {
645 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700646 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700647 if ( child->_next ) {
648 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700649 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700650 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800651}
652
653
U-Stream\Leeae25a442012-02-17 17:48:16 -0800654void XMLNode::DeleteChild( XMLNode* node )
655{
Lee Thomason624d43f2012-10-12 10:58:48 -0700656 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400657 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800658}
659
660
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800661XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
662{
Michael Daumlinged523282013-10-23 07:47:29 +0200663 if (addThis->_document != _document)
664 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700665
Michael Daumlinged523282013-10-23 07:47:29 +0200666 if (addThis->_parent)
667 addThis->_parent->Unlink( addThis );
668 else
669 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700670
Lee Thomason624d43f2012-10-12 10:58:48 -0700671 if ( _lastChild ) {
672 TIXMLASSERT( _firstChild );
673 TIXMLASSERT( _lastChild->_next == 0 );
674 _lastChild->_next = addThis;
675 addThis->_prev = _lastChild;
676 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800677
Lee Thomason624d43f2012-10-12 10:58:48 -0700678 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700679 }
680 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700681 TIXMLASSERT( _firstChild == 0 );
682 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800683
Lee Thomason624d43f2012-10-12 10:58:48 -0700684 addThis->_prev = 0;
685 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700686 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700687 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700688 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800689}
690
691
Lee Thomason1ff38e02012-02-14 18:18:16 -0800692XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
693{
Michael Daumlinged523282013-10-23 07:47:29 +0200694 if (addThis->_document != _document)
695 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700696
Michael Daumlinged523282013-10-23 07:47:29 +0200697 if (addThis->_parent)
698 addThis->_parent->Unlink( addThis );
699 else
700 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700701
Lee Thomason624d43f2012-10-12 10:58:48 -0700702 if ( _firstChild ) {
703 TIXMLASSERT( _lastChild );
704 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800705
Lee Thomason624d43f2012-10-12 10:58:48 -0700706 _firstChild->_prev = addThis;
707 addThis->_next = _firstChild;
708 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800709
Lee Thomason624d43f2012-10-12 10:58:48 -0700710 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700711 }
712 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700713 TIXMLASSERT( _lastChild == 0 );
714 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800715
Lee Thomason624d43f2012-10-12 10:58:48 -0700716 addThis->_prev = 0;
717 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700718 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700719 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400720 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800721}
722
723
724XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
725{
Michael Daumlinged523282013-10-23 07:47:29 +0200726 if (addThis->_document != _document)
727 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700728
Lee Thomason624d43f2012-10-12 10:58:48 -0700729 TIXMLASSERT( afterThis->_parent == this );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700730
Lee Thomason624d43f2012-10-12 10:58:48 -0700731 if ( afterThis->_parent != this ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700732 return 0;
733 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800734
Lee Thomason624d43f2012-10-12 10:58:48 -0700735 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700736 // The last node or the only node.
737 return InsertEndChild( addThis );
738 }
Michael Daumlinged523282013-10-23 07:47:29 +0200739 if (addThis->_parent)
740 addThis->_parent->Unlink( addThis );
741 else
742 addThis->_memPool->SetTracked();
Lee Thomason624d43f2012-10-12 10:58:48 -0700743 addThis->_prev = afterThis;
744 addThis->_next = afterThis->_next;
745 afterThis->_next->_prev = addThis;
746 afterThis->_next = addThis;
747 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700748 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800749}
750
751
752
753
Lee Thomason56bdd022012-02-09 18:16:58 -0800754const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800755{
Lee Thomason624d43f2012-10-12 10:58:48 -0700756 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700757 XMLElement* element = node->ToElement();
758 if ( element ) {
759 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
760 return element;
761 }
762 }
763 }
764 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800765}
766
767
Lee Thomason56bdd022012-02-09 18:16:58 -0800768const XMLElement* XMLNode::LastChildElement( const char* value ) const
769{
Lee Thomason624d43f2012-10-12 10:58:48 -0700770 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700771 XMLElement* element = node->ToElement();
772 if ( element ) {
773 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
774 return element;
775 }
776 }
777 }
778 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800779}
780
781
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800782const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
783{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400784 for( XMLNode* node=this->_next; node; node = node->_next ) {
785 const XMLElement* element = node->ToElement();
786 if ( element
787 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
788 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700789 }
790 }
791 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800792}
793
794
795const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
796{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400797 for( XMLNode* node=_prev; node; node = node->_prev ) {
798 const XMLElement* element = node->ToElement();
799 if ( element
800 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
801 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700802 }
803 }
804 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800805}
806
807
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800808char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800809{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700810 // This is a recursive method, but thinking about it "at the current level"
811 // it is a pretty simple flat list:
812 // <foo/>
813 // <!-- comment -->
814 //
815 // With a special case:
816 // <foo>
817 // </foo>
818 // <!-- comment -->
819 //
820 // Where the closing element (/foo) *must* be the next thing after the opening
821 // element, and the names must match. BUT the tricky bit is that the closing
822 // element will be read by the child.
823 //
824 // 'endTag' is the end tag for this node, it is returned by a call to a child.
825 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800826
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700827 while( p && *p ) {
828 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800829
Lee Thomason624d43f2012-10-12 10:58:48 -0700830 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700831 if ( p == 0 || node == 0 ) {
832 break;
833 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800834
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700835 StrPair endTag;
836 p = node->ParseDeep( p, &endTag );
837 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400838 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700839 node = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -0700840 if ( !_document->Error() ) {
841 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700842 }
843 break;
844 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800845
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400846 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700847 // We read the end tag. Return it to the parent.
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400848 if ( ele && ele->ClosingType() == XMLElement::CLOSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700849 if ( parentEnd ) {
Dmitry-Me08b40dd2014-11-10 11:17:21 +0300850 ele->_value.TransferTo( *parentEnd );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700851 }
Lee Thomason5b0a6772012-11-19 13:54:42 -0800852 node->_memPool->SetTracked(); // created and then immediately deleted.
Dmitry-Mee3225b12014-09-03 11:03:11 +0400853 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700854 return p;
855 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800856
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700857 // Handle an end tag returned to this level.
858 // And handle a bunch of annoying errors.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700859 if ( ele ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400860 bool mismatch = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700861 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400862 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700863 }
864 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400865 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700866 }
867 else if ( !endTag.Empty() ) {
868 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400869 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700870 }
871 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400872 if ( mismatch ) {
873 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
874 p = 0;
875 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700876 }
877 if ( p == 0 ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400878 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700879 node = 0;
880 }
881 if ( node ) {
882 this->InsertEndChild( node );
883 }
884 }
885 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800886}
887
Dmitry-Mee3225b12014-09-03 11:03:11 +0400888void XMLNode::DeleteNode( XMLNode* node )
889{
890 if ( node == 0 ) {
891 return;
892 }
893 MemPool* pool = node->_memPool;
894 node->~XMLNode();
895 pool->Free( node );
896}
897
Lee Thomason5492a1c2012-01-23 15:32:10 -0800898// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800899char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800900{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700901 const char* start = p;
902 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700903 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700904 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700905 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700906 }
907 return p;
908 }
909 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700910 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
911 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700912 flags |= StrPair::COLLAPSE_WHITESPACE;
913 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700914
Lee Thomason624d43f2012-10-12 10:58:48 -0700915 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700916 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700917 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700918 }
919 if ( p && *p ) {
920 return p-1;
921 }
922 }
923 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800924}
925
926
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800927XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
928{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700929 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700930 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700931 }
932 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
933 text->SetCData( this->CData() );
934 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800935}
936
937
938bool XMLText::ShallowEqual( const XMLNode* compare ) const
939{
Dmitry-Me6d202ff2014-09-26 14:21:00 +0400940 const XMLText* text = compare->ToText();
941 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800942}
943
944
Lee Thomason56bdd022012-02-09 18:16:58 -0800945bool XMLText::Accept( XMLVisitor* visitor ) const
946{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700947 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800948}
949
950
Lee Thomason3f57d272012-01-11 15:30:03 -0800951// --------- XMLComment ---------- //
952
Lee Thomasone4422302012-01-20 17:59:50 -0800953XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800954{
955}
956
957
Lee Thomasonce0763e2012-01-11 15:43:54 -0800958XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800959{
Lee Thomason3f57d272012-01-11 15:30:03 -0800960}
961
962
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800963char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800964{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700965 // Comment parses as text.
966 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700967 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700968 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700969 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700970 }
971 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800972}
973
974
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800975XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
976{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700977 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700978 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700979 }
980 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
981 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800982}
983
984
985bool XMLComment::ShallowEqual( const XMLNode* compare ) const
986{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400987 const XMLComment* comment = compare->ToComment();
988 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800989}
990
991
Lee Thomason751da522012-02-10 08:50:51 -0800992bool XMLComment::Accept( XMLVisitor* visitor ) const
993{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700994 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800995}
Lee Thomason56bdd022012-02-09 18:16:58 -0800996
997
Lee Thomason50f97b22012-02-11 16:33:40 -0800998// --------- XMLDeclaration ---------- //
999
1000XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1001{
1002}
1003
1004
1005XMLDeclaration::~XMLDeclaration()
1006{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001007 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001008}
1009
1010
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001011char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001012{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001013 // Declaration parses as text.
1014 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001015 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001016 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001017 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001018 }
1019 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001020}
1021
1022
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001023XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1024{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001025 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001026 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001027 }
1028 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1029 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001030}
1031
1032
1033bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1034{
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001035 const XMLDeclaration* declaration = compare->ToDeclaration();
1036 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001037}
1038
1039
1040
Lee Thomason50f97b22012-02-11 16:33:40 -08001041bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1042{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001043 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001044}
1045
1046// --------- XMLUnknown ---------- //
1047
1048XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1049{
1050}
1051
1052
1053XMLUnknown::~XMLUnknown()
1054{
1055}
1056
1057
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001058char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001059{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001060 // Unknown parses as text.
1061 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001062
Lee Thomason624d43f2012-10-12 10:58:48 -07001063 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001064 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001065 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001066 }
1067 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001068}
1069
1070
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001071XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1072{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001073 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001074 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001075 }
1076 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1077 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001078}
1079
1080
1081bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1082{
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001083 const XMLUnknown* unknown = compare->ToUnknown();
1084 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001085}
1086
1087
Lee Thomason50f97b22012-02-11 16:33:40 -08001088bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1089{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001090 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001091}
1092
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001093// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001094
1095const char* XMLAttribute::Name() const
1096{
1097 return _name.GetStr();
1098}
1099
1100const char* XMLAttribute::Value() const
1101{
1102 return _value.GetStr();
1103}
1104
Lee Thomason6f381b72012-03-02 12:59:39 -08001105char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001106{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001107 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001108 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001109 if ( !p || !*p ) {
1110 return 0;
1111 }
Lee Thomason22aead12012-01-23 13:29:35 -08001112
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001113 // Skip white space before =
1114 p = XMLUtil::SkipWhiteSpace( p );
1115 if ( !p || *p != '=' ) {
1116 return 0;
1117 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001118
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001119 ++p; // move up to opening quote
1120 p = XMLUtil::SkipWhiteSpace( p );
1121 if ( *p != '\"' && *p != '\'' ) {
1122 return 0;
1123 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001124
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001125 char endTag[2] = { *p, 0 };
1126 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001127
Lee Thomason624d43f2012-10-12 10:58:48 -07001128 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001129 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001130}
1131
1132
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001133void XMLAttribute::SetName( const char* n )
1134{
Lee Thomason624d43f2012-10-12 10:58:48 -07001135 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001136}
1137
1138
Lee Thomason2fa81722012-11-09 12:37:46 -08001139XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001140{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001141 if ( XMLUtil::ToInt( Value(), value )) {
1142 return XML_NO_ERROR;
1143 }
1144 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001145}
1146
1147
Lee Thomason2fa81722012-11-09 12:37:46 -08001148XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001149{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001150 if ( XMLUtil::ToUnsigned( Value(), value )) {
1151 return XML_NO_ERROR;
1152 }
1153 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001154}
1155
1156
Lee Thomason2fa81722012-11-09 12:37:46 -08001157XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001158{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001159 if ( XMLUtil::ToBool( 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::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001167{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001168 if ( XMLUtil::ToFloat( Value(), value )) {
1169 return XML_NO_ERROR;
1170 }
1171 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001172}
1173
1174
Lee Thomason2fa81722012-11-09 12:37:46 -08001175XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001176{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001177 if ( XMLUtil::ToDouble( Value(), value )) {
1178 return XML_NO_ERROR;
1179 }
1180 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001181}
1182
1183
1184void XMLAttribute::SetAttribute( const char* v )
1185{
Lee Thomason624d43f2012-10-12 10:58:48 -07001186 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001187}
1188
1189
Lee Thomason1ff38e02012-02-14 18:18:16 -08001190void XMLAttribute::SetAttribute( int v )
1191{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001192 char buf[BUF_SIZE];
1193 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001194 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001195}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001196
1197
1198void XMLAttribute::SetAttribute( unsigned v )
1199{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001200 char buf[BUF_SIZE];
1201 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001202 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001203}
1204
1205
1206void XMLAttribute::SetAttribute( bool v )
1207{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001208 char buf[BUF_SIZE];
1209 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001210 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001211}
1212
1213void XMLAttribute::SetAttribute( double v )
1214{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001215 char buf[BUF_SIZE];
1216 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001217 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001218}
1219
1220void XMLAttribute::SetAttribute( float v )
1221{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001222 char buf[BUF_SIZE];
1223 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001224 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001225}
1226
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001227
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001228// --------- XMLElement ---------- //
1229XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001230 _closingType( 0 ),
1231 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001232{
1233}
1234
1235
1236XMLElement::~XMLElement()
1237{
Lee Thomason624d43f2012-10-12 10:58:48 -07001238 while( _rootAttribute ) {
1239 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001240 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001241 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001242 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001243}
1244
1245
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001246XMLAttribute* XMLElement::FindAttribute( const char* name )
1247{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001248 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001249 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1250 return a;
1251 }
1252 }
1253 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001254}
1255
1256
1257const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1258{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001259 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001260 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1261 return a;
1262 }
1263 }
1264 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001265}
1266
1267
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001268const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001269{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001270 const XMLAttribute* a = FindAttribute( name );
1271 if ( !a ) {
1272 return 0;
1273 }
1274 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1275 return a->Value();
1276 }
1277 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001278}
1279
1280
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001281const char* XMLElement::GetText() const
1282{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001283 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001284 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001285 }
1286 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001287}
1288
1289
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001290void XMLElement::SetText( const char* inText )
1291{
Uli Kusterer869bb592014-01-21 01:36:16 +01001292 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001293 FirstChild()->SetValue( inText );
1294 else {
1295 XMLText* theText = GetDocument()->NewText( inText );
1296 InsertFirstChild( theText );
1297 }
1298}
1299
Lee Thomason5bb2d802014-01-24 10:42:57 -08001300
1301void XMLElement::SetText( int v )
1302{
1303 char buf[BUF_SIZE];
1304 XMLUtil::ToStr( v, buf, BUF_SIZE );
1305 SetText( buf );
1306}
1307
1308
1309void XMLElement::SetText( unsigned v )
1310{
1311 char buf[BUF_SIZE];
1312 XMLUtil::ToStr( v, buf, BUF_SIZE );
1313 SetText( buf );
1314}
1315
1316
1317void XMLElement::SetText( bool v )
1318{
1319 char buf[BUF_SIZE];
1320 XMLUtil::ToStr( v, buf, BUF_SIZE );
1321 SetText( buf );
1322}
1323
1324
1325void XMLElement::SetText( float v )
1326{
1327 char buf[BUF_SIZE];
1328 XMLUtil::ToStr( v, buf, BUF_SIZE );
1329 SetText( buf );
1330}
1331
1332
1333void XMLElement::SetText( double v )
1334{
1335 char buf[BUF_SIZE];
1336 XMLUtil::ToStr( v, buf, BUF_SIZE );
1337 SetText( buf );
1338}
1339
1340
MortenMacFly4ee49f12013-01-14 20:03:14 +01001341XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001342{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001343 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001344 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001345 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001346 return XML_SUCCESS;
1347 }
1348 return XML_CAN_NOT_CONVERT_TEXT;
1349 }
1350 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001351}
1352
1353
MortenMacFly4ee49f12013-01-14 20:03:14 +01001354XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001355{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001356 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001357 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001358 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001359 return XML_SUCCESS;
1360 }
1361 return XML_CAN_NOT_CONVERT_TEXT;
1362 }
1363 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001364}
1365
1366
MortenMacFly4ee49f12013-01-14 20:03:14 +01001367XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001368{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001369 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001370 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001371 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001372 return XML_SUCCESS;
1373 }
1374 return XML_CAN_NOT_CONVERT_TEXT;
1375 }
1376 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001377}
1378
1379
MortenMacFly4ee49f12013-01-14 20:03:14 +01001380XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001381{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001382 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001383 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001384 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001385 return XML_SUCCESS;
1386 }
1387 return XML_CAN_NOT_CONVERT_TEXT;
1388 }
1389 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001390}
1391
1392
MortenMacFly4ee49f12013-01-14 20:03:14 +01001393XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001394{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001395 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001396 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001397 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001398 return XML_SUCCESS;
1399 }
1400 return XML_CAN_NOT_CONVERT_TEXT;
1401 }
1402 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001403}
1404
1405
1406
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001407XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1408{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001409 XMLAttribute* last = 0;
1410 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001411 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001412 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001413 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001414 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1415 break;
1416 }
1417 }
1418 if ( !attrib ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001419 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1420 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001421 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001422 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001423 }
1424 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001425 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001426 }
1427 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001428 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001429 }
1430 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001431}
1432
1433
U-Stream\Leeae25a442012-02-17 17:48:16 -08001434void XMLElement::DeleteAttribute( const char* name )
1435{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001436 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001437 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001438 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1439 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001440 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001441 }
1442 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001443 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001444 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001445 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001446 break;
1447 }
1448 prev = a;
1449 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001450}
1451
1452
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001453char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001454{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001455 const char* start = p;
1456 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001457
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001458 // Read the attributes.
1459 while( p ) {
1460 p = XMLUtil::SkipWhiteSpace( p );
1461 if ( !p || !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001462 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001463 return 0;
1464 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001465
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001466 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001467 if (XMLUtil::IsNameStartChar( *p ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001468 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1469 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001470 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001471
Lee Thomason624d43f2012-10-12 10:58:48 -07001472 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001473 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001474 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001475 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001476 return 0;
1477 }
1478 // There is a minor bug here: if the attribute in the source xml
1479 // document is duplicated, it will not be detected and the
1480 // attribute will be doubly added. However, tracking the 'prevAttribute'
1481 // avoids re-scanning the attribute list. Preferring performance for
1482 // now, may reconsider in the future.
1483 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001484 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001485 }
1486 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001487 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001488 }
1489 prevAttribute = attrib;
1490 }
1491 // end of the tag
1492 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001493 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001494 return p+2; // done; sealed element.
1495 }
1496 // end of the tag
1497 else if ( *p == '>' ) {
1498 ++p;
1499 break;
1500 }
1501 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001502 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001503 return 0;
1504 }
1505 }
1506 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001507}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001508
Dmitry-Mee3225b12014-09-03 11:03:11 +04001509void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1510{
1511 if ( attribute == 0 ) {
1512 return;
1513 }
1514 MemPool* pool = attribute->_memPool;
1515 attribute->~XMLAttribute();
1516 pool->Free( attribute );
1517}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001518
Lee Thomason67d61312012-01-24 16:01:51 -08001519//
1520// <ele></ele>
1521// <ele>foo<b>bar</b></ele>
1522//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001523char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001524{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001525 // Read the element name.
1526 p = XMLUtil::SkipWhiteSpace( p );
1527 if ( !p ) {
1528 return 0;
1529 }
Lee Thomason67d61312012-01-24 16:01:51 -08001530
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001531 // The closing element is the </element> form. It is
1532 // parsed just like a regular element then deleted from
1533 // the DOM.
1534 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001535 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001536 ++p;
1537 }
Lee Thomason67d61312012-01-24 16:01:51 -08001538
Lee Thomason624d43f2012-10-12 10:58:48 -07001539 p = _value.ParseName( p );
1540 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001541 return 0;
1542 }
Lee Thomason67d61312012-01-24 16:01:51 -08001543
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001544 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001545 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001546 return p;
1547 }
Lee Thomason67d61312012-01-24 16:01:51 -08001548
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001549 p = XMLNode::ParseDeep( p, strPair );
1550 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001551}
1552
1553
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001554
1555XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1556{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001557 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001558 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001559 }
1560 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1561 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1562 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1563 }
1564 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001565}
1566
1567
1568bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1569{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001570 const XMLElement* other = compare->ToElement();
1571 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001572
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001573 const XMLAttribute* a=FirstAttribute();
1574 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001575
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001576 while ( a && b ) {
1577 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1578 return false;
1579 }
1580 a = a->Next();
1581 b = b->Next();
1582 }
1583 if ( a || b ) {
1584 // different count
1585 return false;
1586 }
1587 return true;
1588 }
1589 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001590}
1591
1592
Lee Thomason751da522012-02-10 08:50:51 -08001593bool XMLElement::Accept( XMLVisitor* visitor ) const
1594{
Lee Thomason624d43f2012-10-12 10:58:48 -07001595 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001596 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1597 if ( !node->Accept( visitor ) ) {
1598 break;
1599 }
1600 }
1601 }
1602 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001603}
Lee Thomason56bdd022012-02-09 18:16:58 -08001604
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001605
Lee Thomason3f57d272012-01-11 15:30:03 -08001606// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001607
1608// Warning: List must match 'enum XMLError'
1609const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1610 "XML_SUCCESS",
1611 "XML_NO_ATTRIBUTE",
1612 "XML_WRONG_ATTRIBUTE_TYPE",
1613 "XML_ERROR_FILE_NOT_FOUND",
1614 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1615 "XML_ERROR_FILE_READ_ERROR",
1616 "XML_ERROR_ELEMENT_MISMATCH",
1617 "XML_ERROR_PARSING_ELEMENT",
1618 "XML_ERROR_PARSING_ATTRIBUTE",
1619 "XML_ERROR_IDENTIFYING_TAG",
1620 "XML_ERROR_PARSING_TEXT",
1621 "XML_ERROR_PARSING_CDATA",
1622 "XML_ERROR_PARSING_COMMENT",
1623 "XML_ERROR_PARSING_DECLARATION",
1624 "XML_ERROR_PARSING_UNKNOWN",
1625 "XML_ERROR_EMPTY_DOCUMENT",
1626 "XML_ERROR_MISMATCHED_ELEMENT",
1627 "XML_ERROR_PARSING",
1628 "XML_CAN_NOT_CONVERT_TEXT",
1629 "XML_NO_TEXT_NODE"
1630};
1631
1632
Lee Thomason624d43f2012-10-12 10:58:48 -07001633XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001634 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001635 _writeBOM( false ),
1636 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001637 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001638 _whitespace( whitespace ),
1639 _errorStr1( 0 ),
1640 _errorStr2( 0 ),
1641 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001642{
Lee Thomason624d43f2012-10-12 10:58:48 -07001643 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001644}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001645
1646
Lee Thomason3f57d272012-01-11 15:30:03 -08001647XMLDocument::~XMLDocument()
1648{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001649 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001650}
1651
1652
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001653void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001654{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001655 DeleteChildren();
1656
Lee Thomason624d43f2012-10-12 10:58:48 -07001657 _errorID = XML_NO_ERROR;
1658 _errorStr1 = 0;
1659 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001660
Lee Thomason624d43f2012-10-12 10:58:48 -07001661 delete [] _charBuffer;
1662 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001663
1664#if 0
1665 _textPool.Trace( "text" );
1666 _elementPool.Trace( "element" );
1667 _commentPool.Trace( "comment" );
1668 _attributePool.Trace( "attribute" );
1669#endif
1670
1671#ifdef DEBUG
1672 if ( Error() == false ) {
1673 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1674 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1675 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1676 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1677 }
1678#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001679}
1680
Lee Thomason3f57d272012-01-11 15:30:03 -08001681
Lee Thomason2c85a712012-01-31 08:24:24 -08001682XMLElement* XMLDocument::NewElement( const char* name )
1683{
Lee Thomason624d43f2012-10-12 10:58:48 -07001684 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1685 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001686 ele->SetName( name );
1687 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001688}
1689
1690
Lee Thomason1ff38e02012-02-14 18:18:16 -08001691XMLComment* XMLDocument::NewComment( const char* str )
1692{
Lee Thomason624d43f2012-10-12 10:58:48 -07001693 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1694 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001695 comment->SetValue( str );
1696 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001697}
1698
1699
1700XMLText* XMLDocument::NewText( const char* str )
1701{
Lee Thomason624d43f2012-10-12 10:58:48 -07001702 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1703 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001704 text->SetValue( str );
1705 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001706}
1707
1708
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001709XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1710{
Lee Thomason624d43f2012-10-12 10:58:48 -07001711 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1712 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001713 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1714 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001715}
1716
1717
1718XMLUnknown* XMLDocument::NewUnknown( const char* str )
1719{
Lee Thomason624d43f2012-10-12 10:58:48 -07001720 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1721 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001722 unk->SetValue( str );
1723 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001724}
1725
Dmitry-Me01578db2014-08-19 10:18:48 +04001726static FILE* callfopen( const char* filepath, const char* mode )
1727{
1728#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1729 FILE* fp = 0;
1730 errno_t err = fopen_s( &fp, filepath, mode );
1731 if ( err ) {
1732 return 0;
1733 }
1734#else
1735 FILE* fp = fopen( filepath, mode );
1736#endif
1737 return fp;
1738}
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001739
Lee Thomason2fa81722012-11-09 12:37:46 -08001740XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001741{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001742 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001743 FILE* fp = callfopen( filename, "rb" );
1744 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001745 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001746 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001747 }
1748 LoadFile( fp );
1749 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001750 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001751}
1752
1753
Lee Thomason2fa81722012-11-09 12:37:46 -08001754XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001755{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001756 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001757
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001758 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001759 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001760 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1761 return _errorID;
1762 }
1763
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001764 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001765 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001766 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001767 if ( filelength == -1L ) {
1768 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1769 return _errorID;
1770 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001771
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001772 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001773 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001774 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001775 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001776 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001777
Lee Thomason624d43f2012-10-12 10:58:48 -07001778 _charBuffer = new char[size+1];
1779 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001780 if ( read != size ) {
1781 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001782 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001783 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001784
Lee Thomason624d43f2012-10-12 10:58:48 -07001785 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001786
Lee Thomason624d43f2012-10-12 10:58:48 -07001787 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001788 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001789 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001790 if ( !p || !*p ) {
1791 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001792 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001793 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001794
Lee Thomason624d43f2012-10-12 10:58:48 -07001795 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1796 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001797}
1798
1799
Lee Thomason2fa81722012-11-09 12:37:46 -08001800XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001801{
Dmitry-Me01578db2014-08-19 10:18:48 +04001802 FILE* fp = callfopen( filename, "w" );
1803 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001804 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001805 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001806 }
1807 SaveFile(fp, compact);
1808 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001809 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001810}
1811
1812
Lee Thomason2fa81722012-11-09 12:37:46 -08001813XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001814{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001815 XMLPrinter stream( fp, compact );
1816 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001817 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001818}
1819
Lee Thomason1ff38e02012-02-14 18:18:16 -08001820
Lee Thomason2fa81722012-11-09 12:37:46 -08001821XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001822{
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001823 const char* start = p;
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001824 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001825
Lee Thomason82d32002014-02-21 22:47:18 -08001826 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001827 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001828 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001829 }
1830 if ( len == (size_t)(-1) ) {
1831 len = strlen( p );
1832 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001833 _charBuffer = new char[ len+1 ];
1834 memcpy( _charBuffer, p, len );
1835 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001836
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001837 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001838 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001839 if ( !p || !*p ) {
1840 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001841 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001842 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001843
Thomas Roß1470edc2013-05-10 15:44:12 +02001844 ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001845 ParseDeep( _charBuffer+delta, 0 );
Lee Thomasonf07b9522014-10-30 13:25:12 -07001846 if (_errorID) {
1847 // clean up now essentially dangling memory.
1848 // and the parse fail can put objects in the
1849 // pools that are dead and inaccessible.
1850 DeleteChildren();
1851 _elementPool.Clear();
1852 _attributePool.Clear();
1853 _textPool.Clear();
1854 _commentPool.Clear();
1855 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001856 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001857}
1858
1859
PKEuS1c5f99e2013-07-06 11:28:39 +02001860void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001861{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001862 XMLPrinter stdStreamer( stdout );
1863 if ( !streamer ) {
1864 streamer = &stdStreamer;
1865 }
1866 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001867}
1868
1869
Lee Thomason2fa81722012-11-09 12:37:46 -08001870void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001871{
Lee Thomason624d43f2012-10-12 10:58:48 -07001872 _errorID = error;
1873 _errorStr1 = str1;
1874 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001875}
1876
Lee Thomason331596e2014-09-11 14:56:43 -07001877const char* XMLDocument::ErrorName() const
1878{
1879 TIXMLASSERT(_errorID >= 0 && _errorID < XML_ERROR_COUNT );
1880 return _errorNames[_errorID];
1881}
Lee Thomason5cae8972012-01-24 18:03:07 -08001882
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001883void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001884{
Lee Thomason624d43f2012-10-12 10:58:48 -07001885 if ( _errorID ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001886 static const int LEN = 20;
1887 char buf1[LEN] = { 0 };
1888 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001889
Lee Thomason624d43f2012-10-12 10:58:48 -07001890 if ( _errorStr1 ) {
1891 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001892 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001893 if ( _errorStr2 ) {
1894 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001895 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001896
Lee Thomason331596e2014-09-11 14:56:43 -07001897 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
1898 _errorID, ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001899 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001900}
1901
1902
PKEuS1bfb9542013-08-04 13:51:17 +02001903XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001904 _elementJustOpened( false ),
1905 _firstElement( true ),
1906 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001907 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001908 _textDepth( -1 ),
1909 _processEntities( true ),
1910 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001911{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001912 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001913 _entityFlag[i] = false;
1914 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001915 }
1916 for( int i=0; i<NUM_ENTITIES; ++i ) {
1917 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1918 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001919 _entityFlag[ (int)entities[i].value ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001920 }
1921 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001922 _restrictedEntityFlag[(int)'&'] = true;
1923 _restrictedEntityFlag[(int)'<'] = true;
1924 _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
1925 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001926}
1927
1928
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001929void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001930{
1931 va_list va;
1932 va_start( va, format );
1933
Lee Thomason624d43f2012-10-12 10:58:48 -07001934 if ( _fp ) {
1935 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001936 }
1937 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001938#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001939 #if defined(WINCE)
1940 int len = 512;
1941 do {
1942 len = len*2;
1943 char* str = new char[len]();
1944 len = _vsnprintf(str, len, format, va);
1945 delete[] str;
1946 }while (len < 0);
1947 #else
Thomas Roß268c6832014-03-13 23:35:16 +01001948 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08001949 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001950#else
1951 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01001952#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001953 // Close out and re-start the va-args
1954 va_end( va );
1955 va_start( va, format );
Lee Thomasona0744c82014-03-16 10:32:27 -07001956 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
1957#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001958 #if defined(WINCE)
1959 _vsnprintf( p, len+1, format, va );
1960 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07001961 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08001962 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07001963#else
1964 vsnprintf( p, len+1, format, va );
1965#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001966 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001967 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001968}
1969
1970
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001971void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001972{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001973 for( int i=0; i<depth; ++i ) {
1974 Print( " " );
1975 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001976}
1977
1978
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001979void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001980{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001981 // Look for runs of bytes between entities to print.
1982 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001983 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001984
Lee Thomason624d43f2012-10-12 10:58:48 -07001985 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001986 while ( *q ) {
1987 // Remember, char is sometimes signed. (How many times has that bitten me?)
1988 if ( *q > 0 && *q < ENTITY_RANGE ) {
1989 // Check for entities. If one is found, flush
1990 // the stream up until the entity, write the
1991 // entity, and keep looking.
1992 if ( flag[(unsigned)(*q)] ) {
1993 while ( p < q ) {
1994 Print( "%c", *p );
1995 ++p;
1996 }
1997 for( int i=0; i<NUM_ENTITIES; ++i ) {
1998 if ( entities[i].value == *q ) {
1999 Print( "&%s;", entities[i].pattern );
2000 break;
2001 }
2002 }
2003 ++p;
2004 }
2005 }
2006 ++q;
2007 }
2008 }
2009 // Flush the remaining string. This will be the entire
2010 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07002011 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002012 Print( "%s", p );
2013 }
Lee Thomason857b8682012-01-25 17:50:25 -08002014}
2015
U-Stream\Leeae25a442012-02-17 17:48:16 -08002016
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002017void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002018{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002019 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002020 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 -07002021 Print( "%s", bom );
2022 }
2023 if ( writeDec ) {
2024 PushDeclaration( "xml version=\"1.0\"" );
2025 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002026}
2027
2028
Uli Kusterer593a33d2014-02-01 12:48:51 +01002029void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002030{
Lee Thomason624d43f2012-10-12 10:58:48 -07002031 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002032 SealElement();
2033 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002034 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002035
Uli Kusterer593a33d2014-02-01 12:48:51 +01002036 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002037 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002038 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002039 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002040 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002041 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002042
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002043 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002044 _elementJustOpened = true;
2045 _firstElement = false;
2046 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002047}
2048
2049
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002050void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002051{
Lee Thomason624d43f2012-10-12 10:58:48 -07002052 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002053 Print( " %s=\"", name );
2054 PrintString( value, false );
2055 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002056}
2057
2058
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002059void XMLPrinter::PushAttribute( const char* name, int v )
2060{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002061 char buf[BUF_SIZE];
2062 XMLUtil::ToStr( v, buf, BUF_SIZE );
2063 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002064}
2065
2066
2067void XMLPrinter::PushAttribute( const char* name, unsigned v )
2068{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002069 char buf[BUF_SIZE];
2070 XMLUtil::ToStr( v, buf, BUF_SIZE );
2071 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002072}
2073
2074
2075void XMLPrinter::PushAttribute( const char* name, bool v )
2076{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002077 char buf[BUF_SIZE];
2078 XMLUtil::ToStr( v, buf, BUF_SIZE );
2079 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002080}
2081
2082
2083void XMLPrinter::PushAttribute( const char* name, double v )
2084{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002085 char buf[BUF_SIZE];
2086 XMLUtil::ToStr( v, buf, BUF_SIZE );
2087 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002088}
2089
2090
Uli Kustererca412e82014-02-01 13:35:05 +01002091void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002092{
Lee Thomason624d43f2012-10-12 10:58:48 -07002093 --_depth;
2094 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002095
Lee Thomason624d43f2012-10-12 10:58:48 -07002096 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002097 Print( "/>" );
2098 }
2099 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002100 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002101 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002102 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002103 }
2104 Print( "</%s>", name );
2105 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002106
Lee Thomason624d43f2012-10-12 10:58:48 -07002107 if ( _textDepth == _depth ) {
2108 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002109 }
Uli Kustererca412e82014-02-01 13:35:05 +01002110 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002111 Print( "\n" );
2112 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002113 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002114}
2115
2116
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002117void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08002118{
Lee Thomason624d43f2012-10-12 10:58:48 -07002119 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002120 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002121}
2122
2123
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002124void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002125{
Lee Thomason624d43f2012-10-12 10:58:48 -07002126 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002127
Lee Thomason624d43f2012-10-12 10:58:48 -07002128 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002129 SealElement();
2130 }
2131 if ( cdata ) {
2132 Print( "<![CDATA[" );
2133 Print( "%s", text );
2134 Print( "]]>" );
2135 }
2136 else {
2137 PrintString( text, true );
2138 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002139}
2140
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002141void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002142{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002143 char buf[BUF_SIZE];
2144 XMLUtil::ToStr( value, buf, BUF_SIZE );
2145 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002146}
2147
2148
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002149void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002150{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002151 char buf[BUF_SIZE];
2152 XMLUtil::ToStr( value, buf, BUF_SIZE );
2153 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002154}
2155
2156
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002157void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002158{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002159 char buf[BUF_SIZE];
2160 XMLUtil::ToStr( value, buf, BUF_SIZE );
2161 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002162}
2163
2164
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002165void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002166{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002167 char buf[BUF_SIZE];
2168 XMLUtil::ToStr( value, buf, BUF_SIZE );
2169 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002170}
2171
2172
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002173void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002174{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002175 char buf[BUF_SIZE];
2176 XMLUtil::ToStr( value, buf, BUF_SIZE );
2177 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002178}
2179
Lee Thomason5cae8972012-01-24 18:03:07 -08002180
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002181void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002182{
Lee Thomason624d43f2012-10-12 10:58:48 -07002183 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002184 SealElement();
2185 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002186 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002187 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002188 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002189 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002190 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002191 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002192}
Lee Thomason751da522012-02-10 08:50:51 -08002193
2194
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002195void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002196{
Lee Thomason624d43f2012-10-12 10:58:48 -07002197 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002198 SealElement();
2199 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002200 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002201 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002202 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002203 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002204 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002205 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002206}
2207
2208
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002209void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002210{
Lee Thomason624d43f2012-10-12 10:58:48 -07002211 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002212 SealElement();
2213 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002214 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002215 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002216 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002217 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002218 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002219 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002220}
2221
2222
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002223bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002224{
Lee Thomason624d43f2012-10-12 10:58:48 -07002225 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002226 if ( doc.HasBOM() ) {
2227 PushHeader( true, false );
2228 }
2229 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002230}
2231
2232
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002233bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002234{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002235 const XMLElement* parentElem = element.Parent()->ToElement();
2236 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2237 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002238 while ( attribute ) {
2239 PushAttribute( attribute->Name(), attribute->Value() );
2240 attribute = attribute->Next();
2241 }
2242 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002243}
2244
2245
Uli Kustererca412e82014-02-01 13:35:05 +01002246bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002247{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002248 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002249 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002250}
2251
2252
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002253bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002254{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002255 PushText( text.Value(), text.CData() );
2256 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002257}
2258
2259
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002260bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002261{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002262 PushComment( comment.Value() );
2263 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002264}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002265
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002266bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002267{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002268 PushDeclaration( declaration.Value() );
2269 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002270}
2271
2272
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002273bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002274{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002275 PushUnknown( unknown.Value() );
2276 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002277}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002278
Lee Thomason685b8952012-11-12 13:00:06 -08002279} // namespace tinyxml2
2280