blob: df345f97470de0c2644f5b88148268b618aa9f10 [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{
Lee Thomason624d43f2012-10-12 10:58:48 -0700776 for( XMLNode* element=this->_next; element; element = element->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700777 if ( element->ToElement()
778 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
779 return element->ToElement();
780 }
781 }
782 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800783}
784
785
786const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
787{
Lee Thomason624d43f2012-10-12 10:58:48 -0700788 for( XMLNode* element=_prev; element; element = element->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700789 if ( element->ToElement()
790 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
791 return element->ToElement();
792 }
793 }
794 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800795}
796
797
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800798char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800799{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700800 // This is a recursive method, but thinking about it "at the current level"
801 // it is a pretty simple flat list:
802 // <foo/>
803 // <!-- comment -->
804 //
805 // With a special case:
806 // <foo>
807 // </foo>
808 // <!-- comment -->
809 //
810 // Where the closing element (/foo) *must* be the next thing after the opening
811 // element, and the names must match. BUT the tricky bit is that the closing
812 // element will be read by the child.
813 //
814 // 'endTag' is the end tag for this node, it is returned by a call to a child.
815 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800816
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700817 while( p && *p ) {
818 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800819
Lee Thomason624d43f2012-10-12 10:58:48 -0700820 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700821 if ( p == 0 || node == 0 ) {
822 break;
823 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800824
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700825 StrPair endTag;
826 p = node->ParseDeep( p, &endTag );
827 if ( !p ) {
828 DELETE_NODE( node );
829 node = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -0700830 if ( !_document->Error() ) {
831 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700832 }
833 break;
834 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800835
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700836 // We read the end tag. Return it to the parent.
837 if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
838 if ( parentEnd ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700839 *parentEnd = static_cast<XMLElement*>(node)->_value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700840 }
Lee Thomason5b0a6772012-11-19 13:54:42 -0800841 node->_memPool->SetTracked(); // created and then immediately deleted.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700842 DELETE_NODE( node );
843 return p;
844 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800845
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700846 // Handle an end tag returned to this level.
847 // And handle a bunch of annoying errors.
848 XMLElement* ele = node->ToElement();
849 if ( ele ) {
850 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700851 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700852 p = 0;
853 }
854 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700855 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700856 p = 0;
857 }
858 else if ( !endTag.Empty() ) {
859 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700860 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700861 p = 0;
862 }
863 }
864 }
865 if ( p == 0 ) {
866 DELETE_NODE( node );
867 node = 0;
868 }
869 if ( node ) {
870 this->InsertEndChild( node );
871 }
872 }
873 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800874}
875
Lee Thomason5492a1c2012-01-23 15:32:10 -0800876// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800877char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800878{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700879 const char* start = p;
880 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700881 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700882 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700883 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700884 }
885 return p;
886 }
887 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700888 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
889 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700890 flags |= StrPair::COLLAPSE_WHITESPACE;
891 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700892
Lee Thomason624d43f2012-10-12 10:58:48 -0700893 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700894 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700895 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700896 }
897 if ( p && *p ) {
898 return p-1;
899 }
900 }
901 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800902}
903
904
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800905XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
906{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700907 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700908 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700909 }
910 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
911 text->SetCData( this->CData() );
912 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800913}
914
915
916bool XMLText::ShallowEqual( const XMLNode* compare ) const
917{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700918 return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800919}
920
921
Lee Thomason56bdd022012-02-09 18:16:58 -0800922bool XMLText::Accept( XMLVisitor* visitor ) const
923{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700924 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800925}
926
927
Lee Thomason3f57d272012-01-11 15:30:03 -0800928// --------- XMLComment ---------- //
929
Lee Thomasone4422302012-01-20 17:59:50 -0800930XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800931{
932}
933
934
Lee Thomasonce0763e2012-01-11 15:43:54 -0800935XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800936{
Lee Thomason3f57d272012-01-11 15:30:03 -0800937}
938
939
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800940char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800941{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700942 // Comment parses as text.
943 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700944 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700945 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700946 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700947 }
948 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800949}
950
951
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800952XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
953{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700954 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700955 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700956 }
957 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
958 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800959}
960
961
962bool XMLComment::ShallowEqual( const XMLNode* compare ) const
963{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700964 return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800965}
966
967
Lee Thomason751da522012-02-10 08:50:51 -0800968bool XMLComment::Accept( XMLVisitor* visitor ) const
969{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700970 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800971}
Lee Thomason56bdd022012-02-09 18:16:58 -0800972
973
Lee Thomason50f97b22012-02-11 16:33:40 -0800974// --------- XMLDeclaration ---------- //
975
976XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
977{
978}
979
980
981XMLDeclaration::~XMLDeclaration()
982{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700983 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -0800984}
985
986
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800987char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800988{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700989 // Declaration parses as text.
990 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700991 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700992 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700993 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700994 }
995 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800996}
997
998
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800999XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1000{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001001 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001002 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001003 }
1004 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1005 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001006}
1007
1008
1009bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1010{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001011 return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001012}
1013
1014
1015
Lee Thomason50f97b22012-02-11 16:33:40 -08001016bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1017{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001018 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001019}
1020
1021// --------- XMLUnknown ---------- //
1022
1023XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1024{
1025}
1026
1027
1028XMLUnknown::~XMLUnknown()
1029{
1030}
1031
1032
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001033char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001034{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001035 // Unknown parses as text.
1036 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001037
Lee Thomason624d43f2012-10-12 10:58:48 -07001038 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001039 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001040 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001041 }
1042 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001043}
1044
1045
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001046XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1047{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001048 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001049 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001050 }
1051 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1052 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001053}
1054
1055
1056bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1057{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001058 return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001059}
1060
1061
Lee Thomason50f97b22012-02-11 16:33:40 -08001062bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1063{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001064 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001065}
1066
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001067// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001068
1069const char* XMLAttribute::Name() const
1070{
1071 return _name.GetStr();
1072}
1073
1074const char* XMLAttribute::Value() const
1075{
1076 return _value.GetStr();
1077}
1078
Lee Thomason6f381b72012-03-02 12:59:39 -08001079char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001080{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001081 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001082 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001083 if ( !p || !*p ) {
1084 return 0;
1085 }
Lee Thomason22aead12012-01-23 13:29:35 -08001086
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001087 // Skip white space before =
1088 p = XMLUtil::SkipWhiteSpace( p );
1089 if ( !p || *p != '=' ) {
1090 return 0;
1091 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001092
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001093 ++p; // move up to opening quote
1094 p = XMLUtil::SkipWhiteSpace( p );
1095 if ( *p != '\"' && *p != '\'' ) {
1096 return 0;
1097 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001098
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001099 char endTag[2] = { *p, 0 };
1100 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001101
Lee Thomason624d43f2012-10-12 10:58:48 -07001102 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001103 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001104}
1105
1106
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001107void XMLAttribute::SetName( const char* n )
1108{
Lee Thomason624d43f2012-10-12 10:58:48 -07001109 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001110}
1111
1112
Lee Thomason2fa81722012-11-09 12:37:46 -08001113XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001114{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001115 if ( XMLUtil::ToInt( Value(), value )) {
1116 return XML_NO_ERROR;
1117 }
1118 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001119}
1120
1121
Lee Thomason2fa81722012-11-09 12:37:46 -08001122XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001123{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001124 if ( XMLUtil::ToUnsigned( Value(), value )) {
1125 return XML_NO_ERROR;
1126 }
1127 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001128}
1129
1130
Lee Thomason2fa81722012-11-09 12:37:46 -08001131XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001132{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001133 if ( XMLUtil::ToBool( Value(), value )) {
1134 return XML_NO_ERROR;
1135 }
1136 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001137}
1138
1139
Lee Thomason2fa81722012-11-09 12:37:46 -08001140XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001141{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001142 if ( XMLUtil::ToFloat( Value(), value )) {
1143 return XML_NO_ERROR;
1144 }
1145 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001146}
1147
1148
Lee Thomason2fa81722012-11-09 12:37:46 -08001149XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001150{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001151 if ( XMLUtil::ToDouble( Value(), value )) {
1152 return XML_NO_ERROR;
1153 }
1154 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001155}
1156
1157
1158void XMLAttribute::SetAttribute( const char* v )
1159{
Lee Thomason624d43f2012-10-12 10:58:48 -07001160 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001161}
1162
1163
Lee Thomason1ff38e02012-02-14 18:18:16 -08001164void XMLAttribute::SetAttribute( int v )
1165{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001166 char buf[BUF_SIZE];
1167 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001168 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001169}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001170
1171
1172void XMLAttribute::SetAttribute( unsigned v )
1173{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001174 char buf[BUF_SIZE];
1175 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001176 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001177}
1178
1179
1180void XMLAttribute::SetAttribute( bool v )
1181{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001182 char buf[BUF_SIZE];
1183 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001184 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001185}
1186
1187void XMLAttribute::SetAttribute( double v )
1188{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001189 char buf[BUF_SIZE];
1190 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001191 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001192}
1193
1194void XMLAttribute::SetAttribute( float v )
1195{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001196 char buf[BUF_SIZE];
1197 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001198 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001199}
1200
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001201
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001202// --------- XMLElement ---------- //
1203XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001204 _closingType( 0 ),
1205 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001206{
1207}
1208
1209
1210XMLElement::~XMLElement()
1211{
Lee Thomason624d43f2012-10-12 10:58:48 -07001212 while( _rootAttribute ) {
1213 XMLAttribute* next = _rootAttribute->_next;
1214 DELETE_ATTRIBUTE( _rootAttribute );
1215 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001216 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001217}
1218
1219
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001220XMLAttribute* XMLElement::FindAttribute( const char* name )
1221{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001222 XMLAttribute* a = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001223 for( a=_rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001224 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1225 return a;
1226 }
1227 }
1228 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001229}
1230
1231
1232const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1233{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001234 XMLAttribute* a = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001235 for( a=_rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001236 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1237 return a;
1238 }
1239 }
1240 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001241}
1242
1243
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001244const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001245{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001246 const XMLAttribute* a = FindAttribute( name );
1247 if ( !a ) {
1248 return 0;
1249 }
1250 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1251 return a->Value();
1252 }
1253 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001254}
1255
1256
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001257const char* XMLElement::GetText() const
1258{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001259 if ( FirstChild() && FirstChild()->ToText() ) {
1260 return FirstChild()->ToText()->Value();
1261 }
1262 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001263}
1264
1265
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001266void XMLElement::SetText( const char* inText )
1267{
Uli Kusterer869bb592014-01-21 01:36:16 +01001268 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001269 FirstChild()->SetValue( inText );
1270 else {
1271 XMLText* theText = GetDocument()->NewText( inText );
1272 InsertFirstChild( theText );
1273 }
1274}
1275
Lee Thomason5bb2d802014-01-24 10:42:57 -08001276
1277void XMLElement::SetText( int v )
1278{
1279 char buf[BUF_SIZE];
1280 XMLUtil::ToStr( v, buf, BUF_SIZE );
1281 SetText( buf );
1282}
1283
1284
1285void XMLElement::SetText( unsigned v )
1286{
1287 char buf[BUF_SIZE];
1288 XMLUtil::ToStr( v, buf, BUF_SIZE );
1289 SetText( buf );
1290}
1291
1292
1293void XMLElement::SetText( bool v )
1294{
1295 char buf[BUF_SIZE];
1296 XMLUtil::ToStr( v, buf, BUF_SIZE );
1297 SetText( buf );
1298}
1299
1300
1301void XMLElement::SetText( float v )
1302{
1303 char buf[BUF_SIZE];
1304 XMLUtil::ToStr( v, buf, BUF_SIZE );
1305 SetText( buf );
1306}
1307
1308
1309void XMLElement::SetText( double v )
1310{
1311 char buf[BUF_SIZE];
1312 XMLUtil::ToStr( v, buf, BUF_SIZE );
1313 SetText( buf );
1314}
1315
1316
MortenMacFly4ee49f12013-01-14 20:03:14 +01001317XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001318{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001319 if ( FirstChild() && FirstChild()->ToText() ) {
1320 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001321 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001322 return XML_SUCCESS;
1323 }
1324 return XML_CAN_NOT_CONVERT_TEXT;
1325 }
1326 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001327}
1328
1329
MortenMacFly4ee49f12013-01-14 20:03:14 +01001330XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001331{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001332 if ( FirstChild() && FirstChild()->ToText() ) {
1333 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001334 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001335 return XML_SUCCESS;
1336 }
1337 return XML_CAN_NOT_CONVERT_TEXT;
1338 }
1339 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001340}
1341
1342
MortenMacFly4ee49f12013-01-14 20:03:14 +01001343XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001344{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001345 if ( FirstChild() && FirstChild()->ToText() ) {
1346 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001347 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001348 return XML_SUCCESS;
1349 }
1350 return XML_CAN_NOT_CONVERT_TEXT;
1351 }
1352 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001353}
1354
1355
MortenMacFly4ee49f12013-01-14 20:03:14 +01001356XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001357{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001358 if ( FirstChild() && FirstChild()->ToText() ) {
1359 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001360 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001361 return XML_SUCCESS;
1362 }
1363 return XML_CAN_NOT_CONVERT_TEXT;
1364 }
1365 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001366}
1367
1368
MortenMacFly4ee49f12013-01-14 20:03:14 +01001369XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001370{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001371 if ( FirstChild() && FirstChild()->ToText() ) {
1372 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001373 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001374 return XML_SUCCESS;
1375 }
1376 return XML_CAN_NOT_CONVERT_TEXT;
1377 }
1378 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001379}
1380
1381
1382
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001383XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1384{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001385 XMLAttribute* last = 0;
1386 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001387 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001388 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001389 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001390 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1391 break;
1392 }
1393 }
1394 if ( !attrib ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001395 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1396 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001397 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001398 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001399 }
1400 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001401 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001402 }
1403 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001404 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001405 }
1406 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001407}
1408
1409
U-Stream\Leeae25a442012-02-17 17:48:16 -08001410void XMLElement::DeleteAttribute( const char* name )
1411{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001412 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001413 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001414 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1415 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001416 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001417 }
1418 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001419 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001420 }
1421 DELETE_ATTRIBUTE( a );
1422 break;
1423 }
1424 prev = a;
1425 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001426}
1427
1428
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001429char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001430{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001431 const char* start = p;
1432 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001433
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001434 // Read the attributes.
1435 while( p ) {
1436 p = XMLUtil::SkipWhiteSpace( p );
1437 if ( !p || !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001438 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001439 return 0;
1440 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001441
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001442 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001443 if (XMLUtil::IsNameStartChar( *p ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001444 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1445 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001446 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001447
Lee Thomason624d43f2012-10-12 10:58:48 -07001448 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001449 if ( !p || Attribute( attrib->Name() ) ) {
1450 DELETE_ATTRIBUTE( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001451 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001452 return 0;
1453 }
1454 // There is a minor bug here: if the attribute in the source xml
1455 // document is duplicated, it will not be detected and the
1456 // attribute will be doubly added. However, tracking the 'prevAttribute'
1457 // avoids re-scanning the attribute list. Preferring performance for
1458 // now, may reconsider in the future.
1459 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001460 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001461 }
1462 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001463 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001464 }
1465 prevAttribute = attrib;
1466 }
1467 // end of the tag
1468 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001469 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001470 return p+2; // done; sealed element.
1471 }
1472 // end of the tag
1473 else if ( *p == '>' ) {
1474 ++p;
1475 break;
1476 }
1477 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001478 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001479 return 0;
1480 }
1481 }
1482 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001483}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001484
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001485
Lee Thomason67d61312012-01-24 16:01:51 -08001486//
1487// <ele></ele>
1488// <ele>foo<b>bar</b></ele>
1489//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001490char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001491{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001492 // Read the element name.
1493 p = XMLUtil::SkipWhiteSpace( p );
1494 if ( !p ) {
1495 return 0;
1496 }
Lee Thomason67d61312012-01-24 16:01:51 -08001497
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001498 // The closing element is the </element> form. It is
1499 // parsed just like a regular element then deleted from
1500 // the DOM.
1501 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001502 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001503 ++p;
1504 }
Lee Thomason67d61312012-01-24 16:01:51 -08001505
Lee Thomason624d43f2012-10-12 10:58:48 -07001506 p = _value.ParseName( p );
1507 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001508 return 0;
1509 }
Lee Thomason67d61312012-01-24 16:01:51 -08001510
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001511 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001512 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001513 return p;
1514 }
Lee Thomason67d61312012-01-24 16:01:51 -08001515
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001516 p = XMLNode::ParseDeep( p, strPair );
1517 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001518}
1519
1520
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001521
1522XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1523{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001524 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001525 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001526 }
1527 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1528 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1529 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1530 }
1531 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001532}
1533
1534
1535bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1536{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001537 const XMLElement* other = compare->ToElement();
1538 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001539
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001540 const XMLAttribute* a=FirstAttribute();
1541 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001542
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001543 while ( a && b ) {
1544 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1545 return false;
1546 }
1547 a = a->Next();
1548 b = b->Next();
1549 }
1550 if ( a || b ) {
1551 // different count
1552 return false;
1553 }
1554 return true;
1555 }
1556 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001557}
1558
1559
Lee Thomason751da522012-02-10 08:50:51 -08001560bool XMLElement::Accept( XMLVisitor* visitor ) const
1561{
Lee Thomason624d43f2012-10-12 10:58:48 -07001562 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001563 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1564 if ( !node->Accept( visitor ) ) {
1565 break;
1566 }
1567 }
1568 }
1569 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001570}
Lee Thomason56bdd022012-02-09 18:16:58 -08001571
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001572
Lee Thomason3f57d272012-01-11 15:30:03 -08001573// --------- XMLDocument ----------- //
Lee Thomason624d43f2012-10-12 10:58:48 -07001574XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001575 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001576 _writeBOM( false ),
1577 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001578 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001579 _whitespace( whitespace ),
1580 _errorStr1( 0 ),
1581 _errorStr2( 0 ),
1582 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001583{
Lee Thomason624d43f2012-10-12 10:58:48 -07001584 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001585}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001586
1587
Lee Thomason3f57d272012-01-11 15:30:03 -08001588XMLDocument::~XMLDocument()
1589{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001590 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -07001591 delete [] _charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001592
Lee Thomason (grinliz)61cea672013-02-01 19:13:13 -08001593#if 0
Lee Thomason (grinliz)ac83b4e2013-02-01 09:02:34 -08001594 _textPool.Trace( "text" );
1595 _elementPool.Trace( "element" );
1596 _commentPool.Trace( "comment" );
1597 _attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -08001598#endif
1599
Lee Thomason5b0a6772012-11-19 13:54:42 -08001600#ifdef DEBUG
1601 if ( Error() == false ) {
1602 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1603 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1604 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1605 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1606 }
1607#endif
Lee Thomason3f57d272012-01-11 15:30:03 -08001608}
1609
1610
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001611void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001612{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001613 DeleteChildren();
1614
Lee Thomason624d43f2012-10-12 10:58:48 -07001615 _errorID = XML_NO_ERROR;
1616 _errorStr1 = 0;
1617 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001618
Lee Thomason624d43f2012-10-12 10:58:48 -07001619 delete [] _charBuffer;
1620 _charBuffer = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001621}
1622
Lee Thomason3f57d272012-01-11 15:30:03 -08001623
Lee Thomason2c85a712012-01-31 08:24:24 -08001624XMLElement* XMLDocument::NewElement( const char* name )
1625{
Lee Thomason624d43f2012-10-12 10:58:48 -07001626 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1627 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001628 ele->SetName( name );
1629 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001630}
1631
1632
Lee Thomason1ff38e02012-02-14 18:18:16 -08001633XMLComment* XMLDocument::NewComment( const char* str )
1634{
Lee Thomason624d43f2012-10-12 10:58:48 -07001635 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1636 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001637 comment->SetValue( str );
1638 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001639}
1640
1641
1642XMLText* XMLDocument::NewText( const char* str )
1643{
Lee Thomason624d43f2012-10-12 10:58:48 -07001644 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1645 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001646 text->SetValue( str );
1647 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001648}
1649
1650
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001651XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1652{
Lee Thomason624d43f2012-10-12 10:58:48 -07001653 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1654 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001655 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1656 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001657}
1658
1659
1660XMLUnknown* XMLDocument::NewUnknown( const char* str )
1661{
Lee Thomason624d43f2012-10-12 10:58:48 -07001662 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1663 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001664 unk->SetValue( str );
1665 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001666}
1667
Dmitry-Me01578db2014-08-19 10:18:48 +04001668static FILE* callfopen( const char* filepath, const char* mode )
1669{
1670#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1671 FILE* fp = 0;
1672 errno_t err = fopen_s( &fp, filepath, mode );
1673 if ( err ) {
1674 return 0;
1675 }
1676#else
1677 FILE* fp = fopen( filepath, mode );
1678#endif
1679 return fp;
1680}
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001681
Lee Thomason2fa81722012-11-09 12:37:46 -08001682XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001683{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001684 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001685 FILE* fp = callfopen( filename, "rb" );
1686 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001687 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001688 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001689 }
1690 LoadFile( fp );
1691 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001692 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001693}
1694
1695
Lee Thomason2fa81722012-11-09 12:37:46 -08001696XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001697{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001698 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001699
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001700 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001701 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001702 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1703 return _errorID;
1704 }
1705
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001706 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001707 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001708 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001709 if ( filelength == -1L ) {
1710 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1711 return _errorID;
1712 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001713
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001714 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001715 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001716 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001717 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001718 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001719
Lee Thomason624d43f2012-10-12 10:58:48 -07001720 _charBuffer = new char[size+1];
1721 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001722 if ( read != size ) {
1723 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001724 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001725 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001726
Lee Thomason624d43f2012-10-12 10:58:48 -07001727 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001728
Lee Thomason624d43f2012-10-12 10:58:48 -07001729 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001730 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001731 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001732 if ( !p || !*p ) {
1733 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001734 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001735 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001736
Lee Thomason624d43f2012-10-12 10:58:48 -07001737 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1738 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001739}
1740
1741
Lee Thomason2fa81722012-11-09 12:37:46 -08001742XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001743{
Dmitry-Me01578db2014-08-19 10:18:48 +04001744 FILE* fp = callfopen( filename, "w" );
1745 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001746 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001747 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001748 }
1749 SaveFile(fp, compact);
1750 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001751 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001752}
1753
1754
Lee Thomason2fa81722012-11-09 12:37:46 -08001755XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001756{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001757 XMLPrinter stream( fp, compact );
1758 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001759 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001760}
1761
Lee Thomason1ff38e02012-02-14 18:18:16 -08001762
Lee Thomason2fa81722012-11-09 12:37:46 -08001763XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001764{
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001765 const char* start = p;
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001766 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001767
Lee Thomason82d32002014-02-21 22:47:18 -08001768 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001769 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001770 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001771 }
1772 if ( len == (size_t)(-1) ) {
1773 len = strlen( p );
1774 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001775 _charBuffer = new char[ len+1 ];
1776 memcpy( _charBuffer, p, len );
1777 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001778
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001779 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001780 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001781 if ( !p || !*p ) {
1782 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001783 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001784 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001785
Thomas Roß1470edc2013-05-10 15:44:12 +02001786 ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001787 ParseDeep( _charBuffer+delta, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001788 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001789}
1790
1791
PKEuS1c5f99e2013-07-06 11:28:39 +02001792void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001793{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001794 XMLPrinter stdStreamer( stdout );
1795 if ( !streamer ) {
1796 streamer = &stdStreamer;
1797 }
1798 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001799}
1800
1801
Lee Thomason2fa81722012-11-09 12:37:46 -08001802void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001803{
Lee Thomason624d43f2012-10-12 10:58:48 -07001804 _errorID = error;
1805 _errorStr1 = str1;
1806 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001807}
1808
Lee Thomason5cae8972012-01-24 18:03:07 -08001809
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001810void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001811{
Lee Thomason624d43f2012-10-12 10:58:48 -07001812 if ( _errorID ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001813 static const int LEN = 20;
1814 char buf1[LEN] = { 0 };
1815 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001816
Lee Thomason624d43f2012-10-12 10:58:48 -07001817 if ( _errorStr1 ) {
1818 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001819 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001820 if ( _errorStr2 ) {
1821 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001822 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001823
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001824 printf( "XMLDocument error id=%d str1=%s str2=%s\n",
Lee Thomason624d43f2012-10-12 10:58:48 -07001825 _errorID, buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001826 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001827}
1828
1829
PKEuS1bfb9542013-08-04 13:51:17 +02001830XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001831 _elementJustOpened( false ),
1832 _firstElement( true ),
1833 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001834 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001835 _textDepth( -1 ),
1836 _processEntities( true ),
1837 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001838{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001839 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001840 _entityFlag[i] = false;
1841 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001842 }
1843 for( int i=0; i<NUM_ENTITIES; ++i ) {
1844 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1845 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001846 _entityFlag[ (int)entities[i].value ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001847 }
1848 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001849 _restrictedEntityFlag[(int)'&'] = true;
1850 _restrictedEntityFlag[(int)'<'] = true;
1851 _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
1852 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001853}
1854
1855
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001856void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001857{
1858 va_list va;
1859 va_start( va, format );
1860
Lee Thomason624d43f2012-10-12 10:58:48 -07001861 if ( _fp ) {
1862 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001863 }
1864 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001865#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001866 #if defined(WINCE)
1867 int len = 512;
1868 do {
1869 len = len*2;
1870 char* str = new char[len]();
1871 len = _vsnprintf(str, len, format, va);
1872 delete[] str;
1873 }while (len < 0);
1874 #else
Thomas Roß268c6832014-03-13 23:35:16 +01001875 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08001876 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001877#else
1878 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01001879#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001880 // Close out and re-start the va-args
1881 va_end( va );
1882 va_start( va, format );
Lee Thomasona0744c82014-03-16 10:32:27 -07001883 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
1884#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001885 #if defined(WINCE)
1886 _vsnprintf( p, len+1, format, va );
1887 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07001888 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08001889 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07001890#else
1891 vsnprintf( p, len+1, format, va );
1892#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001893 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001894 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001895}
1896
1897
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001898void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001899{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001900 for( int i=0; i<depth; ++i ) {
1901 Print( " " );
1902 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001903}
1904
1905
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001906void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001907{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001908 // Look for runs of bytes between entities to print.
1909 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001910 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001911
Lee Thomason624d43f2012-10-12 10:58:48 -07001912 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001913 while ( *q ) {
1914 // Remember, char is sometimes signed. (How many times has that bitten me?)
1915 if ( *q > 0 && *q < ENTITY_RANGE ) {
1916 // Check for entities. If one is found, flush
1917 // the stream up until the entity, write the
1918 // entity, and keep looking.
1919 if ( flag[(unsigned)(*q)] ) {
1920 while ( p < q ) {
1921 Print( "%c", *p );
1922 ++p;
1923 }
1924 for( int i=0; i<NUM_ENTITIES; ++i ) {
1925 if ( entities[i].value == *q ) {
1926 Print( "&%s;", entities[i].pattern );
1927 break;
1928 }
1929 }
1930 ++p;
1931 }
1932 }
1933 ++q;
1934 }
1935 }
1936 // Flush the remaining string. This will be the entire
1937 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07001938 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001939 Print( "%s", p );
1940 }
Lee Thomason857b8682012-01-25 17:50:25 -08001941}
1942
U-Stream\Leeae25a442012-02-17 17:48:16 -08001943
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001944void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001945{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001946 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02001947 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 -07001948 Print( "%s", bom );
1949 }
1950 if ( writeDec ) {
1951 PushDeclaration( "xml version=\"1.0\"" );
1952 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001953}
1954
1955
Uli Kusterer593a33d2014-02-01 12:48:51 +01001956void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08001957{
Lee Thomason624d43f2012-10-12 10:58:48 -07001958 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001959 SealElement();
1960 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001961 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08001962
Uli Kusterer593a33d2014-02-01 12:48:51 +01001963 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001964 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02001965 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01001966 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001967 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001968 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001969
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001970 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07001971 _elementJustOpened = true;
1972 _firstElement = false;
1973 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08001974}
1975
1976
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001977void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08001978{
Lee Thomason624d43f2012-10-12 10:58:48 -07001979 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001980 Print( " %s=\"", name );
1981 PrintString( value, false );
1982 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001983}
1984
1985
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001986void XMLPrinter::PushAttribute( const char* name, int v )
1987{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001988 char buf[BUF_SIZE];
1989 XMLUtil::ToStr( v, buf, BUF_SIZE );
1990 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001991}
1992
1993
1994void XMLPrinter::PushAttribute( const char* name, unsigned v )
1995{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001996 char buf[BUF_SIZE];
1997 XMLUtil::ToStr( v, buf, BUF_SIZE );
1998 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001999}
2000
2001
2002void XMLPrinter::PushAttribute( const char* name, bool v )
2003{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002004 char buf[BUF_SIZE];
2005 XMLUtil::ToStr( v, buf, BUF_SIZE );
2006 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002007}
2008
2009
2010void XMLPrinter::PushAttribute( const char* name, double v )
2011{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002012 char buf[BUF_SIZE];
2013 XMLUtil::ToStr( v, buf, BUF_SIZE );
2014 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002015}
2016
2017
Uli Kustererca412e82014-02-01 13:35:05 +01002018void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002019{
Lee Thomason624d43f2012-10-12 10:58:48 -07002020 --_depth;
2021 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002022
Lee Thomason624d43f2012-10-12 10:58:48 -07002023 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002024 Print( "/>" );
2025 }
2026 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002027 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002028 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002029 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002030 }
2031 Print( "</%s>", name );
2032 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002033
Lee Thomason624d43f2012-10-12 10:58:48 -07002034 if ( _textDepth == _depth ) {
2035 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002036 }
Uli Kustererca412e82014-02-01 13:35:05 +01002037 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002038 Print( "\n" );
2039 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002040 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002041}
2042
2043
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002044void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08002045{
Lee Thomason624d43f2012-10-12 10:58:48 -07002046 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002047 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002048}
2049
2050
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002051void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002052{
Lee Thomason624d43f2012-10-12 10:58:48 -07002053 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002054
Lee Thomason624d43f2012-10-12 10:58:48 -07002055 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002056 SealElement();
2057 }
2058 if ( cdata ) {
2059 Print( "<![CDATA[" );
2060 Print( "%s", text );
2061 Print( "]]>" );
2062 }
2063 else {
2064 PrintString( text, true );
2065 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002066}
2067
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002068void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002069{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002070 char buf[BUF_SIZE];
2071 XMLUtil::ToStr( value, buf, BUF_SIZE );
2072 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002073}
2074
2075
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002076void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002077{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002078 char buf[BUF_SIZE];
2079 XMLUtil::ToStr( value, buf, BUF_SIZE );
2080 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002081}
2082
2083
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002084void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002085{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002086 char buf[BUF_SIZE];
2087 XMLUtil::ToStr( value, buf, BUF_SIZE );
2088 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002089}
2090
2091
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002092void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002093{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002094 char buf[BUF_SIZE];
2095 XMLUtil::ToStr( value, buf, BUF_SIZE );
2096 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002097}
2098
2099
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002100void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002101{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002102 char buf[BUF_SIZE];
2103 XMLUtil::ToStr( value, buf, BUF_SIZE );
2104 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002105}
2106
Lee Thomason5cae8972012-01-24 18:03:07 -08002107
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002108void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002109{
Lee Thomason624d43f2012-10-12 10:58:48 -07002110 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002111 SealElement();
2112 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002113 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002114 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002115 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002116 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002117 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002118 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002119}
Lee Thomason751da522012-02-10 08:50:51 -08002120
2121
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002122void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002123{
Lee Thomason624d43f2012-10-12 10:58:48 -07002124 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002125 SealElement();
2126 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002127 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002128 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002129 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002130 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002131 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002132 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002133}
2134
2135
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002136void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002137{
Lee Thomason624d43f2012-10-12 10:58:48 -07002138 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002139 SealElement();
2140 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002141 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002142 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002143 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002144 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002145 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002146 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002147}
2148
2149
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002150bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002151{
Lee Thomason624d43f2012-10-12 10:58:48 -07002152 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002153 if ( doc.HasBOM() ) {
2154 PushHeader( true, false );
2155 }
2156 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002157}
2158
2159
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002160bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002161{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002162 const XMLElement* parentElem = element.Parent()->ToElement();
2163 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2164 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002165 while ( attribute ) {
2166 PushAttribute( attribute->Name(), attribute->Value() );
2167 attribute = attribute->Next();
2168 }
2169 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002170}
2171
2172
Uli Kustererca412e82014-02-01 13:35:05 +01002173bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002174{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002175 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002176 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002177}
2178
2179
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002180bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002181{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002182 PushText( text.Value(), text.CData() );
2183 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002184}
2185
2186
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002187bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002188{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002189 PushComment( comment.Value() );
2190 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002191}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002192
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002193bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002194{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002195 PushDeclaration( declaration.Value() );
2196 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002197}
2198
2199
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002200bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002201{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002202 PushUnknown( unknown.Value() );
2203 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002204}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002205
Lee Thomason685b8952012-11-12 13:00:06 -08002206} // namespace tinyxml2
2207