blob: 608185625e45f37a40a0c7d96c1cbd807407e629 [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
U-Lama\Lee560bd472011-12-28 19:42:49 -080024#include "tinyxml2.h"
25
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070026#include <new> // yes, this one new style header, is in the Android SDK.
Lee Thomasona9cf3f92012-10-11 16:56:51 -070027# ifdef ANDROID_NDK
28# include <stddef.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070029#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070030# include <cstddef>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070031#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080032
Lee Thomasone4422302012-01-20 17:59:50 -080033static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -080034static const char LF = LINE_FEED;
35static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
36static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -080037static const char SINGLE_QUOTE = '\'';
38static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -080039
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080040// Bunch of unicode info at:
41// http://www.unicode.org/faq/utf_bom.html
42// ef bb bf (Microsoft "lead bytes") - designates UTF-8
43
44static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
45static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
46static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080047
48
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080049#define DELETE_NODE( node ) { \
Lee Thomasona9cf3f92012-10-11 16:56:51 -070050 if ( node ) { \
Lee Thomason624d43f2012-10-12 10:58:48 -070051 MemPool* pool = node->_memPool; \
Lee Thomasona9cf3f92012-10-11 16:56:51 -070052 node->~XMLNode(); \
53 pool->Free( node ); \
54 } \
55 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080056#define DELETE_ATTRIBUTE( attrib ) { \
Lee Thomasona9cf3f92012-10-11 16:56:51 -070057 if ( attrib ) { \
Lee Thomason624d43f2012-10-12 10:58:48 -070058 MemPool* pool = attrib->_memPool; \
Lee Thomasona9cf3f92012-10-11 16:56:51 -070059 attrib->~XMLAttribute(); \
60 pool->Free( attrib ); \
61 } \
62 }
Lee Thomason43f59302012-02-06 18:18:11 -080063
Kevin Wojniak04c22d22012-11-08 11:02:22 -080064namespace tinyxml2
65{
66
Lee Thomason8ee79892012-01-25 17:44:30 -080067struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -070068 const char* pattern;
69 int length;
70 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -080071};
72
73static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070074static const Entity entities[NUM_ENTITIES] = {
75 { "quot", 4, DOUBLE_QUOTE },
76 { "amp", 3, '&' },
77 { "apos", 4, SINGLE_QUOTE },
78 { "lt", 2, '<' },
79 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -080080};
81
Lee Thomasonfde6a752012-01-14 18:08:12 -080082
Lee Thomason1a1d4a72012-02-15 09:09:25 -080083StrPair::~StrPair()
84{
Lee Thomasona9cf3f92012-10-11 16:56:51 -070085 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -080086}
87
88
89void StrPair::Reset()
90{
Lee Thomason120b3a62012-10-12 10:06:59 -070091 if ( _flags & NEEDS_DELETE ) {
92 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070093 }
Lee Thomason120b3a62012-10-12 10:06:59 -070094 _flags = 0;
95 _start = 0;
96 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -080097}
98
99
100void StrPair::SetStr( const char* str, int flags )
101{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700102 Reset();
103 size_t len = strlen( str );
Lee Thomason120b3a62012-10-12 10:06:59 -0700104 _start = new char[ len+1 ];
105 memcpy( _start, str, len+1 );
106 _end = _start + len;
107 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800108}
109
110
111char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
112{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700113 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800114
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700115 char* start = p; // fixme: hides a member
116 char endChar = *endTag;
117 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800118
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700119 // Inner loop of text parsing.
120 while ( *p ) {
121 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
122 Set( start, p, strFlags );
123 return p + length;
124 }
125 ++p;
126 }
127 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800128}
129
130
131char* StrPair::ParseName( char* p )
132{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700133 char* start = p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800134
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700135 if ( !start || !(*start) ) {
136 return 0;
137 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800138
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +0200139 while( *p && ( p == start ? XMLUtil::IsNameStartChar( *p ) : XMLUtil::IsNameChar( *p ) )) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700140 ++p;
141 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800142
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700143 if ( p > start ) {
144 Set( start, p, 0 );
145 return p;
146 }
147 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800148}
149
150
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700151void StrPair::CollapseWhitespace()
152{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700153 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700154 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700155
Lee Thomason120b3a62012-10-12 10:06:59 -0700156 if ( _start && *_start ) {
157 char* p = _start; // the read pointer
158 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700159
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700160 while( *p ) {
161 if ( XMLUtil::IsWhiteSpace( *p )) {
162 p = XMLUtil::SkipWhiteSpace( p );
163 if ( *p == 0 ) {
164 break; // don't write to q; this trims the trailing space.
165 }
166 *q = ' ';
167 ++q;
168 }
169 *q = *p;
170 ++q;
171 ++p;
172 }
173 *q = 0;
174 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700175}
176
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800177
Lee Thomasone4422302012-01-20 17:59:50 -0800178const char* StrPair::GetStr()
179{
Lee Thomason120b3a62012-10-12 10:06:59 -0700180 if ( _flags & NEEDS_FLUSH ) {
181 *_end = 0;
182 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800183
Lee Thomason120b3a62012-10-12 10:06:59 -0700184 if ( _flags ) {
185 char* p = _start; // the read pointer
186 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800187
Lee Thomason120b3a62012-10-12 10:06:59 -0700188 while( p < _end ) {
189 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700190 // CR-LF pair becomes LF
191 // CR alone becomes LF
192 // LF-CR becomes LF
193 if ( *(p+1) == LF ) {
194 p += 2;
195 }
196 else {
197 ++p;
198 }
199 *q++ = LF;
200 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700201 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700202 if ( *(p+1) == CR ) {
203 p += 2;
204 }
205 else {
206 ++p;
207 }
208 *q++ = LF;
209 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700210 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700211 // Entities handled by tinyXML2:
212 // - special entities in the entity table [in/out]
213 // - numeric character reference [in]
214 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800215
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700216 if ( *(p+1) == '#' ) {
217 char buf[10] = { 0 };
218 int len;
219 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
220 for( int i=0; i<len; ++i ) {
221 *q++ = buf[i];
222 }
223 TIXMLASSERT( q <= p );
224 }
225 else {
226 int i=0;
227 for(; i<NUM_ENTITIES; ++i ) {
228 if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
229 && *(p+entities[i].length+1) == ';' ) {
230 // Found an entity convert;
231 *q = entities[i].value;
232 ++q;
233 p += entities[i].length + 2;
234 break;
235 }
236 }
237 if ( i == NUM_ENTITIES ) {
238 // fixme: treat as error?
239 ++p;
240 ++q;
241 }
242 }
243 }
244 else {
245 *q = *p;
246 ++p;
247 ++q;
248 }
249 }
250 *q = 0;
251 }
252 // The loop below has plenty going on, and this
253 // is a less useful mode. Break it out.
Lee Thomason120b3a62012-10-12 10:06:59 -0700254 if ( _flags & COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700255 CollapseWhitespace();
256 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700257 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700258 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700259 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800260}
261
Lee Thomason2c85a712012-01-31 08:24:24 -0800262
Lee Thomasone4422302012-01-20 17:59:50 -0800263
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800264
Lee Thomason56bdd022012-02-09 18:16:58 -0800265// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800266
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800267const char* XMLUtil::ReadBOM( const char* p, bool* bom )
268{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700269 *bom = false;
270 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
271 // Check for BOM:
272 if ( *(pu+0) == TIXML_UTF_LEAD_0
273 && *(pu+1) == TIXML_UTF_LEAD_1
274 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
275 *bom = true;
276 p += 3;
277 }
278 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800279}
280
281
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800282void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
283{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700284 const unsigned long BYTE_MASK = 0xBF;
285 const unsigned long BYTE_MARK = 0x80;
286 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800287
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700288 if (input < 0x80) {
289 *length = 1;
290 }
291 else if ( input < 0x800 ) {
292 *length = 2;
293 }
294 else if ( input < 0x10000 ) {
295 *length = 3;
296 }
297 else if ( input < 0x200000 ) {
298 *length = 4;
299 }
300 else {
301 *length = 0; // This code won't covert this correctly anyway.
302 return;
303 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800304
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700305 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800306
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700307 // Scary scary fall throughs.
308 switch (*length) {
309 case 4:
310 --output;
311 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
312 input >>= 6;
313 case 3:
314 --output;
315 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
316 input >>= 6;
317 case 2:
318 --output;
319 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
320 input >>= 6;
321 case 1:
322 --output;
323 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100324 default:
325 break;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700326 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800327}
328
329
330const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
331{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700332 // Presume an entity, and pull it out.
333 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800334
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700335 if ( *(p+1) == '#' && *(p+2) ) {
336 unsigned long ucs = 0;
337 ptrdiff_t delta = 0;
338 unsigned mult = 1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800339
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700340 if ( *(p+2) == 'x' ) {
341 // Hexadecimal.
342 if ( !*(p+3) ) {
343 return 0;
344 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800345
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700346 const char* q = p+3;
347 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800348
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700349 if ( !q || !*q ) {
350 return 0;
351 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800352
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700353 delta = q-p;
354 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800355
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700356 while ( *q != 'x' ) {
357 if ( *q >= '0' && *q <= '9' ) {
358 ucs += mult * (*q - '0');
359 }
360 else if ( *q >= 'a' && *q <= 'f' ) {
361 ucs += mult * (*q - 'a' + 10);
362 }
363 else if ( *q >= 'A' && *q <= 'F' ) {
364 ucs += mult * (*q - 'A' + 10 );
365 }
366 else {
367 return 0;
368 }
369 mult *= 16;
370 --q;
371 }
372 }
373 else {
374 // Decimal.
375 if ( !*(p+2) ) {
376 return 0;
377 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800378
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700379 const char* q = p+2;
380 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800381
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700382 if ( !q || !*q ) {
383 return 0;
384 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800385
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700386 delta = q-p;
387 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800388
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700389 while ( *q != '#' ) {
390 if ( *q >= '0' && *q <= '9' ) {
391 ucs += mult * (*q - '0');
392 }
393 else {
394 return 0;
395 }
396 mult *= 10;
397 --q;
398 }
399 }
400 // convert the UCS to UTF-8
401 ConvertUTF32ToUTF8( ucs, value, length );
402 return p + delta + 1;
403 }
404 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800405}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800406
407
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700408void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700409{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700410 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700411}
412
413
Uli Kusterer664d0562014-01-21 12:24:47 +0100414void XMLUtil::ToStr( long long v, char* buffer, int bufferSize )
415{
416 TIXML_SNPRINTF( buffer, bufferSize, "%lld", v );
417}
418
419
Lee Thomason21be8822012-07-15 17:27:22 -0700420void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
421{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700422 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700423}
424
425
426void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
427{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700428 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700429}
430
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800431/*
432 ToStr() of a number is a very tricky topic.
433 https://github.com/leethomason/tinyxml2/issues/106
434*/
Lee Thomason21be8822012-07-15 17:27:22 -0700435void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
436{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800437 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700438}
439
440
441void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
442{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800443 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700444}
445
446
447bool XMLUtil::ToInt( const char* str, int* value )
448{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700449 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
450 return true;
451 }
452 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700453}
454
Uli Kusterer664d0562014-01-21 12:24:47 +0100455bool XMLUtil::ToLongLong( const char* str, long long* value )
456{
457 if ( TIXML_SSCANF( str, "%lld", value ) == 1 ) {
458 return true;
459 }
460 return false;
461}
462
Lee Thomason21be8822012-07-15 17:27:22 -0700463bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
464{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700465 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
466 return true;
467 }
468 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700469}
470
471bool XMLUtil::ToBool( const char* str, bool* value )
472{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700473 int ival = 0;
474 if ( ToInt( str, &ival )) {
475 *value = (ival==0) ? false : true;
476 return true;
477 }
478 if ( StringEqual( str, "true" ) ) {
479 *value = true;
480 return true;
481 }
482 else if ( StringEqual( str, "false" ) ) {
483 *value = false;
484 return true;
485 }
486 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700487}
488
489
490bool XMLUtil::ToFloat( const char* str, float* value )
491{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700492 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
493 return true;
494 }
495 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700496}
497
498bool XMLUtil::ToDouble( const char* str, double* value )
499{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700500 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
501 return true;
502 }
503 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700504}
505
506
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700507char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800508{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700509 XMLNode* returnNode = 0;
510 char* start = p;
511 p = XMLUtil::SkipWhiteSpace( p );
512 if( !p || !*p ) {
513 return p;
514 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800515
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700516 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800517 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700518 static const char* xmlHeader = { "<?" };
519 static const char* commentHeader = { "<!--" };
520 static const char* dtdHeader = { "<!" };
521 static const char* cdataHeader = { "<![CDATA[" };
522 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800523
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700524 static const int xmlHeaderLen = 2;
525 static const int commentHeaderLen = 4;
526 static const int dtdHeaderLen = 2;
527 static const int cdataHeaderLen = 9;
528 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800529
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800530#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800531#pragma warning ( push )
532#pragma warning ( disable : 4127 )
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800533#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700534 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
535 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800536#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800537#pragma warning (pop)
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800538#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700539 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700540 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
541 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700542 p += xmlHeaderLen;
543 }
544 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700545 returnNode = new (_commentPool.Alloc()) XMLComment( this );
546 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700547 p += commentHeaderLen;
548 }
549 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700550 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700551 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700552 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700553 p += cdataHeaderLen;
554 text->SetCData( true );
555 }
556 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700557 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
558 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700559 p += dtdHeaderLen;
560 }
561 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700562 returnNode = new (_elementPool.Alloc()) XMLElement( this );
563 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700564 p += elementHeaderLen;
565 }
566 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700567 returnNode = new (_textPool.Alloc()) XMLText( this );
568 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700569 p = start; // Back it up, all the text counts.
570 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800571
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700572 *node = returnNode;
573 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800574}
575
576
Lee Thomason751da522012-02-10 08:50:51 -0800577bool XMLDocument::Accept( XMLVisitor* visitor ) const
578{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700579 if ( visitor->VisitEnter( *this ) ) {
580 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
581 if ( !node->Accept( visitor ) ) {
582 break;
583 }
584 }
585 }
586 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800587}
Lee Thomason56bdd022012-02-09 18:16:58 -0800588
589
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800590// --------- XMLNode ----------- //
591
592XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700593 _document( doc ),
594 _parent( 0 ),
595 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200596 _prev( 0 ), _next( 0 ),
597 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800598{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800599}
600
601
602XMLNode::~XMLNode()
603{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700604 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700605 if ( _parent ) {
606 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700607 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800608}
609
Michael Daumling21626882013-10-22 17:03:37 +0200610const char* XMLNode::Value() const
611{
612 return _value.GetStr();
613}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800614
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800615void XMLNode::SetValue( const char* str, bool staticMem )
616{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700617 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700618 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700619 }
620 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700621 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700622 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800623}
624
625
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800626void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800627{
Lee Thomason624d43f2012-10-12 10:58:48 -0700628 while( _firstChild ) {
629 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700630 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700631
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700632 DELETE_NODE( node );
633 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700634 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800635}
636
637
638void XMLNode::Unlink( XMLNode* child )
639{
Lee Thomason624d43f2012-10-12 10:58:48 -0700640 if ( child == _firstChild ) {
641 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700642 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700643 if ( child == _lastChild ) {
644 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700645 }
Lee Thomasond923c672012-01-23 08:44:25 -0800646
Lee Thomason624d43f2012-10-12 10:58:48 -0700647 if ( child->_prev ) {
648 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700649 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700650 if ( child->_next ) {
651 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700652 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700653 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800654}
655
656
U-Stream\Leeae25a442012-02-17 17:48:16 -0800657void XMLNode::DeleteChild( XMLNode* node )
658{
Lee Thomason624d43f2012-10-12 10:58:48 -0700659 TIXMLASSERT( node->_parent == this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700660 DELETE_NODE( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800661}
662
663
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800664XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
665{
Michael Daumlinged523282013-10-23 07:47:29 +0200666 if (addThis->_document != _document)
667 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700668
Michael Daumlinged523282013-10-23 07:47:29 +0200669 if (addThis->_parent)
670 addThis->_parent->Unlink( addThis );
671 else
672 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700673
Lee Thomason624d43f2012-10-12 10:58:48 -0700674 if ( _lastChild ) {
675 TIXMLASSERT( _firstChild );
676 TIXMLASSERT( _lastChild->_next == 0 );
677 _lastChild->_next = addThis;
678 addThis->_prev = _lastChild;
679 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800680
Lee Thomason624d43f2012-10-12 10:58:48 -0700681 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700682 }
683 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700684 TIXMLASSERT( _firstChild == 0 );
685 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800686
Lee Thomason624d43f2012-10-12 10:58:48 -0700687 addThis->_prev = 0;
688 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700689 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700690 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700691 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800692}
693
694
Lee Thomason1ff38e02012-02-14 18:18:16 -0800695XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
696{
Michael Daumlinged523282013-10-23 07:47:29 +0200697 if (addThis->_document != _document)
698 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700699
Michael Daumlinged523282013-10-23 07:47:29 +0200700 if (addThis->_parent)
701 addThis->_parent->Unlink( addThis );
702 else
703 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700704
Lee Thomason624d43f2012-10-12 10:58:48 -0700705 if ( _firstChild ) {
706 TIXMLASSERT( _lastChild );
707 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800708
Lee Thomason624d43f2012-10-12 10:58:48 -0700709 _firstChild->_prev = addThis;
710 addThis->_next = _firstChild;
711 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800712
Lee Thomason624d43f2012-10-12 10:58:48 -0700713 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700714 }
715 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700716 TIXMLASSERT( _lastChild == 0 );
717 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800718
Lee Thomason624d43f2012-10-12 10:58:48 -0700719 addThis->_prev = 0;
720 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700721 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700722 addThis->_parent = this;
Michael Daumlinged523282013-10-23 07:47:29 +0200723 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800724}
725
726
727XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
728{
Michael Daumlinged523282013-10-23 07:47:29 +0200729 if (addThis->_document != _document)
730 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700731
Lee Thomason624d43f2012-10-12 10:58:48 -0700732 TIXMLASSERT( afterThis->_parent == this );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700733
Lee Thomason624d43f2012-10-12 10:58:48 -0700734 if ( afterThis->_parent != this ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700735 return 0;
736 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800737
Lee Thomason624d43f2012-10-12 10:58:48 -0700738 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700739 // The last node or the only node.
740 return InsertEndChild( addThis );
741 }
Michael Daumlinged523282013-10-23 07:47:29 +0200742 if (addThis->_parent)
743 addThis->_parent->Unlink( addThis );
744 else
745 addThis->_memPool->SetTracked();
Lee Thomason624d43f2012-10-12 10:58:48 -0700746 addThis->_prev = afterThis;
747 addThis->_next = afterThis->_next;
748 afterThis->_next->_prev = addThis;
749 afterThis->_next = addThis;
750 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700751 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800752}
753
754
755
756
Lee Thomason56bdd022012-02-09 18:16:58 -0800757const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800758{
Lee Thomason624d43f2012-10-12 10:58:48 -0700759 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700760 XMLElement* element = node->ToElement();
761 if ( element ) {
762 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
763 return element;
764 }
765 }
766 }
767 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800768}
769
770
Lee Thomason56bdd022012-02-09 18:16:58 -0800771const XMLElement* XMLNode::LastChildElement( const char* value ) const
772{
Lee Thomason624d43f2012-10-12 10:58:48 -0700773 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700774 XMLElement* element = node->ToElement();
775 if ( element ) {
776 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
777 return element;
778 }
779 }
780 }
781 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800782}
783
784
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800785const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
786{
Lee Thomason624d43f2012-10-12 10:58:48 -0700787 for( XMLNode* element=this->_next; element; element = element->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700788 if ( element->ToElement()
789 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
790 return element->ToElement();
791 }
792 }
793 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800794}
795
796
797const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
798{
Lee Thomason624d43f2012-10-12 10:58:48 -0700799 for( XMLNode* element=_prev; element; element = element->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700800 if ( element->ToElement()
801 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
802 return element->ToElement();
803 }
804 }
805 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800806}
807
808
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800809char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800810{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700811 // This is a recursive method, but thinking about it "at the current level"
812 // it is a pretty simple flat list:
813 // <foo/>
814 // <!-- comment -->
815 //
816 // With a special case:
817 // <foo>
818 // </foo>
819 // <!-- comment -->
820 //
821 // Where the closing element (/foo) *must* be the next thing after the opening
822 // element, and the names must match. BUT the tricky bit is that the closing
823 // element will be read by the child.
824 //
825 // 'endTag' is the end tag for this node, it is returned by a call to a child.
826 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800827
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700828 while( p && *p ) {
829 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800830
Lee Thomason624d43f2012-10-12 10:58:48 -0700831 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700832 if ( p == 0 || node == 0 ) {
833 break;
834 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800835
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700836 StrPair endTag;
837 p = node->ParseDeep( p, &endTag );
838 if ( !p ) {
839 DELETE_NODE( node );
840 node = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -0700841 if ( !_document->Error() ) {
842 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700843 }
844 break;
845 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800846
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700847 // We read the end tag. Return it to the parent.
848 if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
849 if ( parentEnd ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700850 *parentEnd = static_cast<XMLElement*>(node)->_value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700851 }
Lee Thomason5b0a6772012-11-19 13:54:42 -0800852 node->_memPool->SetTracked(); // created and then immediately deleted.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700853 DELETE_NODE( node );
854 return p;
855 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800856
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700857 // Handle an end tag returned to this level.
858 // And handle a bunch of annoying errors.
859 XMLElement* ele = node->ToElement();
860 if ( ele ) {
861 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700862 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700863 p = 0;
864 }
865 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700866 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700867 p = 0;
868 }
869 else if ( !endTag.Empty() ) {
870 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700871 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700872 p = 0;
873 }
874 }
875 }
876 if ( p == 0 ) {
877 DELETE_NODE( node );
878 node = 0;
879 }
880 if ( node ) {
881 this->InsertEndChild( node );
882 }
883 }
884 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800885}
886
Lee Thomason5492a1c2012-01-23 15:32:10 -0800887// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800888char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800889{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700890 const char* start = p;
891 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700892 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700893 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700894 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700895 }
896 return p;
897 }
898 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700899 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
900 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700901 flags |= StrPair::COLLAPSE_WHITESPACE;
902 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700903
Lee Thomason624d43f2012-10-12 10:58:48 -0700904 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700905 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700906 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700907 }
908 if ( p && *p ) {
909 return p-1;
910 }
911 }
912 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800913}
914
915
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800916XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
917{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700918 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700919 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700920 }
921 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
922 text->SetCData( this->CData() );
923 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800924}
925
926
927bool XMLText::ShallowEqual( const XMLNode* compare ) const
928{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700929 return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800930}
931
932
Lee Thomason56bdd022012-02-09 18:16:58 -0800933bool XMLText::Accept( XMLVisitor* visitor ) const
934{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700935 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800936}
937
938
Lee Thomason3f57d272012-01-11 15:30:03 -0800939// --------- XMLComment ---------- //
940
Lee Thomasone4422302012-01-20 17:59:50 -0800941XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800942{
943}
944
945
Lee Thomasonce0763e2012-01-11 15:43:54 -0800946XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800947{
Lee Thomason3f57d272012-01-11 15:30:03 -0800948}
949
950
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800951char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800952{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700953 // Comment parses as text.
954 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700955 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700956 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700957 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700958 }
959 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800960}
961
962
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800963XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
964{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700965 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700966 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700967 }
968 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
969 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800970}
971
972
973bool XMLComment::ShallowEqual( const XMLNode* compare ) const
974{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700975 return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800976}
977
978
Lee Thomason751da522012-02-10 08:50:51 -0800979bool XMLComment::Accept( XMLVisitor* visitor ) const
980{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700981 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800982}
Lee Thomason56bdd022012-02-09 18:16:58 -0800983
984
Lee Thomason50f97b22012-02-11 16:33:40 -0800985// --------- XMLDeclaration ---------- //
986
987XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
988{
989}
990
991
992XMLDeclaration::~XMLDeclaration()
993{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700994 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -0800995}
996
997
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800998char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800999{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001000 // Declaration parses as text.
1001 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001002 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001003 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001004 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001005 }
1006 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001007}
1008
1009
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001010XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1011{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001012 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001013 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001014 }
1015 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1016 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001017}
1018
1019
1020bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1021{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001022 return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001023}
1024
1025
1026
Lee Thomason50f97b22012-02-11 16:33:40 -08001027bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1028{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001029 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001030}
1031
1032// --------- XMLUnknown ---------- //
1033
1034XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1035{
1036}
1037
1038
1039XMLUnknown::~XMLUnknown()
1040{
1041}
1042
1043
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001044char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001045{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001046 // Unknown parses as text.
1047 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001048
Lee Thomason624d43f2012-10-12 10:58:48 -07001049 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001050 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001051 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001052 }
1053 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001054}
1055
1056
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001057XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1058{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001059 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001060 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001061 }
1062 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1063 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001064}
1065
1066
1067bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1068{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001069 return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001070}
1071
1072
Lee Thomason50f97b22012-02-11 16:33:40 -08001073bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1074{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001075 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001076}
1077
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001078// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001079
1080const char* XMLAttribute::Name() const
1081{
1082 return _name.GetStr();
1083}
1084
1085const char* XMLAttribute::Value() const
1086{
1087 return _value.GetStr();
1088}
1089
Lee Thomason6f381b72012-03-02 12:59:39 -08001090char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001091{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001092 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001093 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001094 if ( !p || !*p ) {
1095 return 0;
1096 }
Lee Thomason22aead12012-01-23 13:29:35 -08001097
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001098 // Skip white space before =
1099 p = XMLUtil::SkipWhiteSpace( p );
1100 if ( !p || *p != '=' ) {
1101 return 0;
1102 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001103
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001104 ++p; // move up to opening quote
1105 p = XMLUtil::SkipWhiteSpace( p );
1106 if ( *p != '\"' && *p != '\'' ) {
1107 return 0;
1108 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001109
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001110 char endTag[2] = { *p, 0 };
1111 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001112
Lee Thomason624d43f2012-10-12 10:58:48 -07001113 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001114 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001115}
1116
1117
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001118void XMLAttribute::SetName( const char* n )
1119{
Lee Thomason624d43f2012-10-12 10:58:48 -07001120 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001121}
1122
1123
Lee Thomason2fa81722012-11-09 12:37:46 -08001124XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001125{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001126 if ( XMLUtil::ToInt( Value(), value )) {
1127 return XML_NO_ERROR;
1128 }
1129 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001130}
1131
1132
Lee Thomason2fa81722012-11-09 12:37:46 -08001133XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001134{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001135 if ( XMLUtil::ToUnsigned( Value(), value )) {
1136 return XML_NO_ERROR;
1137 }
1138 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001139}
1140
1141
Lee Thomason2fa81722012-11-09 12:37:46 -08001142XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001143{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001144 if ( XMLUtil::ToBool( Value(), value )) {
1145 return XML_NO_ERROR;
1146 }
1147 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001148}
1149
1150
Lee Thomason2fa81722012-11-09 12:37:46 -08001151XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001152{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001153 if ( XMLUtil::ToFloat( Value(), value )) {
1154 return XML_NO_ERROR;
1155 }
1156 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001157}
1158
1159
Lee Thomason2fa81722012-11-09 12:37:46 -08001160XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001161{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001162 if ( XMLUtil::ToDouble( Value(), value )) {
1163 return XML_NO_ERROR;
1164 }
1165 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001166}
1167
1168
1169void XMLAttribute::SetAttribute( const char* v )
1170{
Lee Thomason624d43f2012-10-12 10:58:48 -07001171 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001172}
1173
1174
Lee Thomason1ff38e02012-02-14 18:18:16 -08001175void XMLAttribute::SetAttribute( int v )
1176{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001177 char buf[BUF_SIZE];
1178 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001179 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001180}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001181
1182
Uli Kusterer664d0562014-01-21 12:24:47 +01001183void XMLAttribute::SetAttribute( long long v )
1184{
1185 char buf[BUF_SIZE];
1186 XMLUtil::ToStr( v, buf, BUF_SIZE );
1187 _value.SetStr( buf );
1188}
1189
1190
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001191void XMLAttribute::SetAttribute( unsigned v )
1192{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001193 char buf[BUF_SIZE];
1194 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001195 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001196}
1197
1198
1199void XMLAttribute::SetAttribute( bool v )
1200{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001201 char buf[BUF_SIZE];
1202 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001203 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001204}
1205
1206void XMLAttribute::SetAttribute( double v )
1207{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001208 char buf[BUF_SIZE];
1209 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001210 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001211}
1212
1213void XMLAttribute::SetAttribute( float v )
1214{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001215 char buf[BUF_SIZE];
1216 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001217 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001218}
1219
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001220
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001221// --------- XMLElement ---------- //
1222XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001223 _closingType( 0 ),
1224 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001225{
1226}
1227
1228
1229XMLElement::~XMLElement()
1230{
Lee Thomason624d43f2012-10-12 10:58:48 -07001231 while( _rootAttribute ) {
1232 XMLAttribute* next = _rootAttribute->_next;
1233 DELETE_ATTRIBUTE( _rootAttribute );
1234 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001235 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001236}
1237
1238
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001239XMLAttribute* XMLElement::FindAttribute( const char* name )
1240{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001241 XMLAttribute* a = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001242 for( a=_rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001243 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1244 return a;
1245 }
1246 }
1247 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001248}
1249
1250
1251const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1252{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001253 XMLAttribute* a = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001254 for( a=_rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001255 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1256 return a;
1257 }
1258 }
1259 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001260}
1261
1262
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001263const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001264{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001265 const XMLAttribute* a = FindAttribute( name );
1266 if ( !a ) {
1267 return 0;
1268 }
1269 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1270 return a->Value();
1271 }
1272 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001273}
1274
1275
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001276const char* XMLElement::GetText() const
1277{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001278 if ( FirstChild() && FirstChild()->ToText() ) {
1279 return FirstChild()->ToText()->Value();
1280 }
1281 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001282}
1283
1284
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001285void XMLElement::SetText( const char* inText )
1286{
Uli Kusterer869bb592014-01-21 01:36:16 +01001287 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001288 FirstChild()->SetValue( inText );
1289 else {
1290 XMLText* theText = GetDocument()->NewText( inText );
1291 InsertFirstChild( theText );
1292 }
1293}
1294
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001295
Lee Thomason5bb2d802014-01-24 10:42:57 -08001296void XMLElement::SetText( int v )
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001297{
1298 char buf[BUF_SIZE];
Lee Thomason5bb2d802014-01-24 10:42:57 -08001299 XMLUtil::ToStr( v, buf, BUF_SIZE );
1300 SetText( buf );
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001301}
1302
1303
Lee Thomason5bb2d802014-01-24 10:42:57 -08001304void XMLElement::SetText( unsigned v )
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001305{
1306 char buf[BUF_SIZE];
Lee Thomason5bb2d802014-01-24 10:42:57 -08001307 XMLUtil::ToStr( v, buf, BUF_SIZE );
1308 SetText( buf );
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001309}
1310
1311
Lee Thomason5bb2d802014-01-24 10:42:57 -08001312void XMLElement::SetText( bool v )
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001313{
1314 char buf[BUF_SIZE];
Lee Thomason5bb2d802014-01-24 10:42:57 -08001315 XMLUtil::ToStr( v, buf, BUF_SIZE );
1316 SetText( buf );
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001317}
1318
1319
Lee Thomason5bb2d802014-01-24 10:42:57 -08001320void XMLElement::SetText( float v )
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001321{
1322 char buf[BUF_SIZE];
Lee Thomason5bb2d802014-01-24 10:42:57 -08001323 XMLUtil::ToStr( v, buf, BUF_SIZE );
1324 SetText( buf );
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001325}
1326
Lee Thomason5bb2d802014-01-24 10:42:57 -08001327
1328void XMLElement::SetText( double v )
Uli Kusterer664d0562014-01-21 12:24:47 +01001329{
1330 char buf[BUF_SIZE];
Lee Thomason5bb2d802014-01-24 10:42:57 -08001331 XMLUtil::ToStr( v, buf, BUF_SIZE );
1332 SetText( buf );
Uli Kusterer664d0562014-01-21 12:24:47 +01001333}
1334
1335
Uli Kustererc1c20bb2014-01-21 02:23:20 +01001336void XMLElement::SetBoolFirstChild( bool inBool )
1337{
1338 if( FirstChild() && FirstChild()->ToElement()
1339 && (strcmp(FirstChild()->Value(),"true") == 0 || strcmp(FirstChild()->Value(),"false") == 0) ) {
1340 FirstChild()->SetValue( inBool ? "true" : "false" );
1341 }
1342 else if( !FirstChild() ) {
1343 XMLElement* theText = GetDocument()->NewElement( inBool ? "true" : "false" );
1344 InsertFirstChild( theText );
1345 }
1346}
1347
1348
Uli Kustererff8e2042014-01-21 02:53:47 +01001349XMLError XMLElement::QueryBoolFirstChild( bool *outBool )
Uli Kustererc1c20bb2014-01-21 02:23:20 +01001350{
Uli Kustererff8e2042014-01-21 02:53:47 +01001351 if ( FirstChild() )
1352 {
1353 if ( FirstChild()->ToElement() )
1354 {
1355 bool isTrue = strcmp( FirstChild()->Value(), "true" ) == 0;
1356 bool isFalse = strcmp( FirstChild()->Value(), "false" ) == 0;
1357 if( !isTrue && !isFalse )
1358 return XML_CAN_NOT_CONVERT_TEXT;
1359
1360 *outBool = isTrue;
1361 return XML_SUCCESS;
1362 }
1363 else
1364 return XML_NO_ELEMENT_NODE;
Uli Kustererc1c20bb2014-01-21 02:23:20 +01001365 }
Uli Kustererff8e2042014-01-21 02:53:47 +01001366 else
1367 return XML_NO_ELEMENT_NODE;
Uli Kustererc1c20bb2014-01-21 02:23:20 +01001368}
1369
1370
MortenMacFly4ee49f12013-01-14 20:03:14 +01001371XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001372{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001373 if ( FirstChild() && FirstChild()->ToText() ) {
1374 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001375 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001376 return XML_SUCCESS;
1377 }
1378 return XML_CAN_NOT_CONVERT_TEXT;
1379 }
1380 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001381}
1382
1383
Uli Kusterer664d0562014-01-21 12:24:47 +01001384XMLError XMLElement::QueryLongLongText( long long* ival ) const
1385{
1386 if ( FirstChild() && FirstChild()->ToText() ) {
1387 const char* t = FirstChild()->ToText()->Value();
1388 if ( XMLUtil::ToLongLong( t, ival ) ) {
1389 return XML_SUCCESS;
1390 }
1391 return XML_CAN_NOT_CONVERT_TEXT;
1392 }
1393 return XML_NO_TEXT_NODE;
1394}
1395
1396
MortenMacFly4ee49f12013-01-14 20:03:14 +01001397XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001398{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001399 if ( FirstChild() && FirstChild()->ToText() ) {
1400 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001401 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001402 return XML_SUCCESS;
1403 }
1404 return XML_CAN_NOT_CONVERT_TEXT;
1405 }
1406 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001407}
1408
1409
MortenMacFly4ee49f12013-01-14 20:03:14 +01001410XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001411{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001412 if ( FirstChild() && FirstChild()->ToText() ) {
1413 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001414 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001415 return XML_SUCCESS;
1416 }
1417 return XML_CAN_NOT_CONVERT_TEXT;
1418 }
1419 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001420}
1421
1422
MortenMacFly4ee49f12013-01-14 20:03:14 +01001423XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001424{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001425 if ( FirstChild() && FirstChild()->ToText() ) {
1426 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001427 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001428 return XML_SUCCESS;
1429 }
1430 return XML_CAN_NOT_CONVERT_TEXT;
1431 }
1432 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001433}
1434
1435
MortenMacFly4ee49f12013-01-14 20:03:14 +01001436XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001437{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001438 if ( FirstChild() && FirstChild()->ToText() ) {
1439 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001440 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001441 return XML_SUCCESS;
1442 }
1443 return XML_CAN_NOT_CONVERT_TEXT;
1444 }
1445 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001446}
1447
1448
1449
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001450XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1451{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001452 XMLAttribute* last = 0;
1453 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001454 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001455 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001456 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001457 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1458 break;
1459 }
1460 }
1461 if ( !attrib ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001462 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1463 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001464 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001465 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001466 }
1467 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001468 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001469 }
1470 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001471 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001472 }
1473 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001474}
1475
1476
U-Stream\Leeae25a442012-02-17 17:48:16 -08001477void XMLElement::DeleteAttribute( const char* name )
1478{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001479 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001480 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001481 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1482 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001483 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001484 }
1485 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001486 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001487 }
1488 DELETE_ATTRIBUTE( a );
1489 break;
1490 }
1491 prev = a;
1492 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001493}
1494
1495
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001496char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001497{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001498 const char* start = p;
1499 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001500
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001501 // Read the attributes.
1502 while( p ) {
1503 p = XMLUtil::SkipWhiteSpace( p );
1504 if ( !p || !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001505 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001506 return 0;
1507 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001508
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001509 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001510 if (XMLUtil::IsNameStartChar( *p ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001511 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1512 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001513 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001514
Lee Thomason624d43f2012-10-12 10:58:48 -07001515 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001516 if ( !p || Attribute( attrib->Name() ) ) {
1517 DELETE_ATTRIBUTE( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001518 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001519 return 0;
1520 }
1521 // There is a minor bug here: if the attribute in the source xml
1522 // document is duplicated, it will not be detected and the
1523 // attribute will be doubly added. However, tracking the 'prevAttribute'
1524 // avoids re-scanning the attribute list. Preferring performance for
1525 // now, may reconsider in the future.
1526 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001527 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001528 }
1529 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001530 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001531 }
1532 prevAttribute = attrib;
1533 }
1534 // end of the tag
1535 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001536 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001537 return p+2; // done; sealed element.
1538 }
1539 // end of the tag
1540 else if ( *p == '>' ) {
1541 ++p;
1542 break;
1543 }
1544 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001545 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001546 return 0;
1547 }
1548 }
1549 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001550}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001551
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001552
Lee Thomason67d61312012-01-24 16:01:51 -08001553//
1554// <ele></ele>
1555// <ele>foo<b>bar</b></ele>
1556//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001557char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001558{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001559 // Read the element name.
1560 p = XMLUtil::SkipWhiteSpace( p );
1561 if ( !p ) {
1562 return 0;
1563 }
Lee Thomason67d61312012-01-24 16:01:51 -08001564
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001565 // The closing element is the </element> form. It is
1566 // parsed just like a regular element then deleted from
1567 // the DOM.
1568 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001569 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001570 ++p;
1571 }
Lee Thomason67d61312012-01-24 16:01:51 -08001572
Lee Thomason624d43f2012-10-12 10:58:48 -07001573 p = _value.ParseName( p );
1574 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001575 return 0;
1576 }
Lee Thomason67d61312012-01-24 16:01:51 -08001577
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001578 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001579 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001580 return p;
1581 }
Lee Thomason67d61312012-01-24 16:01:51 -08001582
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001583 p = XMLNode::ParseDeep( p, strPair );
1584 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001585}
1586
1587
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001588
1589XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1590{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001591 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001592 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001593 }
1594 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1595 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1596 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1597 }
1598 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001599}
1600
1601
1602bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1603{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001604 const XMLElement* other = compare->ToElement();
1605 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001606
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001607 const XMLAttribute* a=FirstAttribute();
1608 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001609
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001610 while ( a && b ) {
1611 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1612 return false;
1613 }
1614 a = a->Next();
1615 b = b->Next();
1616 }
1617 if ( a || b ) {
1618 // different count
1619 return false;
1620 }
1621 return true;
1622 }
1623 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001624}
1625
1626
Lee Thomason751da522012-02-10 08:50:51 -08001627bool XMLElement::Accept( XMLVisitor* visitor ) const
1628{
Lee Thomason624d43f2012-10-12 10:58:48 -07001629 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001630 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1631 if ( !node->Accept( visitor ) ) {
1632 break;
1633 }
1634 }
1635 }
1636 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001637}
Lee Thomason56bdd022012-02-09 18:16:58 -08001638
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001639
Lee Thomason3f57d272012-01-11 15:30:03 -08001640// --------- XMLDocument ----------- //
Lee Thomason624d43f2012-10-12 10:58:48 -07001641XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001642 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001643 _writeBOM( false ),
1644 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001645 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001646 _whitespace( whitespace ),
1647 _errorStr1( 0 ),
1648 _errorStr2( 0 ),
1649 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001650{
Lee Thomason624d43f2012-10-12 10:58:48 -07001651 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001652}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001653
1654
Lee Thomason3f57d272012-01-11 15:30:03 -08001655XMLDocument::~XMLDocument()
1656{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001657 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -07001658 delete [] _charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001659
Lee Thomason (grinliz)61cea672013-02-01 19:13:13 -08001660#if 0
Lee Thomason (grinliz)ac83b4e2013-02-01 09:02:34 -08001661 _textPool.Trace( "text" );
1662 _elementPool.Trace( "element" );
1663 _commentPool.Trace( "comment" );
1664 _attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -08001665#endif
1666
Lee Thomason5b0a6772012-11-19 13:54:42 -08001667#ifdef DEBUG
1668 if ( Error() == false ) {
1669 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1670 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1671 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1672 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1673 }
1674#endif
Lee Thomason3f57d272012-01-11 15:30:03 -08001675}
1676
1677
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001678void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001679{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001680 DeleteChildren();
1681
Lee Thomason624d43f2012-10-12 10:58:48 -07001682 _errorID = XML_NO_ERROR;
1683 _errorStr1 = 0;
1684 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001685
Lee Thomason624d43f2012-10-12 10:58:48 -07001686 delete [] _charBuffer;
1687 _charBuffer = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001688}
1689
Lee Thomason3f57d272012-01-11 15:30:03 -08001690
Lee Thomason2c85a712012-01-31 08:24:24 -08001691XMLElement* XMLDocument::NewElement( const char* name )
1692{
Lee Thomason624d43f2012-10-12 10:58:48 -07001693 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1694 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001695 ele->SetName( name );
1696 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001697}
1698
1699
Lee Thomason1ff38e02012-02-14 18:18:16 -08001700XMLComment* XMLDocument::NewComment( const char* str )
1701{
Lee Thomason624d43f2012-10-12 10:58:48 -07001702 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1703 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001704 comment->SetValue( str );
1705 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001706}
1707
1708
1709XMLText* XMLDocument::NewText( const char* str )
1710{
Lee Thomason624d43f2012-10-12 10:58:48 -07001711 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1712 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001713 text->SetValue( str );
1714 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001715}
1716
1717
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001718XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1719{
Lee Thomason624d43f2012-10-12 10:58:48 -07001720 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1721 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001722 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1723 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001724}
1725
1726
1727XMLUnknown* XMLDocument::NewUnknown( const char* str )
1728{
Lee Thomason624d43f2012-10-12 10:58:48 -07001729 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1730 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001731 unk->SetValue( str );
1732 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001733}
1734
1735
Lee Thomason2fa81722012-11-09 12:37:46 -08001736XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001737{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001738 Clear();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001739 FILE* fp = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001740
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001741#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1742 errno_t err = fopen_s(&fp, filename, "rb" );
1743 if ( !fp || err) {
1744#else
1745 fp = fopen( filename, "rb" );
1746 if ( !fp) {
1747#endif
1748 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001749 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001750 }
1751 LoadFile( fp );
1752 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001753 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001754}
1755
1756
Lee Thomason2fa81722012-11-09 12:37:46 -08001757XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001758{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001759 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001760
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001761 fseek( fp, 0, SEEK_SET );
1762 fgetc( fp );
1763 if ( ferror( fp ) != 0 ) {
1764 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1765 return _errorID;
1766 }
1767
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001768 fseek( fp, 0, SEEK_END );
1769 size_t size = ftell( fp );
1770 fseek( fp, 0, SEEK_SET );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001771
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001772 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001773 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001774 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001775 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001776
Lee Thomason624d43f2012-10-12 10:58:48 -07001777 _charBuffer = new char[size+1];
1778 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001779 if ( read != size ) {
1780 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001781 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001782 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001783
Lee Thomason624d43f2012-10-12 10:58:48 -07001784 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001785
Lee Thomason624d43f2012-10-12 10:58:48 -07001786 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001787 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001788 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001789 if ( !p || !*p ) {
1790 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001791 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001792 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001793
Lee Thomason624d43f2012-10-12 10:58:48 -07001794 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1795 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001796}
1797
1798
Lee Thomason2fa81722012-11-09 12:37:46 -08001799XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001800{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001801 FILE* fp = 0;
1802#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1803 errno_t err = fopen_s(&fp, filename, "w" );
1804 if ( !fp || err) {
1805#else
1806 fp = fopen( filename, "w" );
1807 if ( !fp) {
1808#endif
1809 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001810 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001811 }
1812 SaveFile(fp, compact);
1813 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001814 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001815}
1816
1817
Lee Thomason2fa81722012-11-09 12:37:46 -08001818XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001819{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001820 XMLPrinter stream( fp, compact );
1821 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001822 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001823}
1824
Lee Thomason1ff38e02012-02-14 18:18:16 -08001825
Lee Thomason2fa81722012-11-09 12:37:46 -08001826XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001827{
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001828 const char* start = p;
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001829 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001830
psi690ba072013-11-03 10:54:33 +09001831 if ( len == 0 ) {
1832 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1833 return _errorID;
1834 }
1835
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001836 if ( !p || !*p ) {
1837 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001838 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001839 }
1840 if ( len == (size_t)(-1) ) {
1841 len = strlen( p );
1842 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001843 _charBuffer = new char[ len+1 ];
1844 memcpy( _charBuffer, p, len );
1845 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001846
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001847 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001848 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001849 if ( !p || !*p ) {
1850 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001851 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001852 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001853
Thomas Roß1470edc2013-05-10 15:44:12 +02001854 ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001855 ParseDeep( _charBuffer+delta, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001856 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001857}
1858
1859
PKEuS1c5f99e2013-07-06 11:28:39 +02001860void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001861{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001862 XMLPrinter stdStreamer( stdout );
1863 if ( !streamer ) {
1864 streamer = &stdStreamer;
1865 }
1866 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001867}
1868
1869
Lee Thomason2fa81722012-11-09 12:37:46 -08001870void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001871{
Lee Thomason624d43f2012-10-12 10:58:48 -07001872 _errorID = error;
1873 _errorStr1 = str1;
1874 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001875}
1876
Lee Thomason5cae8972012-01-24 18:03:07 -08001877
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001878void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001879{
Lee Thomason624d43f2012-10-12 10:58:48 -07001880 if ( _errorID ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001881 static const int LEN = 20;
1882 char buf1[LEN] = { 0 };
1883 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001884
Lee Thomason624d43f2012-10-12 10:58:48 -07001885 if ( _errorStr1 ) {
1886 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001887 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001888 if ( _errorStr2 ) {
1889 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001890 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001891
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001892 printf( "XMLDocument error id=%d str1=%s str2=%s\n",
Lee Thomason624d43f2012-10-12 10:58:48 -07001893 _errorID, buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001894 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001895}
1896
1897
PKEuS1bfb9542013-08-04 13:51:17 +02001898XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001899 _elementJustOpened( false ),
1900 _firstElement( true ),
1901 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001902 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001903 _textDepth( -1 ),
1904 _processEntities( true ),
1905 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001906{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001907 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001908 _entityFlag[i] = false;
1909 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001910 }
1911 for( int i=0; i<NUM_ENTITIES; ++i ) {
1912 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1913 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001914 _entityFlag[ (int)entities[i].value ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001915 }
1916 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001917 _restrictedEntityFlag[(int)'&'] = true;
1918 _restrictedEntityFlag[(int)'<'] = true;
1919 _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
1920 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001921}
1922
1923
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001924void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001925{
1926 va_list va;
1927 va_start( va, format );
1928
Lee Thomason624d43f2012-10-12 10:58:48 -07001929 if ( _fp ) {
1930 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001931 }
1932 else {
1933 // This seems brutally complex. Haven't figured out a better
1934 // way on windows.
1935#ifdef _MSC_VER
1936 int len = -1;
1937 int expand = 1000;
1938 while ( len < 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001939 len = vsnprintf_s( _accumulator.Mem(), _accumulator.Capacity(), _TRUNCATE, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001940 if ( len < 0 ) {
1941 expand *= 3/2;
Lee Thomason1aa8fc42012-10-13 20:01:30 -07001942 _accumulator.PushArr( expand );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001943 }
1944 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001945 char* p = _buffer.PushArr( len ) - 1;
1946 memcpy( p, _accumulator.Mem(), len+1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001947#else
1948 int len = vsnprintf( 0, 0, format, va );
1949 // Close out and re-start the va-args
1950 va_end( va );
1951 va_start( va, format );
Lee Thomason624d43f2012-10-12 10:58:48 -07001952 char* p = _buffer.PushArr( len ) - 1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001953 vsnprintf( p, len+1, format, va );
1954#endif
1955 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001956 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001957}
1958
1959
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001960void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001961{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001962 for( int i=0; i<depth; ++i ) {
1963 Print( " " );
1964 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001965}
1966
1967
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001968void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001969{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001970 // Look for runs of bytes between entities to print.
1971 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001972 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001973
Lee Thomason624d43f2012-10-12 10:58:48 -07001974 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001975 while ( *q ) {
1976 // Remember, char is sometimes signed. (How many times has that bitten me?)
1977 if ( *q > 0 && *q < ENTITY_RANGE ) {
1978 // Check for entities. If one is found, flush
1979 // the stream up until the entity, write the
1980 // entity, and keep looking.
1981 if ( flag[(unsigned)(*q)] ) {
1982 while ( p < q ) {
1983 Print( "%c", *p );
1984 ++p;
1985 }
1986 for( int i=0; i<NUM_ENTITIES; ++i ) {
1987 if ( entities[i].value == *q ) {
1988 Print( "&%s;", entities[i].pattern );
1989 break;
1990 }
1991 }
1992 ++p;
1993 }
1994 }
1995 ++q;
1996 }
1997 }
1998 // Flush the remaining string. This will be the entire
1999 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07002000 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002001 Print( "%s", p );
2002 }
Lee Thomason857b8682012-01-25 17:50:25 -08002003}
2004
U-Stream\Leeae25a442012-02-17 17:48:16 -08002005
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002006void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002007{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002008 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002009 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 -07002010 Print( "%s", bom );
2011 }
2012 if ( writeDec ) {
2013 PushDeclaration( "xml version=\"1.0\"" );
2014 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002015}
2016
2017
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002018void XMLPrinter::OpenElement( const char* name )
Lee Thomason5cae8972012-01-24 18:03:07 -08002019{
Lee Thomason624d43f2012-10-12 10:58:48 -07002020 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002021 SealElement();
2022 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002023 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002024
Lee Thomason624d43f2012-10-12 10:58:48 -07002025 if ( _textDepth < 0 && !_firstElement && !_compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002026 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002027 }
2028 if ( !_compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002029 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002030 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002031
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002032 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002033 _elementJustOpened = true;
2034 _firstElement = false;
2035 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002036}
2037
2038
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002039void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002040{
Lee Thomason624d43f2012-10-12 10:58:48 -07002041 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002042 Print( " %s=\"", name );
2043 PrintString( value, false );
2044 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002045}
2046
2047
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002048void XMLPrinter::PushAttribute( const char* name, int v )
2049{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002050 char buf[BUF_SIZE];
2051 XMLUtil::ToStr( v, buf, BUF_SIZE );
2052 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002053}
2054
2055
2056void XMLPrinter::PushAttribute( const char* name, unsigned v )
2057{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002058 char buf[BUF_SIZE];
2059 XMLUtil::ToStr( v, buf, BUF_SIZE );
2060 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002061}
2062
2063
2064void XMLPrinter::PushAttribute( const char* name, bool v )
2065{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002066 char buf[BUF_SIZE];
2067 XMLUtil::ToStr( v, buf, BUF_SIZE );
2068 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002069}
2070
2071
2072void XMLPrinter::PushAttribute( const char* name, double v )
2073{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002074 char buf[BUF_SIZE];
2075 XMLUtil::ToStr( v, buf, BUF_SIZE );
2076 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002077}
2078
2079
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002080void XMLPrinter::CloseElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08002081{
Lee Thomason624d43f2012-10-12 10:58:48 -07002082 --_depth;
2083 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002084
Lee Thomason624d43f2012-10-12 10:58:48 -07002085 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002086 Print( "/>" );
2087 }
2088 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07002089 if ( _textDepth < 0 && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002090 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002091 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002092 }
2093 Print( "</%s>", name );
2094 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002095
Lee Thomason624d43f2012-10-12 10:58:48 -07002096 if ( _textDepth == _depth ) {
2097 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002098 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002099 if ( _depth == 0 && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002100 Print( "\n" );
2101 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002102 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002103}
2104
2105
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002106void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08002107{
Lee Thomason624d43f2012-10-12 10:58:48 -07002108 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002109 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002110}
2111
2112
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002113void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002114{
Lee Thomason624d43f2012-10-12 10:58:48 -07002115 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002116
Lee Thomason624d43f2012-10-12 10:58:48 -07002117 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002118 SealElement();
2119 }
2120 if ( cdata ) {
2121 Print( "<![CDATA[" );
2122 Print( "%s", text );
2123 Print( "]]>" );
2124 }
2125 else {
2126 PrintString( text, true );
2127 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002128}
2129
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002130void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002131{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002132 char buf[BUF_SIZE];
2133 XMLUtil::ToStr( value, buf, BUF_SIZE );
2134 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002135}
2136
2137
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002138void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002139{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002140 char buf[BUF_SIZE];
2141 XMLUtil::ToStr( value, buf, BUF_SIZE );
2142 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002143}
2144
2145
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002146void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002147{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002148 char buf[BUF_SIZE];
2149 XMLUtil::ToStr( value, buf, BUF_SIZE );
2150 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002151}
2152
2153
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002154void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002155{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002156 char buf[BUF_SIZE];
2157 XMLUtil::ToStr( value, buf, BUF_SIZE );
2158 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002159}
2160
2161
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002162void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002163{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002164 char buf[BUF_SIZE];
2165 XMLUtil::ToStr( value, buf, BUF_SIZE );
2166 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002167}
2168
Lee Thomason5cae8972012-01-24 18:03:07 -08002169
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002170void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002171{
Lee Thomason624d43f2012-10-12 10:58:48 -07002172 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002173 SealElement();
2174 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002175 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002176 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002177 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002178 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002179 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002180 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002181}
Lee Thomason751da522012-02-10 08:50:51 -08002182
2183
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002184void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002185{
Lee Thomason624d43f2012-10-12 10:58:48 -07002186 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002187 SealElement();
2188 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002189 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002190 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002191 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002192 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002193 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002194 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002195}
2196
2197
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002198void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002199{
Lee Thomason624d43f2012-10-12 10:58:48 -07002200 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002201 SealElement();
2202 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002203 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002204 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002205 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002206 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002207 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002208 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002209}
2210
2211
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002212bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002213{
Lee Thomason624d43f2012-10-12 10:58:48 -07002214 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002215 if ( doc.HasBOM() ) {
2216 PushHeader( true, false );
2217 }
2218 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002219}
2220
2221
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002222bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002223{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002224 OpenElement( element.Name() );
2225 while ( attribute ) {
2226 PushAttribute( attribute->Name(), attribute->Value() );
2227 attribute = attribute->Next();
2228 }
2229 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002230}
2231
2232
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08002233bool XMLPrinter::VisitExit( const XMLElement& )
Lee Thomason751da522012-02-10 08:50:51 -08002234{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002235 CloseElement();
2236 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002237}
2238
2239
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002240bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002241{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002242 PushText( text.Value(), text.CData() );
2243 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002244}
2245
2246
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002247bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002248{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002249 PushComment( comment.Value() );
2250 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002251}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002252
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002253bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002254{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002255 PushDeclaration( declaration.Value() );
2256 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002257}
2258
2259
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002260bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002261{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002262 PushUnknown( unknown.Value() );
2263 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002264}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002265
Lee Thomason685b8952012-11-12 13:00:06 -08002266} // namespace tinyxml2
2267