blob: fe5b43717759a65af9184a3859fc34653ca2f8f7 [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
48
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080049#define DELETE_NODE( node ) { \
Lee Thomasona9cf3f92012-10-11 16:56:51 -070050 if ( node ) { \
Lee Thomason624d43f2012-10-12 10:58:48 -070051 MemPool* pool = node->_memPool; \
Lee Thomasona9cf3f92012-10-11 16:56:51 -070052 node->~XMLNode(); \
53 pool->Free( node ); \
54 } \
55 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080056#define DELETE_ATTRIBUTE( attrib ) { \
Lee Thomasona9cf3f92012-10-11 16:56:51 -070057 if ( attrib ) { \
Lee Thomason624d43f2012-10-12 10:58:48 -070058 MemPool* pool = attrib->_memPool; \
Lee Thomasona9cf3f92012-10-11 16:56:51 -070059 attrib->~XMLAttribute(); \
60 pool->Free( attrib ); \
61 } \
62 }
Lee Thomason43f59302012-02-06 18:18:11 -080063
Kevin Wojniak04c22d22012-11-08 11:02:22 -080064namespace tinyxml2
65{
66
Lee Thomason8ee79892012-01-25 17:44:30 -080067struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -070068 const char* pattern;
69 int length;
70 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -080071};
72
73static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070074static const Entity entities[NUM_ENTITIES] = {
75 { "quot", 4, DOUBLE_QUOTE },
76 { "amp", 3, '&' },
77 { "apos", 4, SINGLE_QUOTE },
78 { "lt", 2, '<' },
79 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -080080};
81
Lee Thomasonfde6a752012-01-14 18:08:12 -080082
Lee Thomason1a1d4a72012-02-15 09:09:25 -080083StrPair::~StrPair()
84{
Lee Thomasona9cf3f92012-10-11 16:56:51 -070085 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -080086}
87
88
89void StrPair::Reset()
90{
Lee Thomason120b3a62012-10-12 10:06:59 -070091 if ( _flags & NEEDS_DELETE ) {
92 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070093 }
Lee Thomason120b3a62012-10-12 10:06:59 -070094 _flags = 0;
95 _start = 0;
96 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -080097}
98
99
100void StrPair::SetStr( const char* str, int flags )
101{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700102 Reset();
103 size_t len = strlen( str );
Lee Thomason120b3a62012-10-12 10:06:59 -0700104 _start = new char[ len+1 ];
105 memcpy( _start, str, len+1 );
106 _end = _start + len;
107 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800108}
109
110
111char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
112{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700113 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800114
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700115 char* start = p; // fixme: hides a member
116 char endChar = *endTag;
117 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800118
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700119 // Inner loop of text parsing.
120 while ( *p ) {
121 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
122 Set( start, p, strFlags );
123 return p + length;
124 }
125 ++p;
126 }
127 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800128}
129
130
131char* StrPair::ParseName( char* p )
132{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700133 char* start = p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800134
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700135 if ( !start || !(*start) ) {
136 return 0;
137 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800138
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +0200139 while( *p && ( p == start ? XMLUtil::IsNameStartChar( *p ) : XMLUtil::IsNameChar( *p ) )) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700140 ++p;
141 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800142
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700143 if ( p > start ) {
144 Set( start, p, 0 );
145 return p;
146 }
147 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800148}
149
150
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700151void StrPair::CollapseWhitespace()
152{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700153 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700154 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700155
Lee Thomason120b3a62012-10-12 10:06:59 -0700156 if ( _start && *_start ) {
157 char* p = _start; // the read pointer
158 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700159
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700160 while( *p ) {
161 if ( XMLUtil::IsWhiteSpace( *p )) {
162 p = XMLUtil::SkipWhiteSpace( p );
163 if ( *p == 0 ) {
164 break; // don't write to q; this trims the trailing space.
165 }
166 *q = ' ';
167 ++q;
168 }
169 *q = *p;
170 ++q;
171 ++p;
172 }
173 *q = 0;
174 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700175}
176
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800177
Lee Thomasone4422302012-01-20 17:59:50 -0800178const char* StrPair::GetStr()
179{
Lee Thomason120b3a62012-10-12 10:06:59 -0700180 if ( _flags & NEEDS_FLUSH ) {
181 *_end = 0;
182 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800183
Lee Thomason120b3a62012-10-12 10:06:59 -0700184 if ( _flags ) {
185 char* p = _start; // the read pointer
186 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800187
Lee Thomason120b3a62012-10-12 10:06:59 -0700188 while( p < _end ) {
189 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700190 // CR-LF pair becomes LF
191 // CR alone becomes LF
192 // LF-CR becomes LF
193 if ( *(p+1) == LF ) {
194 p += 2;
195 }
196 else {
197 ++p;
198 }
199 *q++ = LF;
200 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700201 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700202 if ( *(p+1) == CR ) {
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_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700211 // Entities handled by tinyXML2:
212 // - special entities in the entity table [in/out]
213 // - numeric character reference [in]
214 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800215
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700216 if ( *(p+1) == '#' ) {
217 char buf[10] = { 0 };
218 int len;
219 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
220 for( int i=0; i<len; ++i ) {
221 *q++ = buf[i];
222 }
223 TIXMLASSERT( q <= p );
224 }
225 else {
226 int i=0;
227 for(; i<NUM_ENTITIES; ++i ) {
228 if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
229 && *(p+entities[i].length+1) == ';' ) {
230 // Found an entity convert;
231 *q = entities[i].value;
232 ++q;
233 p += entities[i].length + 2;
234 break;
235 }
236 }
237 if ( i == NUM_ENTITIES ) {
238 // fixme: treat as error?
239 ++p;
240 ++q;
241 }
242 }
243 }
244 else {
245 *q = *p;
246 ++p;
247 ++q;
248 }
249 }
250 *q = 0;
251 }
252 // The loop below has plenty going on, and this
253 // is a less useful mode. Break it out.
Lee Thomason120b3a62012-10-12 10:06:59 -0700254 if ( _flags & COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700255 CollapseWhitespace();
256 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700257 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700258 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700259 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800260}
261
Lee Thomason2c85a712012-01-31 08:24:24 -0800262
Lee Thomasone4422302012-01-20 17:59:50 -0800263
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800264
Lee Thomason56bdd022012-02-09 18:16:58 -0800265// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800266
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800267const char* XMLUtil::ReadBOM( const char* p, bool* bom )
268{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700269 *bom = false;
270 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
271 // Check for BOM:
272 if ( *(pu+0) == TIXML_UTF_LEAD_0
273 && *(pu+1) == TIXML_UTF_LEAD_1
274 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
275 *bom = true;
276 p += 3;
277 }
278 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800279}
280
281
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800282void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
283{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700284 const unsigned long BYTE_MASK = 0xBF;
285 const unsigned long BYTE_MARK = 0x80;
286 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800287
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700288 if (input < 0x80) {
289 *length = 1;
290 }
291 else if ( input < 0x800 ) {
292 *length = 2;
293 }
294 else if ( input < 0x10000 ) {
295 *length = 3;
296 }
297 else if ( input < 0x200000 ) {
298 *length = 4;
299 }
300 else {
301 *length = 0; // This code won't covert this correctly anyway.
302 return;
303 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800304
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700305 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800306
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700307 // Scary scary fall throughs.
308 switch (*length) {
309 case 4:
310 --output;
311 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
312 input >>= 6;
313 case 3:
314 --output;
315 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
316 input >>= 6;
317 case 2:
318 --output;
319 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
320 input >>= 6;
321 case 1:
322 --output;
323 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100324 default:
325 break;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700326 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800327}
328
329
330const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
331{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700332 // Presume an entity, and pull it out.
333 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800334
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700335 if ( *(p+1) == '#' && *(p+2) ) {
336 unsigned long ucs = 0;
337 ptrdiff_t delta = 0;
338 unsigned mult = 1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800339
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700340 if ( *(p+2) == 'x' ) {
341 // Hexadecimal.
342 if ( !*(p+3) ) {
343 return 0;
344 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800345
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700346 const char* q = p+3;
347 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800348
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700349 if ( !q || !*q ) {
350 return 0;
351 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800352
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700353 delta = q-p;
354 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800355
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700356 while ( *q != 'x' ) {
357 if ( *q >= '0' && *q <= '9' ) {
358 ucs += mult * (*q - '0');
359 }
360 else if ( *q >= 'a' && *q <= 'f' ) {
361 ucs += mult * (*q - 'a' + 10);
362 }
363 else if ( *q >= 'A' && *q <= 'F' ) {
364 ucs += mult * (*q - 'A' + 10 );
365 }
366 else {
367 return 0;
368 }
369 mult *= 16;
370 --q;
371 }
372 }
373 else {
374 // Decimal.
375 if ( !*(p+2) ) {
376 return 0;
377 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800378
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700379 const char* q = p+2;
380 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800381
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700382 if ( !q || !*q ) {
383 return 0;
384 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800385
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700386 delta = q-p;
387 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800388
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700389 while ( *q != '#' ) {
390 if ( *q >= '0' && *q <= '9' ) {
391 ucs += mult * (*q - '0');
392 }
393 else {
394 return 0;
395 }
396 mult *= 10;
397 --q;
398 }
399 }
400 // convert the UCS to UTF-8
401 ConvertUTF32ToUTF8( ucs, value, length );
402 return p + delta + 1;
403 }
404 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800405}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800406
407
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700408void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700409{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700410 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700411}
412
413
Uli Kusterer664d0562014-01-21 12:24:47 +0100414void XMLUtil::ToStr( long long v, char* buffer, int bufferSize )
415{
416 TIXML_SNPRINTF( buffer, bufferSize, "%lld", v );
417}
418
419
Lee Thomason21be8822012-07-15 17:27:22 -0700420void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
421{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700422 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700423}
424
425
426void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
427{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700428 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700429}
430
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800431/*
432 ToStr() of a number is a very tricky topic.
433 https://github.com/leethomason/tinyxml2/issues/106
434*/
Lee Thomason21be8822012-07-15 17:27:22 -0700435void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
436{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800437 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700438}
439
440
441void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
442{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800443 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700444}
445
446
447bool XMLUtil::ToInt( const char* str, int* value )
448{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700449 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
450 return true;
451 }
452 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700453}
454
Uli Kusterer664d0562014-01-21 12:24:47 +0100455bool XMLUtil::ToLongLong( const char* str, long long* value )
456{
457 if ( TIXML_SSCANF( str, "%lld", value ) == 1 ) {
458 return true;
459 }
460 return false;
461}
462
Lee Thomason21be8822012-07-15 17:27:22 -0700463bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
464{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700465 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
466 return true;
467 }
468 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700469}
470
471bool XMLUtil::ToBool( const char* str, bool* value )
472{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700473 int ival = 0;
474 if ( ToInt( str, &ival )) {
475 *value = (ival==0) ? false : true;
476 return true;
477 }
478 if ( StringEqual( str, "true" ) ) {
479 *value = true;
480 return true;
481 }
482 else if ( StringEqual( str, "false" ) ) {
483 *value = false;
484 return true;
485 }
486 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700487}
488
489
490bool XMLUtil::ToFloat( const char* str, float* value )
491{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700492 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
493 return true;
494 }
495 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700496}
497
498bool XMLUtil::ToDouble( const char* str, double* value )
499{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700500 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
501 return true;
502 }
503 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700504}
505
506
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700507char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800508{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700509 XMLNode* returnNode = 0;
510 char* start = p;
511 p = XMLUtil::SkipWhiteSpace( p );
512 if( !p || !*p ) {
513 return p;
514 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800515
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700516 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800517 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700518 static const char* xmlHeader = { "<?" };
519 static const char* commentHeader = { "<!--" };
520 static const char* dtdHeader = { "<!" };
521 static const char* cdataHeader = { "<![CDATA[" };
522 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800523
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700524 static const int xmlHeaderLen = 2;
525 static const int commentHeaderLen = 4;
526 static const int dtdHeaderLen = 2;
527 static const int cdataHeaderLen = 9;
528 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800529
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800530#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800531#pragma warning ( push )
532#pragma warning ( disable : 4127 )
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800533#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700534 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
535 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800536#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800537#pragma warning (pop)
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800538#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700539 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700540 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
541 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700542 p += xmlHeaderLen;
543 }
544 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700545 returnNode = new (_commentPool.Alloc()) XMLComment( this );
546 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700547 p += commentHeaderLen;
548 }
549 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700550 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700551 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700552 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700553 p += cdataHeaderLen;
554 text->SetCData( true );
555 }
556 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700557 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
558 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700559 p += dtdHeaderLen;
560 }
561 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700562 returnNode = new (_elementPool.Alloc()) XMLElement( this );
563 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700564 p += elementHeaderLen;
565 }
566 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700567 returnNode = new (_textPool.Alloc()) XMLText( this );
568 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700569 p = start; // Back it up, all the text counts.
570 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800571
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700572 *node = returnNode;
573 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800574}
575
576
Lee Thomason751da522012-02-10 08:50:51 -0800577bool XMLDocument::Accept( XMLVisitor* visitor ) const
578{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700579 if ( visitor->VisitEnter( *this ) ) {
580 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
581 if ( !node->Accept( visitor ) ) {
582 break;
583 }
584 }
585 }
586 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800587}
Lee Thomason56bdd022012-02-09 18:16:58 -0800588
589
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800590// --------- XMLNode ----------- //
591
592XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700593 _document( doc ),
594 _parent( 0 ),
595 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200596 _prev( 0 ), _next( 0 ),
597 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800598{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800599}
600
601
602XMLNode::~XMLNode()
603{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700604 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700605 if ( _parent ) {
606 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700607 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800608}
609
Michael Daumling21626882013-10-22 17:03:37 +0200610const char* XMLNode::Value() const
611{
612 return _value.GetStr();
613}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800614
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800615void XMLNode::SetValue( const char* str, bool staticMem )
616{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700617 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700618 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700619 }
620 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700621 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700622 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800623}
624
625
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800626void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800627{
Lee Thomason624d43f2012-10-12 10:58:48 -0700628 while( _firstChild ) {
629 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700630 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700631
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700632 DELETE_NODE( node );
633 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700634 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800635}
636
637
638void XMLNode::Unlink( XMLNode* child )
639{
Lee Thomason624d43f2012-10-12 10:58:48 -0700640 if ( child == _firstChild ) {
641 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700642 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700643 if ( child == _lastChild ) {
644 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700645 }
Lee Thomasond923c672012-01-23 08:44:25 -0800646
Lee Thomason624d43f2012-10-12 10:58:48 -0700647 if ( child->_prev ) {
648 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700649 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700650 if ( child->_next ) {
651 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700652 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700653 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800654}
655
656
U-Stream\Leeae25a442012-02-17 17:48:16 -0800657void XMLNode::DeleteChild( XMLNode* node )
658{
Lee Thomason624d43f2012-10-12 10:58:48 -0700659 TIXMLASSERT( node->_parent == this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700660 DELETE_NODE( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800661}
662
663
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800664XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
665{
Michael Daumlinged523282013-10-23 07:47:29 +0200666 if (addThis->_document != _document)
667 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700668
Michael Daumlinged523282013-10-23 07:47:29 +0200669 if (addThis->_parent)
670 addThis->_parent->Unlink( addThis );
671 else
672 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700673
Lee Thomason624d43f2012-10-12 10:58:48 -0700674 if ( _lastChild ) {
675 TIXMLASSERT( _firstChild );
676 TIXMLASSERT( _lastChild->_next == 0 );
677 _lastChild->_next = addThis;
678 addThis->_prev = _lastChild;
679 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800680
Lee Thomason624d43f2012-10-12 10:58:48 -0700681 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700682 }
683 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700684 TIXMLASSERT( _firstChild == 0 );
685 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800686
Lee Thomason624d43f2012-10-12 10:58:48 -0700687 addThis->_prev = 0;
688 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700689 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700690 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700691 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800692}
693
694
Lee Thomason1ff38e02012-02-14 18:18:16 -0800695XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
696{
Michael Daumlinged523282013-10-23 07:47:29 +0200697 if (addThis->_document != _document)
698 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700699
Michael Daumlinged523282013-10-23 07:47:29 +0200700 if (addThis->_parent)
701 addThis->_parent->Unlink( addThis );
702 else
703 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700704
Lee Thomason624d43f2012-10-12 10:58:48 -0700705 if ( _firstChild ) {
706 TIXMLASSERT( _lastChild );
707 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800708
Lee Thomason624d43f2012-10-12 10:58:48 -0700709 _firstChild->_prev = addThis;
710 addThis->_next = _firstChild;
711 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800712
Lee Thomason624d43f2012-10-12 10:58:48 -0700713 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700714 }
715 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700716 TIXMLASSERT( _lastChild == 0 );
717 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800718
Lee Thomason624d43f2012-10-12 10:58:48 -0700719 addThis->_prev = 0;
720 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700721 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700722 addThis->_parent = this;
Michael Daumlinged523282013-10-23 07:47:29 +0200723 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800724}
725
726
727XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
728{
Michael Daumlinged523282013-10-23 07:47:29 +0200729 if (addThis->_document != _document)
730 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700731
Lee Thomason624d43f2012-10-12 10:58:48 -0700732 TIXMLASSERT( afterThis->_parent == this );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700733
Lee Thomason624d43f2012-10-12 10:58:48 -0700734 if ( afterThis->_parent != this ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700735 return 0;
736 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800737
Lee Thomason624d43f2012-10-12 10:58:48 -0700738 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700739 // The last node or the only node.
740 return InsertEndChild( addThis );
741 }
Michael Daumlinged523282013-10-23 07:47:29 +0200742 if (addThis->_parent)
743 addThis->_parent->Unlink( addThis );
744 else
745 addThis->_memPool->SetTracked();
Lee Thomason624d43f2012-10-12 10:58:48 -0700746 addThis->_prev = afterThis;
747 addThis->_next = afterThis->_next;
748 afterThis->_next->_prev = addThis;
749 afterThis->_next = addThis;
750 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700751 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800752}
753
754
755
756
Lee Thomason56bdd022012-02-09 18:16:58 -0800757const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800758{
Lee Thomason624d43f2012-10-12 10:58:48 -0700759 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700760 XMLElement* element = node->ToElement();
761 if ( element ) {
762 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
763 return element;
764 }
765 }
766 }
767 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800768}
769
770
Lee Thomason56bdd022012-02-09 18:16:58 -0800771const XMLElement* XMLNode::LastChildElement( const char* value ) const
772{
Lee Thomason624d43f2012-10-12 10:58:48 -0700773 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700774 XMLElement* element = node->ToElement();
775 if ( element ) {
776 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
777 return element;
778 }
779 }
780 }
781 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800782}
783
784
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800785const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
786{
Lee Thomason624d43f2012-10-12 10:58:48 -0700787 for( XMLNode* element=this->_next; element; element = element->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700788 if ( element->ToElement()
789 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
790 return element->ToElement();
791 }
792 }
793 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800794}
795
796
797const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
798{
Lee Thomason624d43f2012-10-12 10:58:48 -0700799 for( XMLNode* element=_prev; element; element = element->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700800 if ( element->ToElement()
801 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
802 return element->ToElement();
803 }
804 }
805 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800806}
807
808
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800809char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800810{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700811 // This is a recursive method, but thinking about it "at the current level"
812 // it is a pretty simple flat list:
813 // <foo/>
814 // <!-- comment -->
815 //
816 // With a special case:
817 // <foo>
818 // </foo>
819 // <!-- comment -->
820 //
821 // Where the closing element (/foo) *must* be the next thing after the opening
822 // element, and the names must match. BUT the tricky bit is that the closing
823 // element will be read by the child.
824 //
825 // 'endTag' is the end tag for this node, it is returned by a call to a child.
826 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800827
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700828 while( p && *p ) {
829 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800830
Lee Thomason624d43f2012-10-12 10:58:48 -0700831 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700832 if ( p == 0 || node == 0 ) {
833 break;
834 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800835
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700836 StrPair endTag;
837 p = node->ParseDeep( p, &endTag );
838 if ( !p ) {
839 DELETE_NODE( node );
840 node = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -0700841 if ( !_document->Error() ) {
842 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700843 }
844 break;
845 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800846
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700847 // We read the end tag. Return it to the parent.
848 if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
849 if ( parentEnd ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700850 *parentEnd = static_cast<XMLElement*>(node)->_value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700851 }
Lee Thomason5b0a6772012-11-19 13:54:42 -0800852 node->_memPool->SetTracked(); // created and then immediately deleted.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700853 DELETE_NODE( node );
854 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.
859 XMLElement* ele = node->ToElement();
860 if ( ele ) {
861 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700862 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700863 p = 0;
864 }
865 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700866 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700867 p = 0;
868 }
869 else if ( !endTag.Empty() ) {
870 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700871 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700872 p = 0;
873 }
874 }
875 }
876 if ( p == 0 ) {
877 DELETE_NODE( node );
878 node = 0;
879 }
880 if ( node ) {
881 this->InsertEndChild( node );
882 }
883 }
884 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800885}
886
Lee Thomason5492a1c2012-01-23 15:32:10 -0800887// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800888char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800889{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700890 const char* start = p;
891 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700892 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700893 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700894 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700895 }
896 return p;
897 }
898 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700899 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
900 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700901 flags |= StrPair::COLLAPSE_WHITESPACE;
902 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700903
Lee Thomason624d43f2012-10-12 10:58:48 -0700904 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700905 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700906 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700907 }
908 if ( p && *p ) {
909 return p-1;
910 }
911 }
912 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800913}
914
915
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800916XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
917{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700918 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700919 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700920 }
921 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
922 text->SetCData( this->CData() );
923 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800924}
925
926
927bool XMLText::ShallowEqual( const XMLNode* compare ) const
928{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700929 return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800930}
931
932
Lee Thomason56bdd022012-02-09 18:16:58 -0800933bool XMLText::Accept( XMLVisitor* visitor ) const
934{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700935 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800936}
937
938
Lee Thomason3f57d272012-01-11 15:30:03 -0800939// --------- XMLComment ---------- //
940
Lee Thomasone4422302012-01-20 17:59:50 -0800941XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800942{
943}
944
945
Lee Thomasonce0763e2012-01-11 15:43:54 -0800946XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800947{
Lee Thomason3f57d272012-01-11 15:30:03 -0800948}
949
950
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800951char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800952{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700953 // Comment parses as text.
954 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700955 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700956 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700957 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700958 }
959 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800960}
961
962
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800963XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
964{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700965 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700966 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700967 }
968 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
969 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800970}
971
972
973bool XMLComment::ShallowEqual( const XMLNode* compare ) const
974{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700975 return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800976}
977
978
Lee Thomason751da522012-02-10 08:50:51 -0800979bool XMLComment::Accept( XMLVisitor* visitor ) const
980{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700981 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800982}
Lee Thomason56bdd022012-02-09 18:16:58 -0800983
984
Lee Thomason50f97b22012-02-11 16:33:40 -0800985// --------- XMLDeclaration ---------- //
986
987XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
988{
989}
990
991
992XMLDeclaration::~XMLDeclaration()
993{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700994 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -0800995}
996
997
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800998char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800999{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001000 // Declaration parses as text.
1001 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001002 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001003 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001004 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001005 }
1006 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001007}
1008
1009
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001010XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1011{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001012 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001013 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001014 }
1015 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1016 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001017}
1018
1019
1020bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1021{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001022 return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001023}
1024
1025
1026
Lee Thomason50f97b22012-02-11 16:33:40 -08001027bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1028{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001029 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001030}
1031
1032// --------- XMLUnknown ---------- //
1033
1034XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1035{
1036}
1037
1038
1039XMLUnknown::~XMLUnknown()
1040{
1041}
1042
1043
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001044char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001045{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001046 // Unknown parses as text.
1047 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001048
Lee Thomason624d43f2012-10-12 10:58:48 -07001049 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001050 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001051 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001052 }
1053 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001054}
1055
1056
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001057XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1058{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001059 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001060 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001061 }
1062 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1063 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001064}
1065
1066
1067bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1068{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001069 return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001070}
1071
1072
Lee Thomason50f97b22012-02-11 16:33:40 -08001073bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1074{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001075 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001076}
1077
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001078// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001079
1080const char* XMLAttribute::Name() const
1081{
1082 return _name.GetStr();
1083}
1084
1085const char* XMLAttribute::Value() const
1086{
1087 return _value.GetStr();
1088}
1089
Lee Thomason6f381b72012-03-02 12:59:39 -08001090char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001091{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001092 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001093 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001094 if ( !p || !*p ) {
1095 return 0;
1096 }
Lee Thomason22aead12012-01-23 13:29:35 -08001097
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001098 // Skip white space before =
1099 p = XMLUtil::SkipWhiteSpace( p );
1100 if ( !p || *p != '=' ) {
1101 return 0;
1102 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001103
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001104 ++p; // move up to opening quote
1105 p = XMLUtil::SkipWhiteSpace( p );
1106 if ( *p != '\"' && *p != '\'' ) {
1107 return 0;
1108 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001109
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001110 char endTag[2] = { *p, 0 };
1111 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001112
Lee Thomason624d43f2012-10-12 10:58:48 -07001113 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001114 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001115}
1116
1117
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001118void XMLAttribute::SetName( const char* n )
1119{
Lee Thomason624d43f2012-10-12 10:58:48 -07001120 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001121}
1122
1123
Lee Thomason2fa81722012-11-09 12:37:46 -08001124XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001125{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001126 if ( XMLUtil::ToInt( Value(), value )) {
1127 return XML_NO_ERROR;
1128 }
1129 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001130}
1131
1132
Lee Thomason2fa81722012-11-09 12:37:46 -08001133XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001134{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001135 if ( XMLUtil::ToUnsigned( Value(), value )) {
1136 return XML_NO_ERROR;
1137 }
1138 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001139}
1140
1141
Lee Thomason2fa81722012-11-09 12:37:46 -08001142XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001143{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001144 if ( XMLUtil::ToBool( Value(), value )) {
1145 return XML_NO_ERROR;
1146 }
1147 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001148}
1149
1150
Lee Thomason2fa81722012-11-09 12:37:46 -08001151XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001152{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001153 if ( XMLUtil::ToFloat( Value(), value )) {
1154 return XML_NO_ERROR;
1155 }
1156 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001157}
1158
1159
Lee Thomason2fa81722012-11-09 12:37:46 -08001160XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001161{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001162 if ( XMLUtil::ToDouble( Value(), value )) {
1163 return XML_NO_ERROR;
1164 }
1165 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001166}
1167
1168
1169void XMLAttribute::SetAttribute( const char* v )
1170{
Lee Thomason624d43f2012-10-12 10:58:48 -07001171 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001172}
1173
1174
Lee Thomason1ff38e02012-02-14 18:18:16 -08001175void XMLAttribute::SetAttribute( int v )
1176{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001177 char buf[BUF_SIZE];
1178 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001179 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001180}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001181
1182
Uli Kusterer664d0562014-01-21 12:24:47 +01001183void XMLAttribute::SetAttribute( long long v )
1184{
1185 char buf[BUF_SIZE];
1186 XMLUtil::ToStr( v, buf, BUF_SIZE );
1187 _value.SetStr( buf );
1188}
1189
1190
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001191void XMLAttribute::SetAttribute( unsigned v )
1192{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001193 char buf[BUF_SIZE];
1194 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001195 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001196}
1197
1198
1199void XMLAttribute::SetAttribute( bool v )
1200{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001201 char buf[BUF_SIZE];
1202 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001203 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001204}
1205
1206void XMLAttribute::SetAttribute( double 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( float 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
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001220
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001221// --------- XMLElement ---------- //
1222XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001223 _closingType( 0 ),
1224 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001225{
1226}
1227
1228
1229XMLElement::~XMLElement()
1230{
Lee Thomason624d43f2012-10-12 10:58:48 -07001231 while( _rootAttribute ) {
1232 XMLAttribute* next = _rootAttribute->_next;
1233 DELETE_ATTRIBUTE( _rootAttribute );
1234 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001235 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001236}
1237
1238
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001239XMLAttribute* XMLElement::FindAttribute( const char* name )
1240{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001241 XMLAttribute* a = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001242 for( a=_rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001243 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1244 return a;
1245 }
1246 }
1247 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001248}
1249
1250
1251const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1252{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001253 XMLAttribute* a = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001254 for( a=_rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001255 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1256 return a;
1257 }
1258 }
1259 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001260}
1261
1262
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001263const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001264{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001265 const XMLAttribute* a = FindAttribute( name );
1266 if ( !a ) {
1267 return 0;
1268 }
1269 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1270 return a->Value();
1271 }
1272 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001273}
1274
1275
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001276const char* XMLElement::GetText() const
1277{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001278 if ( FirstChild() && FirstChild()->ToText() ) {
1279 return FirstChild()->ToText()->Value();
1280 }
1281 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001282}
1283
1284
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001285void XMLElement::SetText( const char* inText )
1286{
Uli Kusterer869bb592014-01-21 01:36:16 +01001287 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001288 FirstChild()->SetValue( inText );
1289 else {
1290 XMLText* theText = GetDocument()->NewText( inText );
1291 InsertFirstChild( theText );
1292 }
1293}
1294
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001295
Lee Thomason5bb2d802014-01-24 10:42:57 -08001296void XMLElement::SetText( int v )
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001297{
1298 char buf[BUF_SIZE];
Lee Thomason5bb2d802014-01-24 10:42:57 -08001299 XMLUtil::ToStr( v, buf, BUF_SIZE );
1300 SetText( buf );
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001301}
1302
1303
Lee Thomason5bb2d802014-01-24 10:42:57 -08001304void XMLElement::SetText( unsigned v )
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001305{
1306 char buf[BUF_SIZE];
Lee Thomason5bb2d802014-01-24 10:42:57 -08001307 XMLUtil::ToStr( v, buf, BUF_SIZE );
1308 SetText( buf );
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001309}
1310
1311
Lee Thomason5bb2d802014-01-24 10:42:57 -08001312void XMLElement::SetText( bool v )
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001313{
1314 char buf[BUF_SIZE];
Lee Thomason5bb2d802014-01-24 10:42:57 -08001315 XMLUtil::ToStr( v, buf, BUF_SIZE );
1316 SetText( buf );
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001317}
1318
1319
Lee Thomason5bb2d802014-01-24 10:42:57 -08001320void XMLElement::SetText( float v )
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001321{
1322 char buf[BUF_SIZE];
Lee Thomason5bb2d802014-01-24 10:42:57 -08001323 XMLUtil::ToStr( v, buf, BUF_SIZE );
1324 SetText( buf );
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001325}
1326
Lee Thomason5bb2d802014-01-24 10:42:57 -08001327
Uli Kusterer35ce3092014-01-25 03:37:16 +01001328void XMLElement::SetText( double v )
1329{
1330 char buf[BUF_SIZE];
1331 XMLUtil::ToStr( v, buf, BUF_SIZE );
1332 SetText( buf );
1333}
1334
1335
1336void XMLElement::SetText( long long v )
Uli Kusterer664d0562014-01-21 12:24:47 +01001337{
1338 char buf[BUF_SIZE];
Lee Thomason5bb2d802014-01-24 10:42:57 -08001339 XMLUtil::ToStr( v, buf, BUF_SIZE );
1340 SetText( buf );
Uli Kusterer664d0562014-01-21 12:24:47 +01001341}
1342
1343
Uli Kustererc1c20bb2014-01-21 02:23:20 +01001344void XMLElement::SetBoolFirstChild( bool inBool )
1345{
1346 if( FirstChild() && FirstChild()->ToElement()
1347 && (strcmp(FirstChild()->Value(),"true") == 0 || strcmp(FirstChild()->Value(),"false") == 0) ) {
1348 FirstChild()->SetValue( inBool ? "true" : "false" );
1349 }
1350 else if( !FirstChild() ) {
1351 XMLElement* theText = GetDocument()->NewElement( inBool ? "true" : "false" );
1352 InsertFirstChild( theText );
1353 }
1354}
1355
1356
Uli Kustererff8e2042014-01-21 02:53:47 +01001357XMLError XMLElement::QueryBoolFirstChild( bool *outBool )
Uli Kustererc1c20bb2014-01-21 02:23:20 +01001358{
Uli Kustererff8e2042014-01-21 02:53:47 +01001359 if ( FirstChild() )
1360 {
1361 if ( FirstChild()->ToElement() )
1362 {
1363 bool isTrue = strcmp( FirstChild()->Value(), "true" ) == 0;
1364 bool isFalse = strcmp( FirstChild()->Value(), "false" ) == 0;
1365 if( !isTrue && !isFalse )
1366 return XML_CAN_NOT_CONVERT_TEXT;
1367
1368 *outBool = isTrue;
1369 return XML_SUCCESS;
1370 }
1371 else
1372 return XML_NO_ELEMENT_NODE;
Uli Kustererc1c20bb2014-01-21 02:23:20 +01001373 }
Uli Kustererff8e2042014-01-21 02:53:47 +01001374 else
1375 return XML_NO_ELEMENT_NODE;
Uli Kustererc1c20bb2014-01-21 02:23:20 +01001376}
1377
1378
MortenMacFly4ee49f12013-01-14 20:03:14 +01001379XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001380{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001381 if ( FirstChild() && FirstChild()->ToText() ) {
1382 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001383 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001384 return XML_SUCCESS;
1385 }
1386 return XML_CAN_NOT_CONVERT_TEXT;
1387 }
1388 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001389}
1390
1391
Uli Kusterer664d0562014-01-21 12:24:47 +01001392XMLError XMLElement::QueryLongLongText( long long* ival ) const
1393{
1394 if ( FirstChild() && FirstChild()->ToText() ) {
1395 const char* t = FirstChild()->ToText()->Value();
1396 if ( XMLUtil::ToLongLong( t, ival ) ) {
1397 return XML_SUCCESS;
1398 }
1399 return XML_CAN_NOT_CONVERT_TEXT;
1400 }
1401 return XML_NO_TEXT_NODE;
1402}
1403
1404
MortenMacFly4ee49f12013-01-14 20:03:14 +01001405XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001406{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001407 if ( FirstChild() && FirstChild()->ToText() ) {
1408 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001409 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001410 return XML_SUCCESS;
1411 }
1412 return XML_CAN_NOT_CONVERT_TEXT;
1413 }
1414 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001415}
1416
1417
MortenMacFly4ee49f12013-01-14 20:03:14 +01001418XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001419{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001420 if ( FirstChild() && FirstChild()->ToText() ) {
1421 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001422 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001423 return XML_SUCCESS;
1424 }
1425 return XML_CAN_NOT_CONVERT_TEXT;
1426 }
1427 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001428}
1429
1430
MortenMacFly4ee49f12013-01-14 20:03:14 +01001431XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001432{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001433 if ( FirstChild() && FirstChild()->ToText() ) {
1434 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001435 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001436 return XML_SUCCESS;
1437 }
1438 return XML_CAN_NOT_CONVERT_TEXT;
1439 }
1440 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001441}
1442
1443
MortenMacFly4ee49f12013-01-14 20:03:14 +01001444XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001445{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001446 if ( FirstChild() && FirstChild()->ToText() ) {
1447 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001448 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001449 return XML_SUCCESS;
1450 }
1451 return XML_CAN_NOT_CONVERT_TEXT;
1452 }
1453 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001454}
1455
1456
1457
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001458XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1459{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001460 XMLAttribute* last = 0;
1461 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001462 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001463 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001464 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001465 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1466 break;
1467 }
1468 }
1469 if ( !attrib ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001470 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1471 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001472 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001473 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001474 }
1475 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001476 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001477 }
1478 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001479 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001480 }
1481 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001482}
1483
1484
U-Stream\Leeae25a442012-02-17 17:48:16 -08001485void XMLElement::DeleteAttribute( const char* name )
1486{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001487 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001488 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001489 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1490 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001491 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001492 }
1493 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001494 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001495 }
1496 DELETE_ATTRIBUTE( a );
1497 break;
1498 }
1499 prev = a;
1500 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001501}
1502
1503
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001504char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001505{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001506 const char* start = p;
1507 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001508
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001509 // Read the attributes.
1510 while( p ) {
1511 p = XMLUtil::SkipWhiteSpace( p );
1512 if ( !p || !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001513 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001514 return 0;
1515 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001516
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001517 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001518 if (XMLUtil::IsNameStartChar( *p ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001519 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1520 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001521 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001522
Lee Thomason624d43f2012-10-12 10:58:48 -07001523 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001524 if ( !p || Attribute( attrib->Name() ) ) {
1525 DELETE_ATTRIBUTE( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001526 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001527 return 0;
1528 }
1529 // There is a minor bug here: if the attribute in the source xml
1530 // document is duplicated, it will not be detected and the
1531 // attribute will be doubly added. However, tracking the 'prevAttribute'
1532 // avoids re-scanning the attribute list. Preferring performance for
1533 // now, may reconsider in the future.
1534 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001535 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001536 }
1537 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001538 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001539 }
1540 prevAttribute = attrib;
1541 }
1542 // end of the tag
1543 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001544 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001545 return p+2; // done; sealed element.
1546 }
1547 // end of the tag
1548 else if ( *p == '>' ) {
1549 ++p;
1550 break;
1551 }
1552 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001553 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001554 return 0;
1555 }
1556 }
1557 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001558}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001559
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001560
Lee Thomason67d61312012-01-24 16:01:51 -08001561//
1562// <ele></ele>
1563// <ele>foo<b>bar</b></ele>
1564//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001565char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001566{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001567 // Read the element name.
1568 p = XMLUtil::SkipWhiteSpace( p );
1569 if ( !p ) {
1570 return 0;
1571 }
Lee Thomason67d61312012-01-24 16:01:51 -08001572
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001573 // The closing element is the </element> form. It is
1574 // parsed just like a regular element then deleted from
1575 // the DOM.
1576 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001577 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001578 ++p;
1579 }
Lee Thomason67d61312012-01-24 16:01:51 -08001580
Lee Thomason624d43f2012-10-12 10:58:48 -07001581 p = _value.ParseName( p );
1582 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001583 return 0;
1584 }
Lee Thomason67d61312012-01-24 16:01:51 -08001585
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001586 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001587 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001588 return p;
1589 }
Lee Thomason67d61312012-01-24 16:01:51 -08001590
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001591 p = XMLNode::ParseDeep( p, strPair );
1592 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001593}
1594
1595
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001596
1597XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1598{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001599 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001600 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001601 }
1602 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1603 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1604 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1605 }
1606 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001607}
1608
1609
1610bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1611{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001612 const XMLElement* other = compare->ToElement();
1613 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001614
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001615 const XMLAttribute* a=FirstAttribute();
1616 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001617
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001618 while ( a && b ) {
1619 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1620 return false;
1621 }
1622 a = a->Next();
1623 b = b->Next();
1624 }
1625 if ( a || b ) {
1626 // different count
1627 return false;
1628 }
1629 return true;
1630 }
1631 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001632}
1633
1634
Lee Thomason751da522012-02-10 08:50:51 -08001635bool XMLElement::Accept( XMLVisitor* visitor ) const
1636{
Lee Thomason624d43f2012-10-12 10:58:48 -07001637 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001638 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1639 if ( !node->Accept( visitor ) ) {
1640 break;
1641 }
1642 }
1643 }
1644 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001645}
Lee Thomason56bdd022012-02-09 18:16:58 -08001646
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001647
Lee Thomason3f57d272012-01-11 15:30:03 -08001648// --------- XMLDocument ----------- //
Lee Thomason624d43f2012-10-12 10:58:48 -07001649XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001650 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001651 _writeBOM( false ),
1652 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001653 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001654 _whitespace( whitespace ),
1655 _errorStr1( 0 ),
1656 _errorStr2( 0 ),
1657 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001658{
Lee Thomason624d43f2012-10-12 10:58:48 -07001659 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001660}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001661
1662
Lee Thomason3f57d272012-01-11 15:30:03 -08001663XMLDocument::~XMLDocument()
1664{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001665 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -07001666 delete [] _charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001667
Lee Thomason (grinliz)61cea672013-02-01 19:13:13 -08001668#if 0
Lee Thomason (grinliz)ac83b4e2013-02-01 09:02:34 -08001669 _textPool.Trace( "text" );
1670 _elementPool.Trace( "element" );
1671 _commentPool.Trace( "comment" );
1672 _attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -08001673#endif
1674
Lee Thomason5b0a6772012-11-19 13:54:42 -08001675#ifdef DEBUG
1676 if ( Error() == false ) {
1677 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1678 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1679 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1680 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1681 }
1682#endif
Lee Thomason3f57d272012-01-11 15:30:03 -08001683}
1684
1685
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001686void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001687{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001688 DeleteChildren();
1689
Lee Thomason624d43f2012-10-12 10:58:48 -07001690 _errorID = XML_NO_ERROR;
1691 _errorStr1 = 0;
1692 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001693
Lee Thomason624d43f2012-10-12 10:58:48 -07001694 delete [] _charBuffer;
1695 _charBuffer = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001696}
1697
Lee Thomason3f57d272012-01-11 15:30:03 -08001698
Lee Thomason2c85a712012-01-31 08:24:24 -08001699XMLElement* XMLDocument::NewElement( const char* name )
1700{
Lee Thomason624d43f2012-10-12 10:58:48 -07001701 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1702 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001703 ele->SetName( name );
1704 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001705}
1706
1707
Lee Thomason1ff38e02012-02-14 18:18:16 -08001708XMLComment* XMLDocument::NewComment( const char* str )
1709{
Lee Thomason624d43f2012-10-12 10:58:48 -07001710 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1711 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001712 comment->SetValue( str );
1713 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001714}
1715
1716
1717XMLText* XMLDocument::NewText( const char* str )
1718{
Lee Thomason624d43f2012-10-12 10:58:48 -07001719 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1720 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001721 text->SetValue( str );
1722 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001723}
1724
1725
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001726XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1727{
Lee Thomason624d43f2012-10-12 10:58:48 -07001728 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1729 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001730 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1731 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001732}
1733
1734
1735XMLUnknown* XMLDocument::NewUnknown( const char* str )
1736{
Lee Thomason624d43f2012-10-12 10:58:48 -07001737 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1738 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001739 unk->SetValue( str );
1740 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001741}
1742
1743
Lee Thomason2fa81722012-11-09 12:37:46 -08001744XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001745{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001746 Clear();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001747 FILE* fp = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001748
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001749#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1750 errno_t err = fopen_s(&fp, filename, "rb" );
1751 if ( !fp || err) {
1752#else
1753 fp = fopen( filename, "rb" );
1754 if ( !fp) {
1755#endif
1756 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001757 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001758 }
1759 LoadFile( fp );
1760 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001761 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001762}
1763
1764
Lee Thomason2fa81722012-11-09 12:37:46 -08001765XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001766{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001767 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001768
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001769 fseek( fp, 0, SEEK_SET );
1770 fgetc( fp );
1771 if ( ferror( fp ) != 0 ) {
1772 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1773 return _errorID;
1774 }
1775
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001776 fseek( fp, 0, SEEK_END );
1777 size_t size = ftell( fp );
1778 fseek( fp, 0, SEEK_SET );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001779
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001780 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001781 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001782 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001783 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001784
Lee Thomason624d43f2012-10-12 10:58:48 -07001785 _charBuffer = new char[size+1];
1786 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001787 if ( read != size ) {
1788 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001789 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001790 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001791
Lee Thomason624d43f2012-10-12 10:58:48 -07001792 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001793
Lee Thomason624d43f2012-10-12 10:58:48 -07001794 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001795 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001796 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001797 if ( !p || !*p ) {
1798 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001799 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001800 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001801
Lee Thomason624d43f2012-10-12 10:58:48 -07001802 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1803 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001804}
1805
1806
Lee Thomason2fa81722012-11-09 12:37:46 -08001807XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001808{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001809 FILE* fp = 0;
1810#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1811 errno_t err = fopen_s(&fp, filename, "w" );
1812 if ( !fp || err) {
1813#else
1814 fp = fopen( filename, "w" );
1815 if ( !fp) {
1816#endif
1817 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001818 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001819 }
1820 SaveFile(fp, compact);
1821 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001822 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001823}
1824
1825
Lee Thomason2fa81722012-11-09 12:37:46 -08001826XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001827{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001828 XMLPrinter stream( fp, compact );
1829 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001830 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001831}
1832
Lee Thomason1ff38e02012-02-14 18:18:16 -08001833
Lee Thomason2fa81722012-11-09 12:37:46 -08001834XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001835{
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001836 const char* start = p;
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001837 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001838
psi690ba072013-11-03 10:54:33 +09001839 if ( len == 0 ) {
1840 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1841 return _errorID;
1842 }
1843
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001844 if ( !p || !*p ) {
1845 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001846 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001847 }
1848 if ( len == (size_t)(-1) ) {
1849 len = strlen( p );
1850 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001851 _charBuffer = new char[ len+1 ];
1852 memcpy( _charBuffer, p, len );
1853 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001854
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001855 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001856 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001857 if ( !p || !*p ) {
1858 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001859 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001860 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001861
Thomas Roß1470edc2013-05-10 15:44:12 +02001862 ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001863 ParseDeep( _charBuffer+delta, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001864 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001865}
1866
1867
PKEuS1c5f99e2013-07-06 11:28:39 +02001868void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001869{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001870 XMLPrinter stdStreamer( stdout );
1871 if ( !streamer ) {
1872 streamer = &stdStreamer;
1873 }
1874 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001875}
1876
1877
Lee Thomason2fa81722012-11-09 12:37:46 -08001878void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001879{
Lee Thomason624d43f2012-10-12 10:58:48 -07001880 _errorID = error;
1881 _errorStr1 = str1;
1882 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001883}
1884
Lee Thomason5cae8972012-01-24 18:03:07 -08001885
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001886void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001887{
Lee Thomason624d43f2012-10-12 10:58:48 -07001888 if ( _errorID ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001889 static const int LEN = 20;
1890 char buf1[LEN] = { 0 };
1891 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001892
Lee Thomason624d43f2012-10-12 10:58:48 -07001893 if ( _errorStr1 ) {
1894 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001895 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001896 if ( _errorStr2 ) {
1897 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001898 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001899
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001900 printf( "XMLDocument error id=%d str1=%s str2=%s\n",
Lee Thomason624d43f2012-10-12 10:58:48 -07001901 _errorID, buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001902 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001903}
1904
1905
PKEuS1bfb9542013-08-04 13:51:17 +02001906XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001907 _elementJustOpened( false ),
1908 _firstElement( true ),
1909 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001910 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001911 _textDepth( -1 ),
1912 _processEntities( true ),
1913 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001914{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001915 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001916 _entityFlag[i] = false;
1917 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001918 }
1919 for( int i=0; i<NUM_ENTITIES; ++i ) {
1920 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1921 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001922 _entityFlag[ (int)entities[i].value ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001923 }
1924 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001925 _restrictedEntityFlag[(int)'&'] = true;
1926 _restrictedEntityFlag[(int)'<'] = true;
1927 _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
1928 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001929}
1930
1931
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001932void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001933{
1934 va_list va;
1935 va_start( va, format );
1936
Lee Thomason624d43f2012-10-12 10:58:48 -07001937 if ( _fp ) {
1938 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001939 }
1940 else {
1941 // This seems brutally complex. Haven't figured out a better
1942 // way on windows.
1943#ifdef _MSC_VER
1944 int len = -1;
1945 int expand = 1000;
1946 while ( len < 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001947 len = vsnprintf_s( _accumulator.Mem(), _accumulator.Capacity(), _TRUNCATE, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001948 if ( len < 0 ) {
1949 expand *= 3/2;
Lee Thomason1aa8fc42012-10-13 20:01:30 -07001950 _accumulator.PushArr( expand );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001951 }
1952 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001953 char* p = _buffer.PushArr( len ) - 1;
1954 memcpy( p, _accumulator.Mem(), len+1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001955#else
1956 int len = vsnprintf( 0, 0, format, va );
1957 // Close out and re-start the va-args
1958 va_end( va );
1959 va_start( va, format );
Lee Thomason624d43f2012-10-12 10:58:48 -07001960 char* p = _buffer.PushArr( len ) - 1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001961 vsnprintf( p, len+1, format, va );
1962#endif
1963 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001964 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001965}
1966
1967
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001968void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001969{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001970 for( int i=0; i<depth; ++i ) {
1971 Print( " " );
1972 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001973}
1974
1975
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001976void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001977{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001978 // Look for runs of bytes between entities to print.
1979 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001980 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001981
Lee Thomason624d43f2012-10-12 10:58:48 -07001982 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001983 while ( *q ) {
1984 // Remember, char is sometimes signed. (How many times has that bitten me?)
1985 if ( *q > 0 && *q < ENTITY_RANGE ) {
1986 // Check for entities. If one is found, flush
1987 // the stream up until the entity, write the
1988 // entity, and keep looking.
1989 if ( flag[(unsigned)(*q)] ) {
1990 while ( p < q ) {
1991 Print( "%c", *p );
1992 ++p;
1993 }
1994 for( int i=0; i<NUM_ENTITIES; ++i ) {
1995 if ( entities[i].value == *q ) {
1996 Print( "&%s;", entities[i].pattern );
1997 break;
1998 }
1999 }
2000 ++p;
2001 }
2002 }
2003 ++q;
2004 }
2005 }
2006 // Flush the remaining string. This will be the entire
2007 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07002008 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002009 Print( "%s", p );
2010 }
Lee Thomason857b8682012-01-25 17:50:25 -08002011}
2012
U-Stream\Leeae25a442012-02-17 17:48:16 -08002013
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002014void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002015{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002016 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002017 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 -07002018 Print( "%s", bom );
2019 }
2020 if ( writeDec ) {
2021 PushDeclaration( "xml version=\"1.0\"" );
2022 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002023}
2024
2025
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002026void XMLPrinter::OpenElement( const char* name )
Lee Thomason5cae8972012-01-24 18:03:07 -08002027{
Lee Thomason624d43f2012-10-12 10:58:48 -07002028 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002029 SealElement();
2030 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002031 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002032
Lee Thomason624d43f2012-10-12 10:58:48 -07002033 if ( _textDepth < 0 && !_firstElement && !_compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002034 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002035 }
2036 if ( !_compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002037 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002038 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002039
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002040 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002041 _elementJustOpened = true;
2042 _firstElement = false;
2043 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002044}
2045
2046
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002047void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002048{
Lee Thomason624d43f2012-10-12 10:58:48 -07002049 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002050 Print( " %s=\"", name );
2051 PrintString( value, false );
2052 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002053}
2054
2055
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002056void XMLPrinter::PushAttribute( const char* name, int v )
2057{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002058 char buf[BUF_SIZE];
2059 XMLUtil::ToStr( v, buf, BUF_SIZE );
2060 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002061}
2062
2063
2064void XMLPrinter::PushAttribute( const char* name, unsigned v )
2065{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002066 char buf[BUF_SIZE];
2067 XMLUtil::ToStr( v, buf, BUF_SIZE );
2068 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002069}
2070
2071
2072void XMLPrinter::PushAttribute( const char* name, bool v )
2073{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002074 char buf[BUF_SIZE];
2075 XMLUtil::ToStr( v, buf, BUF_SIZE );
2076 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002077}
2078
2079
2080void XMLPrinter::PushAttribute( const char* name, double v )
2081{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002082 char buf[BUF_SIZE];
2083 XMLUtil::ToStr( v, buf, BUF_SIZE );
2084 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002085}
2086
2087
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002088void XMLPrinter::CloseElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08002089{
Lee Thomason624d43f2012-10-12 10:58:48 -07002090 --_depth;
2091 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002092
Lee Thomason624d43f2012-10-12 10:58:48 -07002093 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002094 Print( "/>" );
2095 }
2096 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07002097 if ( _textDepth < 0 && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002098 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002099 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002100 }
2101 Print( "</%s>", name );
2102 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002103
Lee Thomason624d43f2012-10-12 10:58:48 -07002104 if ( _textDepth == _depth ) {
2105 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002106 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002107 if ( _depth == 0 && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002108 Print( "\n" );
2109 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002110 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002111}
2112
2113
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002114void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08002115{
Lee Thomason624d43f2012-10-12 10:58:48 -07002116 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002117 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002118}
2119
2120
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002121void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002122{
Lee Thomason624d43f2012-10-12 10:58:48 -07002123 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002124
Lee Thomason624d43f2012-10-12 10:58:48 -07002125 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002126 SealElement();
2127 }
2128 if ( cdata ) {
2129 Print( "<![CDATA[" );
2130 Print( "%s", text );
2131 Print( "]]>" );
2132 }
2133 else {
2134 PrintString( text, true );
2135 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002136}
2137
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002138void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002139{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002140 char buf[BUF_SIZE];
2141 XMLUtil::ToStr( value, buf, BUF_SIZE );
2142 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002143}
2144
2145
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002146void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002147{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002148 char buf[BUF_SIZE];
2149 XMLUtil::ToStr( value, buf, BUF_SIZE );
2150 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002151}
2152
2153
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002154void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002155{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002156 char buf[BUF_SIZE];
2157 XMLUtil::ToStr( value, buf, BUF_SIZE );
2158 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002159}
2160
2161
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002162void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002163{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002164 char buf[BUF_SIZE];
2165 XMLUtil::ToStr( value, buf, BUF_SIZE );
2166 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002167}
2168
2169
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002170void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002171{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002172 char buf[BUF_SIZE];
2173 XMLUtil::ToStr( value, buf, BUF_SIZE );
2174 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002175}
2176
Lee Thomason5cae8972012-01-24 18:03:07 -08002177
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002178void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002179{
Lee Thomason624d43f2012-10-12 10:58:48 -07002180 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002181 SealElement();
2182 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002183 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002184 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002185 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002186 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002187 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002188 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002189}
Lee Thomason751da522012-02-10 08:50:51 -08002190
2191
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002192void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002193{
Lee Thomason624d43f2012-10-12 10:58:48 -07002194 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002195 SealElement();
2196 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002197 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002198 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002199 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002200 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002201 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002202 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002203}
2204
2205
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002206void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002207{
Lee Thomason624d43f2012-10-12 10:58:48 -07002208 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002209 SealElement();
2210 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002211 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002212 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002213 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002214 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002215 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002216 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002217}
2218
2219
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002220bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002221{
Lee Thomason624d43f2012-10-12 10:58:48 -07002222 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002223 if ( doc.HasBOM() ) {
2224 PushHeader( true, false );
2225 }
2226 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002227}
2228
2229
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002230bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002231{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002232 OpenElement( element.Name() );
2233 while ( attribute ) {
2234 PushAttribute( attribute->Name(), attribute->Value() );
2235 attribute = attribute->Next();
2236 }
2237 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002238}
2239
2240
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08002241bool XMLPrinter::VisitExit( const XMLElement& )
Lee Thomason751da522012-02-10 08:50:51 -08002242{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002243 CloseElement();
2244 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002245}
2246
2247
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002248bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002249{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002250 PushText( text.Value(), text.CData() );
2251 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002252}
2253
2254
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002255bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002256{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002257 PushComment( comment.Value() );
2258 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002259}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002260
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002261bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002262{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002263 PushDeclaration( declaration.Value() );
2264 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002265}
2266
2267
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002268bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002269{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002270 PushUnknown( unknown.Value() );
2271 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002272}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002273
Lee Thomason685b8952012-11-12 13:00:06 -08002274} // namespace tinyxml2
2275