blob: efaa29a9049328a47f53c648aebf0e1d2db93312 [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
1296void XMLElement::SetText( int inNum )
1297{
1298 char buf[BUF_SIZE];
1299 XMLUtil::ToStr( inNum, buf, BUF_SIZE );
1300 if ( FirstChild() && FirstChild()->ToText() )
1301 FirstChild()->SetValue( buf );
1302 else {
1303 XMLText* theText = GetDocument()->NewText( buf );
1304 InsertFirstChild( theText );
1305 }
1306}
1307
1308
1309void XMLElement::SetText( unsigned inNum )
1310{
1311 char buf[BUF_SIZE];
1312 XMLUtil::ToStr( inNum, buf, BUF_SIZE );
1313 if ( FirstChild() && FirstChild()->ToText() )
1314 FirstChild()->SetValue( buf );
1315 else {
1316 XMLText* theText = GetDocument()->NewText( buf );
1317 InsertFirstChild( theText );
1318 }
1319}
1320
1321
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001322void XMLElement::SetText( double inNum )
1323{
1324 char buf[BUF_SIZE];
1325 XMLUtil::ToStr( inNum, buf, BUF_SIZE );
1326 if ( FirstChild() && FirstChild()->ToText() )
1327 FirstChild()->SetValue( buf );
1328 else {
1329 XMLText* theText = GetDocument()->NewText( buf );
1330 InsertFirstChild( theText );
1331 }
1332}
1333
1334
1335void XMLElement::SetText( float inNum )
1336{
1337 char buf[BUF_SIZE];
1338 XMLUtil::ToStr( inNum, buf, BUF_SIZE );
1339 if ( FirstChild() && FirstChild()->ToText() )
1340 FirstChild()->SetValue( buf );
1341 else {
1342 XMLText* theText = GetDocument()->NewText( buf );
1343 InsertFirstChild( theText );
1344 }
1345}
1346
Uli Kusterer664d0562014-01-21 12:24:47 +01001347void XMLElement::SetText( long long inNum )
1348{
1349 char buf[BUF_SIZE];
1350 XMLUtil::ToStr( inNum, buf, BUF_SIZE );
1351 if ( FirstChild() && FirstChild()->ToText() )
1352 FirstChild()->SetValue( buf );
1353 else {
1354 XMLText* theText = GetDocument()->NewText( buf );
1355 InsertFirstChild( theText );
1356 }
1357}
1358
1359
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001360
Uli Kustererc1c20bb2014-01-21 02:23:20 +01001361void XMLElement::SetBoolFirstChild( bool inBool )
1362{
1363 if( FirstChild() && FirstChild()->ToElement()
1364 && (strcmp(FirstChild()->Value(),"true") == 0 || strcmp(FirstChild()->Value(),"false") == 0) ) {
1365 FirstChild()->SetValue( inBool ? "true" : "false" );
1366 }
1367 else if( !FirstChild() ) {
1368 XMLElement* theText = GetDocument()->NewElement( inBool ? "true" : "false" );
1369 InsertFirstChild( theText );
1370 }
1371}
1372
1373
Uli Kustererff8e2042014-01-21 02:53:47 +01001374XMLError XMLElement::QueryBoolFirstChild( bool *outBool )
Uli Kustererc1c20bb2014-01-21 02:23:20 +01001375{
Uli Kustererff8e2042014-01-21 02:53:47 +01001376 if ( FirstChild() )
1377 {
1378 if ( FirstChild()->ToElement() )
1379 {
1380 bool isTrue = strcmp( FirstChild()->Value(), "true" ) == 0;
1381 bool isFalse = strcmp( FirstChild()->Value(), "false" ) == 0;
1382 if( !isTrue && !isFalse )
1383 return XML_CAN_NOT_CONVERT_TEXT;
1384
1385 *outBool = isTrue;
1386 return XML_SUCCESS;
1387 }
1388 else
1389 return XML_NO_ELEMENT_NODE;
Uli Kustererc1c20bb2014-01-21 02:23:20 +01001390 }
Uli Kustererff8e2042014-01-21 02:53:47 +01001391 else
1392 return XML_NO_ELEMENT_NODE;
Uli Kustererc1c20bb2014-01-21 02:23:20 +01001393}
1394
1395
MortenMacFly4ee49f12013-01-14 20:03:14 +01001396XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001397{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001398 if ( FirstChild() && FirstChild()->ToText() ) {
1399 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001400 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001401 return XML_SUCCESS;
1402 }
1403 return XML_CAN_NOT_CONVERT_TEXT;
1404 }
1405 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001406}
1407
1408
Uli Kusterer664d0562014-01-21 12:24:47 +01001409XMLError XMLElement::QueryLongLongText( long long* ival ) const
1410{
1411 if ( FirstChild() && FirstChild()->ToText() ) {
1412 const char* t = FirstChild()->ToText()->Value();
1413 if ( XMLUtil::ToLongLong( t, ival ) ) {
1414 return XML_SUCCESS;
1415 }
1416 return XML_CAN_NOT_CONVERT_TEXT;
1417 }
1418 return XML_NO_TEXT_NODE;
1419}
1420
1421
MortenMacFly4ee49f12013-01-14 20:03:14 +01001422XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001423{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001424 if ( FirstChild() && FirstChild()->ToText() ) {
1425 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001426 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001427 return XML_SUCCESS;
1428 }
1429 return XML_CAN_NOT_CONVERT_TEXT;
1430 }
1431 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001432}
1433
1434
MortenMacFly4ee49f12013-01-14 20:03:14 +01001435XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001436{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001437 if ( FirstChild() && FirstChild()->ToText() ) {
1438 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001439 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001440 return XML_SUCCESS;
1441 }
1442 return XML_CAN_NOT_CONVERT_TEXT;
1443 }
1444 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001445}
1446
1447
MortenMacFly4ee49f12013-01-14 20:03:14 +01001448XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001449{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001450 if ( FirstChild() && FirstChild()->ToText() ) {
1451 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001452 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001453 return XML_SUCCESS;
1454 }
1455 return XML_CAN_NOT_CONVERT_TEXT;
1456 }
1457 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001458}
1459
1460
MortenMacFly4ee49f12013-01-14 20:03:14 +01001461XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001462{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001463 if ( FirstChild() && FirstChild()->ToText() ) {
1464 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001465 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001466 return XML_SUCCESS;
1467 }
1468 return XML_CAN_NOT_CONVERT_TEXT;
1469 }
1470 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001471}
1472
1473
1474
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001475XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1476{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001477 XMLAttribute* last = 0;
1478 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001479 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001480 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001481 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001482 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1483 break;
1484 }
1485 }
1486 if ( !attrib ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001487 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1488 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001489 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001490 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001491 }
1492 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001493 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001494 }
1495 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001496 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001497 }
1498 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001499}
1500
1501
U-Stream\Leeae25a442012-02-17 17:48:16 -08001502void XMLElement::DeleteAttribute( const char* name )
1503{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001504 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001505 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001506 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1507 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001508 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001509 }
1510 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001511 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001512 }
1513 DELETE_ATTRIBUTE( a );
1514 break;
1515 }
1516 prev = a;
1517 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001518}
1519
1520
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001521char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001522{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001523 const char* start = p;
1524 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001525
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001526 // Read the attributes.
1527 while( p ) {
1528 p = XMLUtil::SkipWhiteSpace( p );
1529 if ( !p || !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001530 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001531 return 0;
1532 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001533
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001534 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001535 if (XMLUtil::IsNameStartChar( *p ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001536 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1537 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001538 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001539
Lee Thomason624d43f2012-10-12 10:58:48 -07001540 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001541 if ( !p || Attribute( attrib->Name() ) ) {
1542 DELETE_ATTRIBUTE( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001543 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001544 return 0;
1545 }
1546 // There is a minor bug here: if the attribute in the source xml
1547 // document is duplicated, it will not be detected and the
1548 // attribute will be doubly added. However, tracking the 'prevAttribute'
1549 // avoids re-scanning the attribute list. Preferring performance for
1550 // now, may reconsider in the future.
1551 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001552 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001553 }
1554 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001555 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001556 }
1557 prevAttribute = attrib;
1558 }
1559 // end of the tag
1560 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001561 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001562 return p+2; // done; sealed element.
1563 }
1564 // end of the tag
1565 else if ( *p == '>' ) {
1566 ++p;
1567 break;
1568 }
1569 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001570 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001571 return 0;
1572 }
1573 }
1574 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001575}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001576
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001577
Lee Thomason67d61312012-01-24 16:01:51 -08001578//
1579// <ele></ele>
1580// <ele>foo<b>bar</b></ele>
1581//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001582char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001583{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001584 // Read the element name.
1585 p = XMLUtil::SkipWhiteSpace( p );
1586 if ( !p ) {
1587 return 0;
1588 }
Lee Thomason67d61312012-01-24 16:01:51 -08001589
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001590 // The closing element is the </element> form. It is
1591 // parsed just like a regular element then deleted from
1592 // the DOM.
1593 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001594 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001595 ++p;
1596 }
Lee Thomason67d61312012-01-24 16:01:51 -08001597
Lee Thomason624d43f2012-10-12 10:58:48 -07001598 p = _value.ParseName( p );
1599 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001600 return 0;
1601 }
Lee Thomason67d61312012-01-24 16:01:51 -08001602
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001603 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001604 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001605 return p;
1606 }
Lee Thomason67d61312012-01-24 16:01:51 -08001607
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001608 p = XMLNode::ParseDeep( p, strPair );
1609 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001610}
1611
1612
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001613
1614XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1615{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001616 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001617 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001618 }
1619 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1620 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1621 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1622 }
1623 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001624}
1625
1626
1627bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1628{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001629 const XMLElement* other = compare->ToElement();
1630 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001631
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001632 const XMLAttribute* a=FirstAttribute();
1633 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001634
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001635 while ( a && b ) {
1636 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1637 return false;
1638 }
1639 a = a->Next();
1640 b = b->Next();
1641 }
1642 if ( a || b ) {
1643 // different count
1644 return false;
1645 }
1646 return true;
1647 }
1648 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001649}
1650
1651
Lee Thomason751da522012-02-10 08:50:51 -08001652bool XMLElement::Accept( XMLVisitor* visitor ) const
1653{
Lee Thomason624d43f2012-10-12 10:58:48 -07001654 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001655 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1656 if ( !node->Accept( visitor ) ) {
1657 break;
1658 }
1659 }
1660 }
1661 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001662}
Lee Thomason56bdd022012-02-09 18:16:58 -08001663
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001664
Lee Thomason3f57d272012-01-11 15:30:03 -08001665// --------- XMLDocument ----------- //
Lee Thomason624d43f2012-10-12 10:58:48 -07001666XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001667 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001668 _writeBOM( false ),
1669 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001670 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001671 _whitespace( whitespace ),
1672 _errorStr1( 0 ),
1673 _errorStr2( 0 ),
1674 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001675{
Lee Thomason624d43f2012-10-12 10:58:48 -07001676 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001677}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001678
1679
Lee Thomason3f57d272012-01-11 15:30:03 -08001680XMLDocument::~XMLDocument()
1681{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001682 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -07001683 delete [] _charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001684
Lee Thomason (grinliz)61cea672013-02-01 19:13:13 -08001685#if 0
Lee Thomason (grinliz)ac83b4e2013-02-01 09:02:34 -08001686 _textPool.Trace( "text" );
1687 _elementPool.Trace( "element" );
1688 _commentPool.Trace( "comment" );
1689 _attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -08001690#endif
1691
Lee Thomason5b0a6772012-11-19 13:54:42 -08001692#ifdef DEBUG
1693 if ( Error() == false ) {
1694 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1695 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1696 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1697 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1698 }
1699#endif
Lee Thomason3f57d272012-01-11 15:30:03 -08001700}
1701
1702
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001703void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001704{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001705 DeleteChildren();
1706
Lee Thomason624d43f2012-10-12 10:58:48 -07001707 _errorID = XML_NO_ERROR;
1708 _errorStr1 = 0;
1709 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001710
Lee Thomason624d43f2012-10-12 10:58:48 -07001711 delete [] _charBuffer;
1712 _charBuffer = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001713}
1714
Lee Thomason3f57d272012-01-11 15:30:03 -08001715
Lee Thomason2c85a712012-01-31 08:24:24 -08001716XMLElement* XMLDocument::NewElement( const char* name )
1717{
Lee Thomason624d43f2012-10-12 10:58:48 -07001718 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1719 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001720 ele->SetName( name );
1721 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001722}
1723
1724
Lee Thomason1ff38e02012-02-14 18:18:16 -08001725XMLComment* XMLDocument::NewComment( const char* str )
1726{
Lee Thomason624d43f2012-10-12 10:58:48 -07001727 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1728 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001729 comment->SetValue( str );
1730 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001731}
1732
1733
1734XMLText* XMLDocument::NewText( const char* str )
1735{
Lee Thomason624d43f2012-10-12 10:58:48 -07001736 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1737 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001738 text->SetValue( str );
1739 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001740}
1741
1742
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001743XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1744{
Lee Thomason624d43f2012-10-12 10:58:48 -07001745 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1746 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001747 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1748 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001749}
1750
1751
1752XMLUnknown* XMLDocument::NewUnknown( const char* str )
1753{
Lee Thomason624d43f2012-10-12 10:58:48 -07001754 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1755 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001756 unk->SetValue( str );
1757 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001758}
1759
1760
Lee Thomason2fa81722012-11-09 12:37:46 -08001761XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001762{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001763 Clear();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001764 FILE* fp = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001765
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001766#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1767 errno_t err = fopen_s(&fp, filename, "rb" );
1768 if ( !fp || err) {
1769#else
1770 fp = fopen( filename, "rb" );
1771 if ( !fp) {
1772#endif
1773 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001774 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001775 }
1776 LoadFile( fp );
1777 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001778 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001779}
1780
1781
Lee Thomason2fa81722012-11-09 12:37:46 -08001782XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001783{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001784 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001785
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001786 fseek( fp, 0, SEEK_SET );
1787 fgetc( fp );
1788 if ( ferror( fp ) != 0 ) {
1789 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1790 return _errorID;
1791 }
1792
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001793 fseek( fp, 0, SEEK_END );
1794 size_t size = ftell( fp );
1795 fseek( fp, 0, SEEK_SET );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001796
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001797 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001798 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 _charBuffer = new char[size+1];
1803 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001804 if ( read != size ) {
1805 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001806 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001807 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001808
Lee Thomason624d43f2012-10-12 10:58:48 -07001809 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001810
Lee Thomason624d43f2012-10-12 10:58:48 -07001811 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001812 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001813 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001814 if ( !p || !*p ) {
1815 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001816 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001817 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001818
Lee Thomason624d43f2012-10-12 10:58:48 -07001819 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1820 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001821}
1822
1823
Lee Thomason2fa81722012-11-09 12:37:46 -08001824XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001825{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001826 FILE* fp = 0;
1827#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1828 errno_t err = fopen_s(&fp, filename, "w" );
1829 if ( !fp || err) {
1830#else
1831 fp = fopen( filename, "w" );
1832 if ( !fp) {
1833#endif
1834 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001835 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001836 }
1837 SaveFile(fp, compact);
1838 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001839 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001840}
1841
1842
Lee Thomason2fa81722012-11-09 12:37:46 -08001843XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001844{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001845 XMLPrinter stream( fp, compact );
1846 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001847 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001848}
1849
Lee Thomason1ff38e02012-02-14 18:18:16 -08001850
Lee Thomason2fa81722012-11-09 12:37:46 -08001851XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001852{
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001853 const char* start = p;
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001854 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001855
psi690ba072013-11-03 10:54:33 +09001856 if ( len == 0 ) {
1857 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1858 return _errorID;
1859 }
1860
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001861 if ( !p || !*p ) {
1862 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001863 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001864 }
1865 if ( len == (size_t)(-1) ) {
1866 len = strlen( p );
1867 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001868 _charBuffer = new char[ len+1 ];
1869 memcpy( _charBuffer, p, len );
1870 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001871
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001872 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001873 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001874 if ( !p || !*p ) {
1875 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001876 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001877 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001878
Thomas Roß1470edc2013-05-10 15:44:12 +02001879 ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001880 ParseDeep( _charBuffer+delta, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001881 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001882}
1883
1884
PKEuS1c5f99e2013-07-06 11:28:39 +02001885void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001886{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001887 XMLPrinter stdStreamer( stdout );
1888 if ( !streamer ) {
1889 streamer = &stdStreamer;
1890 }
1891 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001892}
1893
1894
Lee Thomason2fa81722012-11-09 12:37:46 -08001895void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001896{
Lee Thomason624d43f2012-10-12 10:58:48 -07001897 _errorID = error;
1898 _errorStr1 = str1;
1899 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001900}
1901
Lee Thomason5cae8972012-01-24 18:03:07 -08001902
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001903void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001904{
Lee Thomason624d43f2012-10-12 10:58:48 -07001905 if ( _errorID ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001906 static const int LEN = 20;
1907 char buf1[LEN] = { 0 };
1908 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001909
Lee Thomason624d43f2012-10-12 10:58:48 -07001910 if ( _errorStr1 ) {
1911 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001912 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001913 if ( _errorStr2 ) {
1914 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001915 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001916
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001917 printf( "XMLDocument error id=%d str1=%s str2=%s\n",
Lee Thomason624d43f2012-10-12 10:58:48 -07001918 _errorID, buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001919 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001920}
1921
1922
PKEuS1bfb9542013-08-04 13:51:17 +02001923XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001924 _elementJustOpened( false ),
1925 _firstElement( true ),
1926 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001927 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001928 _textDepth( -1 ),
1929 _processEntities( true ),
1930 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001931{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001932 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001933 _entityFlag[i] = false;
1934 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001935 }
1936 for( int i=0; i<NUM_ENTITIES; ++i ) {
1937 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1938 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001939 _entityFlag[ (int)entities[i].value ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001940 }
1941 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001942 _restrictedEntityFlag[(int)'&'] = true;
1943 _restrictedEntityFlag[(int)'<'] = true;
1944 _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
1945 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001946}
1947
1948
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001949void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001950{
1951 va_list va;
1952 va_start( va, format );
1953
Lee Thomason624d43f2012-10-12 10:58:48 -07001954 if ( _fp ) {
1955 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001956 }
1957 else {
1958 // This seems brutally complex. Haven't figured out a better
1959 // way on windows.
1960#ifdef _MSC_VER
1961 int len = -1;
1962 int expand = 1000;
1963 while ( len < 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001964 len = vsnprintf_s( _accumulator.Mem(), _accumulator.Capacity(), _TRUNCATE, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001965 if ( len < 0 ) {
1966 expand *= 3/2;
Lee Thomason1aa8fc42012-10-13 20:01:30 -07001967 _accumulator.PushArr( expand );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001968 }
1969 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001970 char* p = _buffer.PushArr( len ) - 1;
1971 memcpy( p, _accumulator.Mem(), len+1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001972#else
1973 int len = vsnprintf( 0, 0, format, va );
1974 // Close out and re-start the va-args
1975 va_end( va );
1976 va_start( va, format );
Lee Thomason624d43f2012-10-12 10:58:48 -07001977 char* p = _buffer.PushArr( len ) - 1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001978 vsnprintf( p, len+1, format, va );
1979#endif
1980 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001981 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001982}
1983
1984
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001985void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001986{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001987 for( int i=0; i<depth; ++i ) {
1988 Print( " " );
1989 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001990}
1991
1992
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001993void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001994{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001995 // Look for runs of bytes between entities to print.
1996 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001997 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001998
Lee Thomason624d43f2012-10-12 10:58:48 -07001999 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002000 while ( *q ) {
2001 // Remember, char is sometimes signed. (How many times has that bitten me?)
2002 if ( *q > 0 && *q < ENTITY_RANGE ) {
2003 // Check for entities. If one is found, flush
2004 // the stream up until the entity, write the
2005 // entity, and keep looking.
2006 if ( flag[(unsigned)(*q)] ) {
2007 while ( p < q ) {
2008 Print( "%c", *p );
2009 ++p;
2010 }
2011 for( int i=0; i<NUM_ENTITIES; ++i ) {
2012 if ( entities[i].value == *q ) {
2013 Print( "&%s;", entities[i].pattern );
2014 break;
2015 }
2016 }
2017 ++p;
2018 }
2019 }
2020 ++q;
2021 }
2022 }
2023 // Flush the remaining string. This will be the entire
2024 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07002025 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002026 Print( "%s", p );
2027 }
Lee Thomason857b8682012-01-25 17:50:25 -08002028}
2029
U-Stream\Leeae25a442012-02-17 17:48:16 -08002030
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002031void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002032{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002033 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002034 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 -07002035 Print( "%s", bom );
2036 }
2037 if ( writeDec ) {
2038 PushDeclaration( "xml version=\"1.0\"" );
2039 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002040}
2041
2042
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002043void XMLPrinter::OpenElement( const char* name )
Lee Thomason5cae8972012-01-24 18:03:07 -08002044{
Lee Thomason624d43f2012-10-12 10:58:48 -07002045 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002046 SealElement();
2047 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002048 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002049
Lee Thomason624d43f2012-10-12 10:58:48 -07002050 if ( _textDepth < 0 && !_firstElement && !_compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002051 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002052 }
2053 if ( !_compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002054 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002055 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002056
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002057 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002058 _elementJustOpened = true;
2059 _firstElement = false;
2060 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002061}
2062
2063
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002064void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002065{
Lee Thomason624d43f2012-10-12 10:58:48 -07002066 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002067 Print( " %s=\"", name );
2068 PrintString( value, false );
2069 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002070}
2071
2072
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002073void XMLPrinter::PushAttribute( const char* name, int v )
2074{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002075 char buf[BUF_SIZE];
2076 XMLUtil::ToStr( v, buf, BUF_SIZE );
2077 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002078}
2079
2080
2081void XMLPrinter::PushAttribute( const char* name, unsigned v )
2082{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002083 char buf[BUF_SIZE];
2084 XMLUtil::ToStr( v, buf, BUF_SIZE );
2085 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002086}
2087
2088
2089void XMLPrinter::PushAttribute( const char* name, bool v )
2090{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002091 char buf[BUF_SIZE];
2092 XMLUtil::ToStr( v, buf, BUF_SIZE );
2093 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002094}
2095
2096
2097void XMLPrinter::PushAttribute( const char* name, double v )
2098{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002099 char buf[BUF_SIZE];
2100 XMLUtil::ToStr( v, buf, BUF_SIZE );
2101 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002102}
2103
2104
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002105void XMLPrinter::CloseElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08002106{
Lee Thomason624d43f2012-10-12 10:58:48 -07002107 --_depth;
2108 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002109
Lee Thomason624d43f2012-10-12 10:58:48 -07002110 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002111 Print( "/>" );
2112 }
2113 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07002114 if ( _textDepth < 0 && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002115 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002116 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002117 }
2118 Print( "</%s>", name );
2119 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002120
Lee Thomason624d43f2012-10-12 10:58:48 -07002121 if ( _textDepth == _depth ) {
2122 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002123 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002124 if ( _depth == 0 && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002125 Print( "\n" );
2126 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002127 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002128}
2129
2130
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002131void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08002132{
Lee Thomason624d43f2012-10-12 10:58:48 -07002133 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002134 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002135}
2136
2137
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002138void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002139{
Lee Thomason624d43f2012-10-12 10:58:48 -07002140 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002141
Lee Thomason624d43f2012-10-12 10:58:48 -07002142 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002143 SealElement();
2144 }
2145 if ( cdata ) {
2146 Print( "<![CDATA[" );
2147 Print( "%s", text );
2148 Print( "]]>" );
2149 }
2150 else {
2151 PrintString( text, true );
2152 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002153}
2154
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002155void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002156{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002157 char buf[BUF_SIZE];
2158 XMLUtil::ToStr( value, buf, BUF_SIZE );
2159 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002160}
2161
2162
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002163void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002164{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002165 char buf[BUF_SIZE];
2166 XMLUtil::ToStr( value, buf, BUF_SIZE );
2167 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002168}
2169
2170
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002171void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002172{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002173 char buf[BUF_SIZE];
2174 XMLUtil::ToStr( value, buf, BUF_SIZE );
2175 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002176}
2177
2178
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002179void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002180{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002181 char buf[BUF_SIZE];
2182 XMLUtil::ToStr( value, buf, BUF_SIZE );
2183 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002184}
2185
2186
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002187void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002188{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002189 char buf[BUF_SIZE];
2190 XMLUtil::ToStr( value, buf, BUF_SIZE );
2191 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002192}
2193
Lee Thomason5cae8972012-01-24 18:03:07 -08002194
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002195void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002196{
Lee Thomason624d43f2012-10-12 10:58:48 -07002197 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002198 SealElement();
2199 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002200 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002201 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002202 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002203 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002204 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002205 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002206}
Lee Thomason751da522012-02-10 08:50:51 -08002207
2208
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002209void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002210{
Lee Thomason624d43f2012-10-12 10:58:48 -07002211 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002212 SealElement();
2213 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002214 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002215 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002216 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002217 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002218 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002219 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002220}
2221
2222
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002223void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002224{
Lee Thomason624d43f2012-10-12 10:58:48 -07002225 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002226 SealElement();
2227 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002228 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002229 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002230 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002231 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002232 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002233 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002234}
2235
2236
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002237bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002238{
Lee Thomason624d43f2012-10-12 10:58:48 -07002239 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002240 if ( doc.HasBOM() ) {
2241 PushHeader( true, false );
2242 }
2243 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002244}
2245
2246
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002247bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002248{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002249 OpenElement( element.Name() );
2250 while ( attribute ) {
2251 PushAttribute( attribute->Name(), attribute->Value() );
2252 attribute = attribute->Next();
2253 }
2254 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002255}
2256
2257
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08002258bool XMLPrinter::VisitExit( const XMLElement& )
Lee Thomason751da522012-02-10 08:50:51 -08002259{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002260 CloseElement();
2261 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002262}
2263
2264
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002265bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002266{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002267 PushText( text.Value(), text.CData() );
2268 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002269}
2270
2271
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002272bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002273{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002274 PushComment( comment.Value() );
2275 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002276}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002277
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002278bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002279{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002280 PushDeclaration( declaration.Value() );
2281 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002282}
2283
2284
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002285bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002286{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002287 PushUnknown( unknown.Value() );
2288 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002289}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002290
Lee Thomason685b8952012-11-12 13:00:06 -08002291} // namespace tinyxml2
2292