blob: c273ebef6530d5b9ad1cea37dc60abf1bb4e601d [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
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400115 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700116 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{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400153 // Adjusting _start would cause undefined behavior on delete[]
154 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700155 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700156 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700157
Lee Thomason120b3a62012-10-12 10:06:59 -0700158 if ( _start && *_start ) {
159 char* p = _start; // the read pointer
160 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700161
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700162 while( *p ) {
163 if ( XMLUtil::IsWhiteSpace( *p )) {
164 p = XMLUtil::SkipWhiteSpace( p );
165 if ( *p == 0 ) {
166 break; // don't write to q; this trims the trailing space.
167 }
168 *q = ' ';
169 ++q;
170 }
171 *q = *p;
172 ++q;
173 ++p;
174 }
175 *q = 0;
176 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700177}
178
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800179
Lee Thomasone4422302012-01-20 17:59:50 -0800180const char* StrPair::GetStr()
181{
Lee Thomason120b3a62012-10-12 10:06:59 -0700182 if ( _flags & NEEDS_FLUSH ) {
183 *_end = 0;
184 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800185
Lee Thomason120b3a62012-10-12 10:06:59 -0700186 if ( _flags ) {
187 char* p = _start; // the read pointer
188 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800189
Lee Thomason120b3a62012-10-12 10:06:59 -0700190 while( p < _end ) {
191 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700192 // CR-LF pair becomes LF
193 // CR alone becomes LF
194 // LF-CR becomes LF
195 if ( *(p+1) == LF ) {
196 p += 2;
197 }
198 else {
199 ++p;
200 }
201 *q++ = LF;
202 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700203 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700204 if ( *(p+1) == CR ) {
205 p += 2;
206 }
207 else {
208 ++p;
209 }
210 *q++ = LF;
211 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700212 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700213 // Entities handled by tinyXML2:
214 // - special entities in the entity table [in/out]
215 // - numeric character reference [in]
216 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800217
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700218 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400219 const int buflen = 10;
220 char buf[buflen] = { 0 };
221 int len = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700222 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
Dmitry-Me63f3de12014-08-21 12:33:19 +0400223 TIXMLASSERT( 0 <= len && len <= buflen );
224 TIXMLASSERT( q + len <= p );
225 memcpy( q, buf, len );
226 q += len;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700227 }
228 else {
229 int i=0;
230 for(; i<NUM_ENTITIES; ++i ) {
231 if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
232 && *(p+entities[i].length+1) == ';' ) {
233 // Found an entity convert;
234 *q = entities[i].value;
235 ++q;
236 p += entities[i].length + 2;
237 break;
238 }
239 }
240 if ( i == NUM_ENTITIES ) {
241 // fixme: treat as error?
242 ++p;
243 ++q;
244 }
245 }
246 }
247 else {
248 *q = *p;
249 ++p;
250 ++q;
251 }
252 }
253 *q = 0;
254 }
255 // The loop below has plenty going on, and this
256 // is a less useful mode. Break it out.
Lee Thomason120b3a62012-10-12 10:06:59 -0700257 if ( _flags & COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700258 CollapseWhitespace();
259 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700260 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700261 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700262 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800263}
264
Lee Thomason2c85a712012-01-31 08:24:24 -0800265
Lee Thomasone4422302012-01-20 17:59:50 -0800266
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800267
Lee Thomason56bdd022012-02-09 18:16:58 -0800268// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800269
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800270const char* XMLUtil::ReadBOM( const char* p, bool* bom )
271{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700272 *bom = false;
273 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
274 // Check for BOM:
275 if ( *(pu+0) == TIXML_UTF_LEAD_0
276 && *(pu+1) == TIXML_UTF_LEAD_1
277 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
278 *bom = true;
279 p += 3;
280 }
281 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800282}
283
284
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800285void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
286{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700287 const unsigned long BYTE_MASK = 0xBF;
288 const unsigned long BYTE_MARK = 0x80;
289 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800290
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700291 if (input < 0x80) {
292 *length = 1;
293 }
294 else if ( input < 0x800 ) {
295 *length = 2;
296 }
297 else if ( input < 0x10000 ) {
298 *length = 3;
299 }
300 else if ( input < 0x200000 ) {
301 *length = 4;
302 }
303 else {
304 *length = 0; // This code won't covert this correctly anyway.
305 return;
306 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800307
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700308 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800309
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700310 // Scary scary fall throughs.
311 switch (*length) {
312 case 4:
313 --output;
314 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
315 input >>= 6;
316 case 3:
317 --output;
318 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
319 input >>= 6;
320 case 2:
321 --output;
322 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
323 input >>= 6;
324 case 1:
325 --output;
326 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100327 default:
328 break;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700329 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800330}
331
332
333const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
334{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700335 // Presume an entity, and pull it out.
336 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800337
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700338 if ( *(p+1) == '#' && *(p+2) ) {
339 unsigned long ucs = 0;
340 ptrdiff_t delta = 0;
341 unsigned mult = 1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800342
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700343 if ( *(p+2) == 'x' ) {
344 // Hexadecimal.
345 if ( !*(p+3) ) {
346 return 0;
347 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800348
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700349 const char* q = p+3;
350 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800351
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700352 if ( !q || !*q ) {
353 return 0;
354 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800355
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700356 delta = q-p;
357 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800358
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700359 while ( *q != 'x' ) {
360 if ( *q >= '0' && *q <= '9' ) {
361 ucs += mult * (*q - '0');
362 }
363 else if ( *q >= 'a' && *q <= 'f' ) {
364 ucs += mult * (*q - 'a' + 10);
365 }
366 else if ( *q >= 'A' && *q <= 'F' ) {
367 ucs += mult * (*q - 'A' + 10 );
368 }
369 else {
370 return 0;
371 }
372 mult *= 16;
373 --q;
374 }
375 }
376 else {
377 // Decimal.
378 if ( !*(p+2) ) {
379 return 0;
380 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800381
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700382 const char* q = p+2;
383 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800384
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700385 if ( !q || !*q ) {
386 return 0;
387 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800388
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700389 delta = q-p;
390 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800391
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700392 while ( *q != '#' ) {
393 if ( *q >= '0' && *q <= '9' ) {
394 ucs += mult * (*q - '0');
395 }
396 else {
397 return 0;
398 }
399 mult *= 10;
400 --q;
401 }
402 }
403 // convert the UCS to UTF-8
404 ConvertUTF32ToUTF8( ucs, value, length );
405 return p + delta + 1;
406 }
407 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800408}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800409
410
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700411void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700412{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700413 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700414}
415
416
417void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
418{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700419 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700420}
421
422
423void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
424{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700425 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700426}
427
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800428/*
429 ToStr() of a number is a very tricky topic.
430 https://github.com/leethomason/tinyxml2/issues/106
431*/
Lee Thomason21be8822012-07-15 17:27:22 -0700432void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
433{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800434 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700435}
436
437
438void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
439{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800440 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700441}
442
443
444bool XMLUtil::ToInt( const char* str, int* value )
445{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700446 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
447 return true;
448 }
449 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700450}
451
452bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
453{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700454 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
455 return true;
456 }
457 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700458}
459
460bool XMLUtil::ToBool( const char* str, bool* value )
461{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700462 int ival = 0;
463 if ( ToInt( str, &ival )) {
464 *value = (ival==0) ? false : true;
465 return true;
466 }
467 if ( StringEqual( str, "true" ) ) {
468 *value = true;
469 return true;
470 }
471 else if ( StringEqual( str, "false" ) ) {
472 *value = false;
473 return true;
474 }
475 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700476}
477
478
479bool XMLUtil::ToFloat( const char* str, float* value )
480{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700481 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
482 return true;
483 }
484 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700485}
486
487bool XMLUtil::ToDouble( const char* str, double* value )
488{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700489 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
490 return true;
491 }
492 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700493}
494
495
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700496char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800497{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700498 XMLNode* returnNode = 0;
499 char* start = p;
500 p = XMLUtil::SkipWhiteSpace( p );
501 if( !p || !*p ) {
502 return p;
503 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800504
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700505 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800506 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700507 static const char* xmlHeader = { "<?" };
508 static const char* commentHeader = { "<!--" };
509 static const char* dtdHeader = { "<!" };
510 static const char* cdataHeader = { "<![CDATA[" };
511 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800512
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700513 static const int xmlHeaderLen = 2;
514 static const int commentHeaderLen = 4;
515 static const int dtdHeaderLen = 2;
516 static const int cdataHeaderLen = 9;
517 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800518
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800519#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800520#pragma warning ( push )
521#pragma warning ( disable : 4127 )
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800522#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700523 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
524 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800525#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800526#pragma warning (pop)
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800527#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700528 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700529 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
530 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700531 p += xmlHeaderLen;
532 }
533 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700534 returnNode = new (_commentPool.Alloc()) XMLComment( this );
535 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700536 p += commentHeaderLen;
537 }
538 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700539 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700540 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700541 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700542 p += cdataHeaderLen;
543 text->SetCData( true );
544 }
545 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700546 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
547 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700548 p += dtdHeaderLen;
549 }
550 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700551 returnNode = new (_elementPool.Alloc()) XMLElement( this );
552 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700553 p += elementHeaderLen;
554 }
555 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700556 returnNode = new (_textPool.Alloc()) XMLText( this );
557 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700558 p = start; // Back it up, all the text counts.
559 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800560
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700561 *node = returnNode;
562 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800563}
564
565
Lee Thomason751da522012-02-10 08:50:51 -0800566bool XMLDocument::Accept( XMLVisitor* visitor ) const
567{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700568 if ( visitor->VisitEnter( *this ) ) {
569 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
570 if ( !node->Accept( visitor ) ) {
571 break;
572 }
573 }
574 }
575 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800576}
Lee Thomason56bdd022012-02-09 18:16:58 -0800577
578
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800579// --------- XMLNode ----------- //
580
581XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700582 _document( doc ),
583 _parent( 0 ),
584 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200585 _prev( 0 ), _next( 0 ),
586 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800587{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800588}
589
590
591XMLNode::~XMLNode()
592{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700593 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700594 if ( _parent ) {
595 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700596 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800597}
598
Michael Daumling21626882013-10-22 17:03:37 +0200599const char* XMLNode::Value() const
600{
601 return _value.GetStr();
602}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800603
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800604void XMLNode::SetValue( const char* str, bool staticMem )
605{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700606 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700607 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700608 }
609 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700610 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700611 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800612}
613
614
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800615void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800616{
Lee Thomason624d43f2012-10-12 10:58:48 -0700617 while( _firstChild ) {
618 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700619 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700620
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700621 DELETE_NODE( node );
622 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700623 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800624}
625
626
627void XMLNode::Unlink( XMLNode* child )
628{
Lee Thomason624d43f2012-10-12 10:58:48 -0700629 if ( child == _firstChild ) {
630 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700631 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700632 if ( child == _lastChild ) {
633 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700634 }
Lee Thomasond923c672012-01-23 08:44:25 -0800635
Lee Thomason624d43f2012-10-12 10:58:48 -0700636 if ( child->_prev ) {
637 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700638 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700639 if ( child->_next ) {
640 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700641 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700642 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800643}
644
645
U-Stream\Leeae25a442012-02-17 17:48:16 -0800646void XMLNode::DeleteChild( XMLNode* node )
647{
Lee Thomason624d43f2012-10-12 10:58:48 -0700648 TIXMLASSERT( node->_parent == this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700649 DELETE_NODE( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800650}
651
652
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800653XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
654{
Michael Daumlinged523282013-10-23 07:47:29 +0200655 if (addThis->_document != _document)
656 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700657
Michael Daumlinged523282013-10-23 07:47:29 +0200658 if (addThis->_parent)
659 addThis->_parent->Unlink( addThis );
660 else
661 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700662
Lee Thomason624d43f2012-10-12 10:58:48 -0700663 if ( _lastChild ) {
664 TIXMLASSERT( _firstChild );
665 TIXMLASSERT( _lastChild->_next == 0 );
666 _lastChild->_next = addThis;
667 addThis->_prev = _lastChild;
668 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800669
Lee Thomason624d43f2012-10-12 10:58:48 -0700670 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700671 }
672 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700673 TIXMLASSERT( _firstChild == 0 );
674 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800675
Lee Thomason624d43f2012-10-12 10:58:48 -0700676 addThis->_prev = 0;
677 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700678 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700679 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700680 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800681}
682
683
Lee Thomason1ff38e02012-02-14 18:18:16 -0800684XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
685{
Michael Daumlinged523282013-10-23 07:47:29 +0200686 if (addThis->_document != _document)
687 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700688
Michael Daumlinged523282013-10-23 07:47:29 +0200689 if (addThis->_parent)
690 addThis->_parent->Unlink( addThis );
691 else
692 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700693
Lee Thomason624d43f2012-10-12 10:58:48 -0700694 if ( _firstChild ) {
695 TIXMLASSERT( _lastChild );
696 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800697
Lee Thomason624d43f2012-10-12 10:58:48 -0700698 _firstChild->_prev = addThis;
699 addThis->_next = _firstChild;
700 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800701
Lee Thomason624d43f2012-10-12 10:58:48 -0700702 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700703 }
704 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700705 TIXMLASSERT( _lastChild == 0 );
706 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800707
Lee Thomason624d43f2012-10-12 10:58:48 -0700708 addThis->_prev = 0;
709 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700710 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700711 addThis->_parent = this;
Michael Daumlinged523282013-10-23 07:47:29 +0200712 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800713}
714
715
716XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
717{
Michael Daumlinged523282013-10-23 07:47:29 +0200718 if (addThis->_document != _document)
719 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700720
Lee Thomason624d43f2012-10-12 10:58:48 -0700721 TIXMLASSERT( afterThis->_parent == this );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700722
Lee Thomason624d43f2012-10-12 10:58:48 -0700723 if ( afterThis->_parent != this ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700724 return 0;
725 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800726
Lee Thomason624d43f2012-10-12 10:58:48 -0700727 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700728 // The last node or the only node.
729 return InsertEndChild( addThis );
730 }
Michael Daumlinged523282013-10-23 07:47:29 +0200731 if (addThis->_parent)
732 addThis->_parent->Unlink( addThis );
733 else
734 addThis->_memPool->SetTracked();
Lee Thomason624d43f2012-10-12 10:58:48 -0700735 addThis->_prev = afterThis;
736 addThis->_next = afterThis->_next;
737 afterThis->_next->_prev = addThis;
738 afterThis->_next = addThis;
739 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700740 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800741}
742
743
744
745
Lee Thomason56bdd022012-02-09 18:16:58 -0800746const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800747{
Lee Thomason624d43f2012-10-12 10:58:48 -0700748 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700749 XMLElement* element = node->ToElement();
750 if ( element ) {
751 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
752 return element;
753 }
754 }
755 }
756 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800757}
758
759
Lee Thomason56bdd022012-02-09 18:16:58 -0800760const XMLElement* XMLNode::LastChildElement( const char* value ) const
761{
Lee Thomason624d43f2012-10-12 10:58:48 -0700762 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700763 XMLElement* element = node->ToElement();
764 if ( element ) {
765 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
766 return element;
767 }
768 }
769 }
770 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800771}
772
773
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800774const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
775{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400776 for( XMLNode* node=this->_next; node; node = node->_next ) {
777 const XMLElement* element = node->ToElement();
778 if ( element
779 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
780 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700781 }
782 }
783 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800784}
785
786
787const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
788{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400789 for( XMLNode* node=_prev; node; node = node->_prev ) {
790 const XMLElement* element = node->ToElement();
791 if ( element
792 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
793 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700794 }
795 }
796 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800797}
798
799
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800800char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800801{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700802 // This is a recursive method, but thinking about it "at the current level"
803 // it is a pretty simple flat list:
804 // <foo/>
805 // <!-- comment -->
806 //
807 // With a special case:
808 // <foo>
809 // </foo>
810 // <!-- comment -->
811 //
812 // Where the closing element (/foo) *must* be the next thing after the opening
813 // element, and the names must match. BUT the tricky bit is that the closing
814 // element will be read by the child.
815 //
816 // 'endTag' is the end tag for this node, it is returned by a call to a child.
817 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800818
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700819 while( p && *p ) {
820 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800821
Lee Thomason624d43f2012-10-12 10:58:48 -0700822 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700823 if ( p == 0 || node == 0 ) {
824 break;
825 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800826
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700827 StrPair endTag;
828 p = node->ParseDeep( p, &endTag );
829 if ( !p ) {
830 DELETE_NODE( node );
831 node = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -0700832 if ( !_document->Error() ) {
833 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700834 }
835 break;
836 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800837
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400838 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700839 // We read the end tag. Return it to the parent.
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400840 if ( ele && ele->ClosingType() == XMLElement::CLOSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700841 if ( parentEnd ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700842 *parentEnd = static_cast<XMLElement*>(node)->_value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700843 }
Lee Thomason5b0a6772012-11-19 13:54:42 -0800844 node->_memPool->SetTracked(); // created and then immediately deleted.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700845 DELETE_NODE( node );
846 return p;
847 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800848
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700849 // Handle an end tag returned to this level.
850 // And handle a bunch of annoying errors.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700851 if ( ele ) {
852 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700853 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700854 p = 0;
855 }
856 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700857 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700858 p = 0;
859 }
860 else if ( !endTag.Empty() ) {
861 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
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 }
866 }
867 if ( p == 0 ) {
868 DELETE_NODE( node );
869 node = 0;
870 }
871 if ( node ) {
872 this->InsertEndChild( node );
873 }
874 }
875 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800876}
877
Lee Thomason5492a1c2012-01-23 15:32:10 -0800878// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800879char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800880{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700881 const char* start = p;
882 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700883 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700884 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700885 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700886 }
887 return p;
888 }
889 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700890 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
891 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700892 flags |= StrPair::COLLAPSE_WHITESPACE;
893 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700894
Lee Thomason624d43f2012-10-12 10:58:48 -0700895 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700896 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700897 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700898 }
899 if ( p && *p ) {
900 return p-1;
901 }
902 }
903 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800904}
905
906
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800907XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
908{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700909 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700910 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700911 }
912 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
913 text->SetCData( this->CData() );
914 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800915}
916
917
918bool XMLText::ShallowEqual( const XMLNode* compare ) const
919{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700920 return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800921}
922
923
Lee Thomason56bdd022012-02-09 18:16:58 -0800924bool XMLText::Accept( XMLVisitor* visitor ) const
925{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700926 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800927}
928
929
Lee Thomason3f57d272012-01-11 15:30:03 -0800930// --------- XMLComment ---------- //
931
Lee Thomasone4422302012-01-20 17:59:50 -0800932XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800933{
934}
935
936
Lee Thomasonce0763e2012-01-11 15:43:54 -0800937XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800938{
Lee Thomason3f57d272012-01-11 15:30:03 -0800939}
940
941
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800942char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800943{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700944 // Comment parses as text.
945 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700946 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700947 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700948 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700949 }
950 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800951}
952
953
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800954XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
955{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700956 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700957 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700958 }
959 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
960 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800961}
962
963
964bool XMLComment::ShallowEqual( const XMLNode* compare ) const
965{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400966 const XMLComment* comment = compare->ToComment();
967 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800968}
969
970
Lee Thomason751da522012-02-10 08:50:51 -0800971bool XMLComment::Accept( XMLVisitor* visitor ) const
972{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700973 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800974}
Lee Thomason56bdd022012-02-09 18:16:58 -0800975
976
Lee Thomason50f97b22012-02-11 16:33:40 -0800977// --------- XMLDeclaration ---------- //
978
979XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
980{
981}
982
983
984XMLDeclaration::~XMLDeclaration()
985{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700986 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -0800987}
988
989
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800990char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800991{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700992 // Declaration parses as text.
993 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700994 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700995 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700996 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700997 }
998 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800999}
1000
1001
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001002XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1003{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001004 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001005 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001006 }
1007 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1008 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001009}
1010
1011
1012bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1013{
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001014 const XMLDeclaration* declaration = compare->ToDeclaration();
1015 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001016}
1017
1018
1019
Lee Thomason50f97b22012-02-11 16:33:40 -08001020bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1021{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001022 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001023}
1024
1025// --------- XMLUnknown ---------- //
1026
1027XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1028{
1029}
1030
1031
1032XMLUnknown::~XMLUnknown()
1033{
1034}
1035
1036
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001037char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001038{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001039 // Unknown parses as text.
1040 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001041
Lee Thomason624d43f2012-10-12 10:58:48 -07001042 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001043 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001044 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001045 }
1046 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001047}
1048
1049
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001050XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1051{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001052 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001053 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001054 }
1055 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1056 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001057}
1058
1059
1060bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1061{
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001062 const XMLUnknown* unknown = compare->ToUnknown();
1063 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001064}
1065
1066
Lee Thomason50f97b22012-02-11 16:33:40 -08001067bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1068{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001069 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001070}
1071
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001072// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001073
1074const char* XMLAttribute::Name() const
1075{
1076 return _name.GetStr();
1077}
1078
1079const char* XMLAttribute::Value() const
1080{
1081 return _value.GetStr();
1082}
1083
Lee Thomason6f381b72012-03-02 12:59:39 -08001084char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001085{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001086 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001087 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001088 if ( !p || !*p ) {
1089 return 0;
1090 }
Lee Thomason22aead12012-01-23 13:29:35 -08001091
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001092 // Skip white space before =
1093 p = XMLUtil::SkipWhiteSpace( p );
1094 if ( !p || *p != '=' ) {
1095 return 0;
1096 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001097
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001098 ++p; // move up to opening quote
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 char endTag[2] = { *p, 0 };
1105 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001106
Lee Thomason624d43f2012-10-12 10:58:48 -07001107 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001108 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001109}
1110
1111
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001112void XMLAttribute::SetName( const char* n )
1113{
Lee Thomason624d43f2012-10-12 10:58:48 -07001114 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001115}
1116
1117
Lee Thomason2fa81722012-11-09 12:37:46 -08001118XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001119{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001120 if ( XMLUtil::ToInt( Value(), value )) {
1121 return XML_NO_ERROR;
1122 }
1123 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001124}
1125
1126
Lee Thomason2fa81722012-11-09 12:37:46 -08001127XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001128{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001129 if ( XMLUtil::ToUnsigned( Value(), value )) {
1130 return XML_NO_ERROR;
1131 }
1132 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001133}
1134
1135
Lee Thomason2fa81722012-11-09 12:37:46 -08001136XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001137{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001138 if ( XMLUtil::ToBool( Value(), value )) {
1139 return XML_NO_ERROR;
1140 }
1141 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001142}
1143
1144
Lee Thomason2fa81722012-11-09 12:37:46 -08001145XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001146{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001147 if ( XMLUtil::ToFloat( Value(), value )) {
1148 return XML_NO_ERROR;
1149 }
1150 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001151}
1152
1153
Lee Thomason2fa81722012-11-09 12:37:46 -08001154XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001155{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001156 if ( XMLUtil::ToDouble( Value(), value )) {
1157 return XML_NO_ERROR;
1158 }
1159 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001160}
1161
1162
1163void XMLAttribute::SetAttribute( const char* v )
1164{
Lee Thomason624d43f2012-10-12 10:58:48 -07001165 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001166}
1167
1168
Lee Thomason1ff38e02012-02-14 18:18:16 -08001169void XMLAttribute::SetAttribute( int v )
1170{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001171 char buf[BUF_SIZE];
1172 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001173 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001174}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001175
1176
1177void XMLAttribute::SetAttribute( unsigned v )
1178{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001179 char buf[BUF_SIZE];
1180 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001181 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001182}
1183
1184
1185void XMLAttribute::SetAttribute( bool v )
1186{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001187 char buf[BUF_SIZE];
1188 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001189 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001190}
1191
1192void XMLAttribute::SetAttribute( double v )
1193{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001194 char buf[BUF_SIZE];
1195 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001196 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001197}
1198
1199void XMLAttribute::SetAttribute( float 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
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001206
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001207// --------- XMLElement ---------- //
1208XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001209 _closingType( 0 ),
1210 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001211{
1212}
1213
1214
1215XMLElement::~XMLElement()
1216{
Lee Thomason624d43f2012-10-12 10:58:48 -07001217 while( _rootAttribute ) {
1218 XMLAttribute* next = _rootAttribute->_next;
1219 DELETE_ATTRIBUTE( _rootAttribute );
1220 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001221 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001222}
1223
1224
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001225XMLAttribute* XMLElement::FindAttribute( const char* name )
1226{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001227 XMLAttribute* a = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001228 for( a=_rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001229 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1230 return a;
1231 }
1232 }
1233 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001234}
1235
1236
1237const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1238{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001239 XMLAttribute* a = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001240 for( a=_rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001241 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1242 return a;
1243 }
1244 }
1245 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001246}
1247
1248
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001249const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001250{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001251 const XMLAttribute* a = FindAttribute( name );
1252 if ( !a ) {
1253 return 0;
1254 }
1255 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1256 return a->Value();
1257 }
1258 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001259}
1260
1261
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001262const char* XMLElement::GetText() const
1263{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001264 if ( FirstChild() && FirstChild()->ToText() ) {
1265 return FirstChild()->ToText()->Value();
1266 }
1267 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001268}
1269
1270
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001271void XMLElement::SetText( const char* inText )
1272{
Uli Kusterer869bb592014-01-21 01:36:16 +01001273 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001274 FirstChild()->SetValue( inText );
1275 else {
1276 XMLText* theText = GetDocument()->NewText( inText );
1277 InsertFirstChild( theText );
1278 }
1279}
1280
Lee Thomason5bb2d802014-01-24 10:42:57 -08001281
1282void XMLElement::SetText( int v )
1283{
1284 char buf[BUF_SIZE];
1285 XMLUtil::ToStr( v, buf, BUF_SIZE );
1286 SetText( buf );
1287}
1288
1289
1290void XMLElement::SetText( unsigned v )
1291{
1292 char buf[BUF_SIZE];
1293 XMLUtil::ToStr( v, buf, BUF_SIZE );
1294 SetText( buf );
1295}
1296
1297
1298void XMLElement::SetText( bool v )
1299{
1300 char buf[BUF_SIZE];
1301 XMLUtil::ToStr( v, buf, BUF_SIZE );
1302 SetText( buf );
1303}
1304
1305
1306void XMLElement::SetText( float v )
1307{
1308 char buf[BUF_SIZE];
1309 XMLUtil::ToStr( v, buf, BUF_SIZE );
1310 SetText( buf );
1311}
1312
1313
1314void XMLElement::SetText( double v )
1315{
1316 char buf[BUF_SIZE];
1317 XMLUtil::ToStr( v, buf, BUF_SIZE );
1318 SetText( buf );
1319}
1320
1321
MortenMacFly4ee49f12013-01-14 20:03:14 +01001322XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001323{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001324 if ( FirstChild() && FirstChild()->ToText() ) {
1325 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001326 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001327 return XML_SUCCESS;
1328 }
1329 return XML_CAN_NOT_CONVERT_TEXT;
1330 }
1331 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001332}
1333
1334
MortenMacFly4ee49f12013-01-14 20:03:14 +01001335XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001336{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001337 if ( FirstChild() && FirstChild()->ToText() ) {
1338 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001339 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001340 return XML_SUCCESS;
1341 }
1342 return XML_CAN_NOT_CONVERT_TEXT;
1343 }
1344 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001345}
1346
1347
MortenMacFly4ee49f12013-01-14 20:03:14 +01001348XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001349{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001350 if ( FirstChild() && FirstChild()->ToText() ) {
1351 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001352 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001353 return XML_SUCCESS;
1354 }
1355 return XML_CAN_NOT_CONVERT_TEXT;
1356 }
1357 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001358}
1359
1360
MortenMacFly4ee49f12013-01-14 20:03:14 +01001361XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001362{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001363 if ( FirstChild() && FirstChild()->ToText() ) {
1364 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001365 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001366 return XML_SUCCESS;
1367 }
1368 return XML_CAN_NOT_CONVERT_TEXT;
1369 }
1370 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001371}
1372
1373
MortenMacFly4ee49f12013-01-14 20:03:14 +01001374XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001375{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001376 if ( FirstChild() && FirstChild()->ToText() ) {
1377 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001378 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001379 return XML_SUCCESS;
1380 }
1381 return XML_CAN_NOT_CONVERT_TEXT;
1382 }
1383 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001384}
1385
1386
1387
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001388XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1389{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001390 XMLAttribute* last = 0;
1391 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001392 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001393 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001394 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001395 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1396 break;
1397 }
1398 }
1399 if ( !attrib ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001400 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1401 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001402 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001403 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001404 }
1405 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001406 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001407 }
1408 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001409 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001410 }
1411 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001412}
1413
1414
U-Stream\Leeae25a442012-02-17 17:48:16 -08001415void XMLElement::DeleteAttribute( const char* name )
1416{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001417 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001418 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001419 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1420 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001421 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001422 }
1423 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001424 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001425 }
1426 DELETE_ATTRIBUTE( a );
1427 break;
1428 }
1429 prev = a;
1430 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001431}
1432
1433
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001434char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001435{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001436 const char* start = p;
1437 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001438
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001439 // Read the attributes.
1440 while( p ) {
1441 p = XMLUtil::SkipWhiteSpace( p );
1442 if ( !p || !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001443 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001444 return 0;
1445 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001446
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001447 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001448 if (XMLUtil::IsNameStartChar( *p ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001449 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1450 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001451 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001452
Lee Thomason624d43f2012-10-12 10:58:48 -07001453 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001454 if ( !p || Attribute( attrib->Name() ) ) {
1455 DELETE_ATTRIBUTE( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001456 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001457 return 0;
1458 }
1459 // There is a minor bug here: if the attribute in the source xml
1460 // document is duplicated, it will not be detected and the
1461 // attribute will be doubly added. However, tracking the 'prevAttribute'
1462 // avoids re-scanning the attribute list. Preferring performance for
1463 // now, may reconsider in the future.
1464 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001465 prevAttribute->_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 prevAttribute = attrib;
1471 }
1472 // end of the tag
1473 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001474 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001475 return p+2; // done; sealed element.
1476 }
1477 // end of the tag
1478 else if ( *p == '>' ) {
1479 ++p;
1480 break;
1481 }
1482 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001483 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001484 return 0;
1485 }
1486 }
1487 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001488}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001489
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001490
Lee Thomason67d61312012-01-24 16:01:51 -08001491//
1492// <ele></ele>
1493// <ele>foo<b>bar</b></ele>
1494//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001495char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001496{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001497 // Read the element name.
1498 p = XMLUtil::SkipWhiteSpace( p );
1499 if ( !p ) {
1500 return 0;
1501 }
Lee Thomason67d61312012-01-24 16:01:51 -08001502
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001503 // The closing element is the </element> form. It is
1504 // parsed just like a regular element then deleted from
1505 // the DOM.
1506 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001507 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001508 ++p;
1509 }
Lee Thomason67d61312012-01-24 16:01:51 -08001510
Lee Thomason624d43f2012-10-12 10:58:48 -07001511 p = _value.ParseName( p );
1512 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001513 return 0;
1514 }
Lee Thomason67d61312012-01-24 16:01:51 -08001515
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001516 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001517 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001518 return p;
1519 }
Lee Thomason67d61312012-01-24 16:01:51 -08001520
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001521 p = XMLNode::ParseDeep( p, strPair );
1522 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001523}
1524
1525
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001526
1527XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1528{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001529 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001530 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001531 }
1532 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1533 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1534 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1535 }
1536 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001537}
1538
1539
1540bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1541{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001542 const XMLElement* other = compare->ToElement();
1543 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001544
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001545 const XMLAttribute* a=FirstAttribute();
1546 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001547
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001548 while ( a && b ) {
1549 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1550 return false;
1551 }
1552 a = a->Next();
1553 b = b->Next();
1554 }
1555 if ( a || b ) {
1556 // different count
1557 return false;
1558 }
1559 return true;
1560 }
1561 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001562}
1563
1564
Lee Thomason751da522012-02-10 08:50:51 -08001565bool XMLElement::Accept( XMLVisitor* visitor ) const
1566{
Lee Thomason624d43f2012-10-12 10:58:48 -07001567 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001568 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1569 if ( !node->Accept( visitor ) ) {
1570 break;
1571 }
1572 }
1573 }
1574 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001575}
Lee Thomason56bdd022012-02-09 18:16:58 -08001576
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001577
Lee Thomason3f57d272012-01-11 15:30:03 -08001578// --------- XMLDocument ----------- //
Lee Thomason624d43f2012-10-12 10:58:48 -07001579XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001580 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001581 _writeBOM( false ),
1582 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001583 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001584 _whitespace( whitespace ),
1585 _errorStr1( 0 ),
1586 _errorStr2( 0 ),
1587 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001588{
Lee Thomason624d43f2012-10-12 10:58:48 -07001589 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001590}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001591
1592
Lee Thomason3f57d272012-01-11 15:30:03 -08001593XMLDocument::~XMLDocument()
1594{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001595 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -07001596 delete [] _charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001597
Lee Thomason (grinliz)61cea672013-02-01 19:13:13 -08001598#if 0
Lee Thomason (grinliz)ac83b4e2013-02-01 09:02:34 -08001599 _textPool.Trace( "text" );
1600 _elementPool.Trace( "element" );
1601 _commentPool.Trace( "comment" );
1602 _attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -08001603#endif
1604
Lee Thomason5b0a6772012-11-19 13:54:42 -08001605#ifdef DEBUG
1606 if ( Error() == false ) {
1607 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1608 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1609 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1610 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1611 }
1612#endif
Lee Thomason3f57d272012-01-11 15:30:03 -08001613}
1614
1615
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001616void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001617{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001618 DeleteChildren();
1619
Lee Thomason624d43f2012-10-12 10:58:48 -07001620 _errorID = XML_NO_ERROR;
1621 _errorStr1 = 0;
1622 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001623
Lee Thomason624d43f2012-10-12 10:58:48 -07001624 delete [] _charBuffer;
1625 _charBuffer = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001626}
1627
Lee Thomason3f57d272012-01-11 15:30:03 -08001628
Lee Thomason2c85a712012-01-31 08:24:24 -08001629XMLElement* XMLDocument::NewElement( const char* name )
1630{
Lee Thomason624d43f2012-10-12 10:58:48 -07001631 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1632 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001633 ele->SetName( name );
1634 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001635}
1636
1637
Lee Thomason1ff38e02012-02-14 18:18:16 -08001638XMLComment* XMLDocument::NewComment( const char* str )
1639{
Lee Thomason624d43f2012-10-12 10:58:48 -07001640 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1641 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001642 comment->SetValue( str );
1643 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001644}
1645
1646
1647XMLText* XMLDocument::NewText( const char* str )
1648{
Lee Thomason624d43f2012-10-12 10:58:48 -07001649 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1650 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001651 text->SetValue( str );
1652 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001653}
1654
1655
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001656XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1657{
Lee Thomason624d43f2012-10-12 10:58:48 -07001658 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1659 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001660 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1661 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001662}
1663
1664
1665XMLUnknown* XMLDocument::NewUnknown( const char* str )
1666{
Lee Thomason624d43f2012-10-12 10:58:48 -07001667 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1668 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001669 unk->SetValue( str );
1670 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001671}
1672
Dmitry-Me01578db2014-08-19 10:18:48 +04001673static FILE* callfopen( const char* filepath, const char* mode )
1674{
1675#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1676 FILE* fp = 0;
1677 errno_t err = fopen_s( &fp, filepath, mode );
1678 if ( err ) {
1679 return 0;
1680 }
1681#else
1682 FILE* fp = fopen( filepath, mode );
1683#endif
1684 return fp;
1685}
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001686
Lee Thomason2fa81722012-11-09 12:37:46 -08001687XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001688{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001689 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001690 FILE* fp = callfopen( filename, "rb" );
1691 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001692 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001693 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001694 }
1695 LoadFile( fp );
1696 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001697 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001698}
1699
1700
Lee Thomason2fa81722012-11-09 12:37:46 -08001701XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001702{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001703 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001704
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001705 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001706 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001707 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1708 return _errorID;
1709 }
1710
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001711 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001712 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001713 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001714 if ( filelength == -1L ) {
1715 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1716 return _errorID;
1717 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001718
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001719 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001720 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001721 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001722 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001723 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001724
Lee Thomason624d43f2012-10-12 10:58:48 -07001725 _charBuffer = new char[size+1];
1726 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001727 if ( read != size ) {
1728 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001729 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001730 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001731
Lee Thomason624d43f2012-10-12 10:58:48 -07001732 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001733
Lee Thomason624d43f2012-10-12 10:58:48 -07001734 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001735 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001736 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001737 if ( !p || !*p ) {
1738 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001739 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001740 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001741
Lee Thomason624d43f2012-10-12 10:58:48 -07001742 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1743 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001744}
1745
1746
Lee Thomason2fa81722012-11-09 12:37:46 -08001747XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001748{
Dmitry-Me01578db2014-08-19 10:18:48 +04001749 FILE* fp = callfopen( filename, "w" );
1750 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001751 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001752 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001753 }
1754 SaveFile(fp, compact);
1755 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001756 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001757}
1758
1759
Lee Thomason2fa81722012-11-09 12:37:46 -08001760XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001761{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001762 XMLPrinter stream( fp, compact );
1763 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001764 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001765}
1766
Lee Thomason1ff38e02012-02-14 18:18:16 -08001767
Lee Thomason2fa81722012-11-09 12:37:46 -08001768XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001769{
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001770 const char* start = p;
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001771 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001772
Lee Thomason82d32002014-02-21 22:47:18 -08001773 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001774 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001775 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001776 }
1777 if ( len == (size_t)(-1) ) {
1778 len = strlen( p );
1779 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001780 _charBuffer = new char[ len+1 ];
1781 memcpy( _charBuffer, p, len );
1782 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001783
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001784 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001785 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001786 if ( !p || !*p ) {
1787 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001788 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001789 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001790
Thomas Roß1470edc2013-05-10 15:44:12 +02001791 ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001792 ParseDeep( _charBuffer+delta, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001793 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001794}
1795
1796
PKEuS1c5f99e2013-07-06 11:28:39 +02001797void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001798{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001799 XMLPrinter stdStreamer( stdout );
1800 if ( !streamer ) {
1801 streamer = &stdStreamer;
1802 }
1803 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001804}
1805
1806
Lee Thomason2fa81722012-11-09 12:37:46 -08001807void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001808{
Lee Thomason624d43f2012-10-12 10:58:48 -07001809 _errorID = error;
1810 _errorStr1 = str1;
1811 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001812}
1813
Lee Thomason5cae8972012-01-24 18:03:07 -08001814
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001815void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001816{
Lee Thomason624d43f2012-10-12 10:58:48 -07001817 if ( _errorID ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001818 static const int LEN = 20;
1819 char buf1[LEN] = { 0 };
1820 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001821
Lee Thomason624d43f2012-10-12 10:58:48 -07001822 if ( _errorStr1 ) {
1823 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001824 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001825 if ( _errorStr2 ) {
1826 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001827 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001828
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001829 printf( "XMLDocument error id=%d str1=%s str2=%s\n",
Lee Thomason624d43f2012-10-12 10:58:48 -07001830 _errorID, buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001831 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001832}
1833
1834
PKEuS1bfb9542013-08-04 13:51:17 +02001835XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001836 _elementJustOpened( false ),
1837 _firstElement( true ),
1838 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001839 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001840 _textDepth( -1 ),
1841 _processEntities( true ),
1842 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001843{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001844 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001845 _entityFlag[i] = false;
1846 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001847 }
1848 for( int i=0; i<NUM_ENTITIES; ++i ) {
1849 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1850 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001851 _entityFlag[ (int)entities[i].value ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001852 }
1853 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001854 _restrictedEntityFlag[(int)'&'] = true;
1855 _restrictedEntityFlag[(int)'<'] = true;
1856 _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
1857 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001858}
1859
1860
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001861void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001862{
1863 va_list va;
1864 va_start( va, format );
1865
Lee Thomason624d43f2012-10-12 10:58:48 -07001866 if ( _fp ) {
1867 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001868 }
1869 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001870#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001871 #if defined(WINCE)
1872 int len = 512;
1873 do {
1874 len = len*2;
1875 char* str = new char[len]();
1876 len = _vsnprintf(str, len, format, va);
1877 delete[] str;
1878 }while (len < 0);
1879 #else
Thomas Roß268c6832014-03-13 23:35:16 +01001880 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08001881 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001882#else
1883 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01001884#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001885 // Close out and re-start the va-args
1886 va_end( va );
1887 va_start( va, format );
Lee Thomasona0744c82014-03-16 10:32:27 -07001888 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
1889#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001890 #if defined(WINCE)
1891 _vsnprintf( p, len+1, format, va );
1892 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07001893 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08001894 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07001895#else
1896 vsnprintf( p, len+1, format, va );
1897#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001898 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001899 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001900}
1901
1902
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001903void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001904{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001905 for( int i=0; i<depth; ++i ) {
1906 Print( " " );
1907 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001908}
1909
1910
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001911void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001912{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001913 // Look for runs of bytes between entities to print.
1914 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001915 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001916
Lee Thomason624d43f2012-10-12 10:58:48 -07001917 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001918 while ( *q ) {
1919 // Remember, char is sometimes signed. (How many times has that bitten me?)
1920 if ( *q > 0 && *q < ENTITY_RANGE ) {
1921 // Check for entities. If one is found, flush
1922 // the stream up until the entity, write the
1923 // entity, and keep looking.
1924 if ( flag[(unsigned)(*q)] ) {
1925 while ( p < q ) {
1926 Print( "%c", *p );
1927 ++p;
1928 }
1929 for( int i=0; i<NUM_ENTITIES; ++i ) {
1930 if ( entities[i].value == *q ) {
1931 Print( "&%s;", entities[i].pattern );
1932 break;
1933 }
1934 }
1935 ++p;
1936 }
1937 }
1938 ++q;
1939 }
1940 }
1941 // Flush the remaining string. This will be the entire
1942 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07001943 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001944 Print( "%s", p );
1945 }
Lee Thomason857b8682012-01-25 17:50:25 -08001946}
1947
U-Stream\Leeae25a442012-02-17 17:48:16 -08001948
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001949void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001950{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001951 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02001952 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 -07001953 Print( "%s", bom );
1954 }
1955 if ( writeDec ) {
1956 PushDeclaration( "xml version=\"1.0\"" );
1957 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001958}
1959
1960
Uli Kusterer593a33d2014-02-01 12:48:51 +01001961void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08001962{
Lee Thomason624d43f2012-10-12 10:58:48 -07001963 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001964 SealElement();
1965 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001966 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08001967
Uli Kusterer593a33d2014-02-01 12:48:51 +01001968 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001969 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02001970 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01001971 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001972 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001973 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001974
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001975 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07001976 _elementJustOpened = true;
1977 _firstElement = false;
1978 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08001979}
1980
1981
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001982void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08001983{
Lee Thomason624d43f2012-10-12 10:58:48 -07001984 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001985 Print( " %s=\"", name );
1986 PrintString( value, false );
1987 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001988}
1989
1990
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001991void XMLPrinter::PushAttribute( const char* name, int v )
1992{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001993 char buf[BUF_SIZE];
1994 XMLUtil::ToStr( v, buf, BUF_SIZE );
1995 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001996}
1997
1998
1999void XMLPrinter::PushAttribute( const char* name, unsigned v )
2000{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002001 char buf[BUF_SIZE];
2002 XMLUtil::ToStr( v, buf, BUF_SIZE );
2003 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002004}
2005
2006
2007void XMLPrinter::PushAttribute( const char* name, bool v )
2008{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002009 char buf[BUF_SIZE];
2010 XMLUtil::ToStr( v, buf, BUF_SIZE );
2011 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002012}
2013
2014
2015void XMLPrinter::PushAttribute( const char* name, double v )
2016{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002017 char buf[BUF_SIZE];
2018 XMLUtil::ToStr( v, buf, BUF_SIZE );
2019 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002020}
2021
2022
Uli Kustererca412e82014-02-01 13:35:05 +01002023void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002024{
Lee Thomason624d43f2012-10-12 10:58:48 -07002025 --_depth;
2026 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002027
Lee Thomason624d43f2012-10-12 10:58:48 -07002028 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002029 Print( "/>" );
2030 }
2031 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002032 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002033 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002034 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002035 }
2036 Print( "</%s>", name );
2037 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002038
Lee Thomason624d43f2012-10-12 10:58:48 -07002039 if ( _textDepth == _depth ) {
2040 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002041 }
Uli Kustererca412e82014-02-01 13:35:05 +01002042 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002043 Print( "\n" );
2044 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002045 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002046}
2047
2048
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002049void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08002050{
Lee Thomason624d43f2012-10-12 10:58:48 -07002051 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002052 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002053}
2054
2055
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002056void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002057{
Lee Thomason624d43f2012-10-12 10:58:48 -07002058 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002059
Lee Thomason624d43f2012-10-12 10:58:48 -07002060 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002061 SealElement();
2062 }
2063 if ( cdata ) {
2064 Print( "<![CDATA[" );
2065 Print( "%s", text );
2066 Print( "]]>" );
2067 }
2068 else {
2069 PrintString( text, true );
2070 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002071}
2072
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002073void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002074{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002075 char buf[BUF_SIZE];
2076 XMLUtil::ToStr( value, buf, BUF_SIZE );
2077 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002078}
2079
2080
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002081void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002082{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002083 char buf[BUF_SIZE];
2084 XMLUtil::ToStr( value, buf, BUF_SIZE );
2085 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002086}
2087
2088
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002089void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002090{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002091 char buf[BUF_SIZE];
2092 XMLUtil::ToStr( value, buf, BUF_SIZE );
2093 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002094}
2095
2096
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002097void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002098{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002099 char buf[BUF_SIZE];
2100 XMLUtil::ToStr( value, buf, BUF_SIZE );
2101 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002102}
2103
2104
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002105void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002106{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002107 char buf[BUF_SIZE];
2108 XMLUtil::ToStr( value, buf, BUF_SIZE );
2109 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002110}
2111
Lee Thomason5cae8972012-01-24 18:03:07 -08002112
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002113void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002114{
Lee Thomason624d43f2012-10-12 10:58:48 -07002115 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002116 SealElement();
2117 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002118 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002119 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002120 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002121 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002122 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002123 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002124}
Lee Thomason751da522012-02-10 08:50:51 -08002125
2126
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002127void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002128{
Lee Thomason624d43f2012-10-12 10:58:48 -07002129 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002130 SealElement();
2131 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002132 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002133 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002134 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002135 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002136 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002137 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002138}
2139
2140
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002141void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002142{
Lee Thomason624d43f2012-10-12 10:58:48 -07002143 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002144 SealElement();
2145 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002146 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002147 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002148 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002149 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002150 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002151 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002152}
2153
2154
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002155bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002156{
Lee Thomason624d43f2012-10-12 10:58:48 -07002157 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002158 if ( doc.HasBOM() ) {
2159 PushHeader( true, false );
2160 }
2161 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002162}
2163
2164
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002165bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002166{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002167 const XMLElement* parentElem = element.Parent()->ToElement();
2168 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2169 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002170 while ( attribute ) {
2171 PushAttribute( attribute->Name(), attribute->Value() );
2172 attribute = attribute->Next();
2173 }
2174 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002175}
2176
2177
Uli Kustererca412e82014-02-01 13:35:05 +01002178bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002179{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002180 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002181 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002182}
2183
2184
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002185bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002186{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002187 PushText( text.Value(), text.CData() );
2188 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002189}
2190
2191
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002192bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002193{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002194 PushComment( comment.Value() );
2195 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002196}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002197
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002198bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002199{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002200 PushDeclaration( declaration.Value() );
2201 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002202}
2203
2204
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002205bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002206{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002207 PushUnknown( unknown.Value() );
2208 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002209}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002210
Lee Thomason685b8952012-11-12 13:00:06 -08002211} // namespace tinyxml2
2212