rev |
line source |
nuclear@19
|
1 /*
|
nuclear@19
|
2 Original code by Lee Thomason (www.grinninglizard.com)
|
nuclear@19
|
3
|
nuclear@19
|
4 This software is provided 'as-is', without any express or implied
|
nuclear@19
|
5 warranty. In no event will the authors be held liable for any
|
nuclear@19
|
6 damages arising from the use of this software.
|
nuclear@19
|
7
|
nuclear@19
|
8 Permission is granted to anyone to use this software for any
|
nuclear@19
|
9 purpose, including commercial applications, and to alter it and
|
nuclear@19
|
10 redistribute it freely, subject to the following restrictions:
|
nuclear@19
|
11
|
nuclear@19
|
12 1. The origin of this software must not be misrepresented; you must
|
nuclear@19
|
13 not claim that you wrote the original software. If you use this
|
nuclear@19
|
14 software in a product, an acknowledgment in the product documentation
|
nuclear@19
|
15 would be appreciated but is not required.
|
nuclear@19
|
16
|
nuclear@19
|
17 2. Altered source versions must be plainly marked as such, and
|
nuclear@19
|
18 must not be misrepresented as being the original software.
|
nuclear@19
|
19
|
nuclear@19
|
20 3. This notice may not be removed or altered from any source
|
nuclear@19
|
21 distribution.
|
nuclear@19
|
22 */
|
nuclear@19
|
23
|
nuclear@19
|
24 #include "tinyxml2.h"
|
nuclear@19
|
25
|
nuclear@19
|
26 #include <new> // yes, this one new style header, is in the Android SDK.
|
nuclear@19
|
27 # ifdef ANDROID_NDK
|
nuclear@19
|
28 # include <stddef.h>
|
nuclear@19
|
29 #else
|
nuclear@19
|
30 # include <cstddef>
|
nuclear@19
|
31 #endif
|
nuclear@19
|
32
|
nuclear@19
|
33 static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
|
nuclear@19
|
34 static const char LF = LINE_FEED;
|
nuclear@19
|
35 static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
|
nuclear@19
|
36 static const char CR = CARRIAGE_RETURN;
|
nuclear@19
|
37 static const char SINGLE_QUOTE = '\'';
|
nuclear@19
|
38 static const char DOUBLE_QUOTE = '\"';
|
nuclear@19
|
39
|
nuclear@19
|
40 // Bunch of unicode info at:
|
nuclear@19
|
41 // http://www.unicode.org/faq/utf_bom.html
|
nuclear@19
|
42 // ef bb bf (Microsoft "lead bytes") - designates UTF-8
|
nuclear@19
|
43
|
nuclear@19
|
44 static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
|
nuclear@19
|
45 static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
|
nuclear@19
|
46 static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
|
nuclear@19
|
47
|
nuclear@19
|
48
|
nuclear@19
|
49 #define DELETE_NODE( node ) { \
|
nuclear@19
|
50 if ( node ) { \
|
nuclear@19
|
51 MemPool* pool = node->_memPool; \
|
nuclear@19
|
52 node->~XMLNode(); \
|
nuclear@19
|
53 pool->Free( node ); \
|
nuclear@19
|
54 } \
|
nuclear@19
|
55 }
|
nuclear@19
|
56 #define DELETE_ATTRIBUTE( attrib ) { \
|
nuclear@19
|
57 if ( attrib ) { \
|
nuclear@19
|
58 MemPool* pool = attrib->_memPool; \
|
nuclear@19
|
59 attrib->~XMLAttribute(); \
|
nuclear@19
|
60 pool->Free( attrib ); \
|
nuclear@19
|
61 } \
|
nuclear@19
|
62 }
|
nuclear@19
|
63
|
nuclear@19
|
64 namespace tinyxml2
|
nuclear@19
|
65 {
|
nuclear@19
|
66
|
nuclear@19
|
67 struct Entity {
|
nuclear@19
|
68 const char* pattern;
|
nuclear@19
|
69 int length;
|
nuclear@19
|
70 char value;
|
nuclear@19
|
71 };
|
nuclear@19
|
72
|
nuclear@19
|
73 static const int NUM_ENTITIES = 5;
|
nuclear@19
|
74 static const Entity entities[NUM_ENTITIES] = {
|
nuclear@19
|
75 { "quot", 4, DOUBLE_QUOTE },
|
nuclear@19
|
76 { "amp", 3, '&' },
|
nuclear@19
|
77 { "apos", 4, SINGLE_QUOTE },
|
nuclear@19
|
78 { "lt", 2, '<' },
|
nuclear@19
|
79 { "gt", 2, '>' }
|
nuclear@19
|
80 };
|
nuclear@19
|
81
|
nuclear@19
|
82
|
nuclear@19
|
83 StrPair::~StrPair()
|
nuclear@19
|
84 {
|
nuclear@19
|
85 Reset();
|
nuclear@19
|
86 }
|
nuclear@19
|
87
|
nuclear@19
|
88
|
nuclear@19
|
89 void StrPair::Reset()
|
nuclear@19
|
90 {
|
nuclear@19
|
91 if ( _flags & NEEDS_DELETE ) {
|
nuclear@19
|
92 delete [] _start;
|
nuclear@19
|
93 }
|
nuclear@19
|
94 _flags = 0;
|
nuclear@19
|
95 _start = 0;
|
nuclear@19
|
96 _end = 0;
|
nuclear@19
|
97 }
|
nuclear@19
|
98
|
nuclear@19
|
99
|
nuclear@19
|
100 void StrPair::SetStr( const char* str, int flags )
|
nuclear@19
|
101 {
|
nuclear@19
|
102 Reset();
|
nuclear@19
|
103 size_t len = strlen( str );
|
nuclear@19
|
104 _start = new char[ len+1 ];
|
nuclear@19
|
105 memcpy( _start, str, len+1 );
|
nuclear@19
|
106 _end = _start + len;
|
nuclear@19
|
107 _flags = flags | NEEDS_DELETE;
|
nuclear@19
|
108 }
|
nuclear@19
|
109
|
nuclear@19
|
110
|
nuclear@19
|
111 char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
|
nuclear@19
|
112 {
|
nuclear@19
|
113 TIXMLASSERT( endTag && *endTag );
|
nuclear@19
|
114
|
nuclear@19
|
115 char* start = p; // fixme: hides a member
|
nuclear@19
|
116 char endChar = *endTag;
|
nuclear@19
|
117 size_t length = strlen( endTag );
|
nuclear@19
|
118
|
nuclear@19
|
119 // Inner loop of text parsing.
|
nuclear@19
|
120 while ( *p ) {
|
nuclear@19
|
121 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
|
nuclear@19
|
122 Set( start, p, strFlags );
|
nuclear@19
|
123 return p + length;
|
nuclear@19
|
124 }
|
nuclear@19
|
125 ++p;
|
nuclear@19
|
126 }
|
nuclear@19
|
127 return 0;
|
nuclear@19
|
128 }
|
nuclear@19
|
129
|
nuclear@19
|
130
|
nuclear@19
|
131 char* StrPair::ParseName( char* p )
|
nuclear@19
|
132 {
|
nuclear@19
|
133 char* start = p;
|
nuclear@19
|
134
|
nuclear@19
|
135 if ( !start || !(*start) ) {
|
nuclear@19
|
136 return 0;
|
nuclear@19
|
137 }
|
nuclear@19
|
138
|
nuclear@19
|
139 while( *p && ( p == start ? XMLUtil::IsNameStartChar( *p ) : XMLUtil::IsNameChar( *p ) )) {
|
nuclear@19
|
140 ++p;
|
nuclear@19
|
141 }
|
nuclear@19
|
142
|
nuclear@19
|
143 if ( p > start ) {
|
nuclear@19
|
144 Set( start, p, 0 );
|
nuclear@19
|
145 return p;
|
nuclear@19
|
146 }
|
nuclear@19
|
147 return 0;
|
nuclear@19
|
148 }
|
nuclear@19
|
149
|
nuclear@19
|
150
|
nuclear@19
|
151 void StrPair::CollapseWhitespace()
|
nuclear@19
|
152 {
|
nuclear@19
|
153 // Trim leading space.
|
nuclear@19
|
154 _start = XMLUtil::SkipWhiteSpace( _start );
|
nuclear@19
|
155
|
nuclear@19
|
156 if ( _start && *_start ) {
|
nuclear@19
|
157 char* p = _start; // the read pointer
|
nuclear@19
|
158 char* q = _start; // the write pointer
|
nuclear@19
|
159
|
nuclear@19
|
160 while( *p ) {
|
nuclear@19
|
161 if ( XMLUtil::IsWhiteSpace( *p )) {
|
nuclear@19
|
162 p = XMLUtil::SkipWhiteSpace( p );
|
nuclear@19
|
163 if ( *p == 0 ) {
|
nuclear@19
|
164 break; // don't write to q; this trims the trailing space.
|
nuclear@19
|
165 }
|
nuclear@19
|
166 *q = ' ';
|
nuclear@19
|
167 ++q;
|
nuclear@19
|
168 }
|
nuclear@19
|
169 *q = *p;
|
nuclear@19
|
170 ++q;
|
nuclear@19
|
171 ++p;
|
nuclear@19
|
172 }
|
nuclear@19
|
173 *q = 0;
|
nuclear@19
|
174 }
|
nuclear@19
|
175 }
|
nuclear@19
|
176
|
nuclear@19
|
177
|
nuclear@19
|
178 const char* StrPair::GetStr()
|
nuclear@19
|
179 {
|
nuclear@19
|
180 if ( _flags & NEEDS_FLUSH ) {
|
nuclear@19
|
181 *_end = 0;
|
nuclear@19
|
182 _flags ^= NEEDS_FLUSH;
|
nuclear@19
|
183
|
nuclear@19
|
184 if ( _flags ) {
|
nuclear@19
|
185 char* p = _start; // the read pointer
|
nuclear@19
|
186 char* q = _start; // the write pointer
|
nuclear@19
|
187
|
nuclear@19
|
188 while( p < _end ) {
|
nuclear@19
|
189 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
|
nuclear@19
|
190 // CR-LF pair becomes LF
|
nuclear@19
|
191 // CR alone becomes LF
|
nuclear@19
|
192 // LF-CR becomes LF
|
nuclear@19
|
193 if ( *(p+1) == LF ) {
|
nuclear@19
|
194 p += 2;
|
nuclear@19
|
195 }
|
nuclear@19
|
196 else {
|
nuclear@19
|
197 ++p;
|
nuclear@19
|
198 }
|
nuclear@19
|
199 *q++ = LF;
|
nuclear@19
|
200 }
|
nuclear@19
|
201 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
|
nuclear@19
|
202 if ( *(p+1) == CR ) {
|
nuclear@19
|
203 p += 2;
|
nuclear@19
|
204 }
|
nuclear@19
|
205 else {
|
nuclear@19
|
206 ++p;
|
nuclear@19
|
207 }
|
nuclear@19
|
208 *q++ = LF;
|
nuclear@19
|
209 }
|
nuclear@19
|
210 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
|
nuclear@19
|
211 // Entities handled by tinyXML2:
|
nuclear@19
|
212 // - special entities in the entity table [in/out]
|
nuclear@19
|
213 // - numeric character reference [in]
|
nuclear@19
|
214 // 中 or 中
|
nuclear@19
|
215
|
nuclear@19
|
216 if ( *(p+1) == '#' ) {
|
nuclear@19
|
217 char buf[10] = { 0 };
|
nuclear@19
|
218 int len;
|
nuclear@19
|
219 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
|
nuclear@19
|
220 for( int i=0; i<len; ++i ) {
|
nuclear@19
|
221 *q++ = buf[i];
|
nuclear@19
|
222 }
|
nuclear@19
|
223 TIXMLASSERT( q <= p );
|
nuclear@19
|
224 }
|
nuclear@19
|
225 else {
|
nuclear@19
|
226 int i=0;
|
nuclear@19
|
227 for(; i<NUM_ENTITIES; ++i ) {
|
nuclear@19
|
228 if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
|
nuclear@19
|
229 && *(p+entities[i].length+1) == ';' ) {
|
nuclear@19
|
230 // Found an entity convert;
|
nuclear@19
|
231 *q = entities[i].value;
|
nuclear@19
|
232 ++q;
|
nuclear@19
|
233 p += entities[i].length + 2;
|
nuclear@19
|
234 break;
|
nuclear@19
|
235 }
|
nuclear@19
|
236 }
|
nuclear@19
|
237 if ( i == NUM_ENTITIES ) {
|
nuclear@19
|
238 // fixme: treat as error?
|
nuclear@19
|
239 ++p;
|
nuclear@19
|
240 ++q;
|
nuclear@19
|
241 }
|
nuclear@19
|
242 }
|
nuclear@19
|
243 }
|
nuclear@19
|
244 else {
|
nuclear@19
|
245 *q = *p;
|
nuclear@19
|
246 ++p;
|
nuclear@19
|
247 ++q;
|
nuclear@19
|
248 }
|
nuclear@19
|
249 }
|
nuclear@19
|
250 *q = 0;
|
nuclear@19
|
251 }
|
nuclear@19
|
252 // The loop below has plenty going on, and this
|
nuclear@19
|
253 // is a less useful mode. Break it out.
|
nuclear@19
|
254 if ( _flags & COLLAPSE_WHITESPACE ) {
|
nuclear@19
|
255 CollapseWhitespace();
|
nuclear@19
|
256 }
|
nuclear@19
|
257 _flags = (_flags & NEEDS_DELETE);
|
nuclear@19
|
258 }
|
nuclear@19
|
259 return _start;
|
nuclear@19
|
260 }
|
nuclear@19
|
261
|
nuclear@19
|
262
|
nuclear@19
|
263
|
nuclear@19
|
264
|
nuclear@19
|
265 // --------- XMLUtil ----------- //
|
nuclear@19
|
266
|
nuclear@19
|
267 const char* XMLUtil::ReadBOM( const char* p, bool* bom )
|
nuclear@19
|
268 {
|
nuclear@19
|
269 *bom = false;
|
nuclear@19
|
270 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
|
nuclear@19
|
271 // Check for BOM:
|
nuclear@19
|
272 if ( *(pu+0) == TIXML_UTF_LEAD_0
|
nuclear@19
|
273 && *(pu+1) == TIXML_UTF_LEAD_1
|
nuclear@19
|
274 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
|
nuclear@19
|
275 *bom = true;
|
nuclear@19
|
276 p += 3;
|
nuclear@19
|
277 }
|
nuclear@19
|
278 return p;
|
nuclear@19
|
279 }
|
nuclear@19
|
280
|
nuclear@19
|
281
|
nuclear@19
|
282 void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
|
nuclear@19
|
283 {
|
nuclear@19
|
284 const unsigned long BYTE_MASK = 0xBF;
|
nuclear@19
|
285 const unsigned long BYTE_MARK = 0x80;
|
nuclear@19
|
286 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
|
nuclear@19
|
287
|
nuclear@19
|
288 if (input < 0x80) {
|
nuclear@19
|
289 *length = 1;
|
nuclear@19
|
290 }
|
nuclear@19
|
291 else if ( input < 0x800 ) {
|
nuclear@19
|
292 *length = 2;
|
nuclear@19
|
293 }
|
nuclear@19
|
294 else if ( input < 0x10000 ) {
|
nuclear@19
|
295 *length = 3;
|
nuclear@19
|
296 }
|
nuclear@19
|
297 else if ( input < 0x200000 ) {
|
nuclear@19
|
298 *length = 4;
|
nuclear@19
|
299 }
|
nuclear@19
|
300 else {
|
nuclear@19
|
301 *length = 0; // This code won't covert this correctly anyway.
|
nuclear@19
|
302 return;
|
nuclear@19
|
303 }
|
nuclear@19
|
304
|
nuclear@19
|
305 output += *length;
|
nuclear@19
|
306
|
nuclear@19
|
307 // Scary scary fall throughs.
|
nuclear@19
|
308 switch (*length) {
|
nuclear@19
|
309 case 4:
|
nuclear@19
|
310 --output;
|
nuclear@19
|
311 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
|
nuclear@19
|
312 input >>= 6;
|
nuclear@19
|
313 case 3:
|
nuclear@19
|
314 --output;
|
nuclear@19
|
315 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
|
nuclear@19
|
316 input >>= 6;
|
nuclear@19
|
317 case 2:
|
nuclear@19
|
318 --output;
|
nuclear@19
|
319 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
|
nuclear@19
|
320 input >>= 6;
|
nuclear@19
|
321 case 1:
|
nuclear@19
|
322 --output;
|
nuclear@19
|
323 *output = (char)(input | FIRST_BYTE_MARK[*length]);
|
nuclear@19
|
324 default:
|
nuclear@19
|
325 break;
|
nuclear@19
|
326 }
|
nuclear@19
|
327 }
|
nuclear@19
|
328
|
nuclear@19
|
329
|
nuclear@19
|
330 const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
|
nuclear@19
|
331 {
|
nuclear@19
|
332 // Presume an entity, and pull it out.
|
nuclear@19
|
333 *length = 0;
|
nuclear@19
|
334
|
nuclear@19
|
335 if ( *(p+1) == '#' && *(p+2) ) {
|
nuclear@19
|
336 unsigned long ucs = 0;
|
nuclear@19
|
337 ptrdiff_t delta = 0;
|
nuclear@19
|
338 unsigned mult = 1;
|
nuclear@19
|
339
|
nuclear@19
|
340 if ( *(p+2) == 'x' ) {
|
nuclear@19
|
341 // Hexadecimal.
|
nuclear@19
|
342 if ( !*(p+3) ) {
|
nuclear@19
|
343 return 0;
|
nuclear@19
|
344 }
|
nuclear@19
|
345
|
nuclear@19
|
346 const char* q = p+3;
|
nuclear@19
|
347 q = strchr( q, ';' );
|
nuclear@19
|
348
|
nuclear@19
|
349 if ( !q || !*q ) {
|
nuclear@19
|
350 return 0;
|
nuclear@19
|
351 }
|
nuclear@19
|
352
|
nuclear@19
|
353 delta = q-p;
|
nuclear@19
|
354 --q;
|
nuclear@19
|
355
|
nuclear@19
|
356 while ( *q != 'x' ) {
|
nuclear@19
|
357 if ( *q >= '0' && *q <= '9' ) {
|
nuclear@19
|
358 ucs += mult * (*q - '0');
|
nuclear@19
|
359 }
|
nuclear@19
|
360 else if ( *q >= 'a' && *q <= 'f' ) {
|
nuclear@19
|
361 ucs += mult * (*q - 'a' + 10);
|
nuclear@19
|
362 }
|
nuclear@19
|
363 else if ( *q >= 'A' && *q <= 'F' ) {
|
nuclear@19
|
364 ucs += mult * (*q - 'A' + 10 );
|
nuclear@19
|
365 }
|
nuclear@19
|
366 else {
|
nuclear@19
|
367 return 0;
|
nuclear@19
|
368 }
|
nuclear@19
|
369 mult *= 16;
|
nuclear@19
|
370 --q;
|
nuclear@19
|
371 }
|
nuclear@19
|
372 }
|
nuclear@19
|
373 else {
|
nuclear@19
|
374 // Decimal.
|
nuclear@19
|
375 if ( !*(p+2) ) {
|
nuclear@19
|
376 return 0;
|
nuclear@19
|
377 }
|
nuclear@19
|
378
|
nuclear@19
|
379 const char* q = p+2;
|
nuclear@19
|
380 q = strchr( q, ';' );
|
nuclear@19
|
381
|
nuclear@19
|
382 if ( !q || !*q ) {
|
nuclear@19
|
383 return 0;
|
nuclear@19
|
384 }
|
nuclear@19
|
385
|
nuclear@19
|
386 delta = q-p;
|
nuclear@19
|
387 --q;
|
nuclear@19
|
388
|
nuclear@19
|
389 while ( *q != '#' ) {
|
nuclear@19
|
390 if ( *q >= '0' && *q <= '9' ) {
|
nuclear@19
|
391 ucs += mult * (*q - '0');
|
nuclear@19
|
392 }
|
nuclear@19
|
393 else {
|
nuclear@19
|
394 return 0;
|
nuclear@19
|
395 }
|
nuclear@19
|
396 mult *= 10;
|
nuclear@19
|
397 --q;
|
nuclear@19
|
398 }
|
nuclear@19
|
399 }
|
nuclear@19
|
400 // convert the UCS to UTF-8
|
nuclear@19
|
401 ConvertUTF32ToUTF8( ucs, value, length );
|
nuclear@19
|
402 return p + delta + 1;
|
nuclear@19
|
403 }
|
nuclear@19
|
404 return p+1;
|
nuclear@19
|
405 }
|
nuclear@19
|
406
|
nuclear@19
|
407
|
nuclear@19
|
408 void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
|
nuclear@19
|
409 {
|
nuclear@19
|
410 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
|
nuclear@19
|
411 }
|
nuclear@19
|
412
|
nuclear@19
|
413
|
nuclear@19
|
414 void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
|
nuclear@19
|
415 {
|
nuclear@19
|
416 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
|
nuclear@19
|
417 }
|
nuclear@19
|
418
|
nuclear@19
|
419
|
nuclear@19
|
420 void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
|
nuclear@19
|
421 {
|
nuclear@19
|
422 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
|
nuclear@19
|
423 }
|
nuclear@19
|
424
|
nuclear@19
|
425
|
nuclear@19
|
426 void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
|
nuclear@19
|
427 {
|
nuclear@19
|
428 TIXML_SNPRINTF( buffer, bufferSize, "%f", v );
|
nuclear@19
|
429 }
|
nuclear@19
|
430
|
nuclear@19
|
431
|
nuclear@19
|
432 void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
|
nuclear@19
|
433 {
|
nuclear@19
|
434 TIXML_SNPRINTF( buffer, bufferSize, "%f", v );
|
nuclear@19
|
435 }
|
nuclear@19
|
436
|
nuclear@19
|
437
|
nuclear@19
|
438 bool XMLUtil::ToInt( const char* str, int* value )
|
nuclear@19
|
439 {
|
nuclear@19
|
440 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
|
nuclear@19
|
441 return true;
|
nuclear@19
|
442 }
|
nuclear@19
|
443 return false;
|
nuclear@19
|
444 }
|
nuclear@19
|
445
|
nuclear@19
|
446 bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
|
nuclear@19
|
447 {
|
nuclear@19
|
448 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
|
nuclear@19
|
449 return true;
|
nuclear@19
|
450 }
|
nuclear@19
|
451 return false;
|
nuclear@19
|
452 }
|
nuclear@19
|
453
|
nuclear@19
|
454 bool XMLUtil::ToBool( const char* str, bool* value )
|
nuclear@19
|
455 {
|
nuclear@19
|
456 int ival = 0;
|
nuclear@19
|
457 if ( ToInt( str, &ival )) {
|
nuclear@19
|
458 *value = (ival==0) ? false : true;
|
nuclear@19
|
459 return true;
|
nuclear@19
|
460 }
|
nuclear@19
|
461 if ( StringEqual( str, "true" ) ) {
|
nuclear@19
|
462 *value = true;
|
nuclear@19
|
463 return true;
|
nuclear@19
|
464 }
|
nuclear@19
|
465 else if ( StringEqual( str, "false" ) ) {
|
nuclear@19
|
466 *value = false;
|
nuclear@19
|
467 return true;
|
nuclear@19
|
468 }
|
nuclear@19
|
469 return false;
|
nuclear@19
|
470 }
|
nuclear@19
|
471
|
nuclear@19
|
472
|
nuclear@19
|
473 bool XMLUtil::ToFloat( const char* str, float* value )
|
nuclear@19
|
474 {
|
nuclear@19
|
475 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
|
nuclear@19
|
476 return true;
|
nuclear@19
|
477 }
|
nuclear@19
|
478 return false;
|
nuclear@19
|
479 }
|
nuclear@19
|
480
|
nuclear@19
|
481 bool XMLUtil::ToDouble( const char* str, double* value )
|
nuclear@19
|
482 {
|
nuclear@19
|
483 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
|
nuclear@19
|
484 return true;
|
nuclear@19
|
485 }
|
nuclear@19
|
486 return false;
|
nuclear@19
|
487 }
|
nuclear@19
|
488
|
nuclear@19
|
489
|
nuclear@19
|
490 char* XMLDocument::Identify( char* p, XMLNode** node )
|
nuclear@19
|
491 {
|
nuclear@19
|
492 XMLNode* returnNode = 0;
|
nuclear@19
|
493 char* start = p;
|
nuclear@19
|
494 p = XMLUtil::SkipWhiteSpace( p );
|
nuclear@19
|
495 if( !p || !*p ) {
|
nuclear@19
|
496 return p;
|
nuclear@19
|
497 }
|
nuclear@19
|
498
|
nuclear@19
|
499 // What is this thing?
|
nuclear@19
|
500 // - Elements start with a letter or underscore, but xml is reserved.
|
nuclear@19
|
501 // - Comments: <!--
|
nuclear@19
|
502 // - Declaration: <?
|
nuclear@19
|
503 // - Everything else is unknown to tinyxml.
|
nuclear@19
|
504 //
|
nuclear@19
|
505
|
nuclear@19
|
506 static const char* xmlHeader = { "<?" };
|
nuclear@19
|
507 static const char* commentHeader = { "<!--" };
|
nuclear@19
|
508 static const char* dtdHeader = { "<!" };
|
nuclear@19
|
509 static const char* cdataHeader = { "<![CDATA[" };
|
nuclear@19
|
510 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
|
nuclear@19
|
511
|
nuclear@19
|
512 static const int xmlHeaderLen = 2;
|
nuclear@19
|
513 static const int commentHeaderLen = 4;
|
nuclear@19
|
514 static const int dtdHeaderLen = 2;
|
nuclear@19
|
515 static const int cdataHeaderLen = 9;
|
nuclear@19
|
516 static const int elementHeaderLen = 1;
|
nuclear@19
|
517
|
nuclear@19
|
518 #if defined(_MSC_VER)
|
nuclear@19
|
519 #pragma warning ( push )
|
nuclear@19
|
520 #pragma warning ( disable : 4127 )
|
nuclear@19
|
521 #endif
|
nuclear@19
|
522 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
|
nuclear@19
|
523 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
|
nuclear@19
|
524 #if defined(_MSC_VER)
|
nuclear@19
|
525 #pragma warning (pop)
|
nuclear@19
|
526 #endif
|
nuclear@19
|
527 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
|
nuclear@19
|
528 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
|
nuclear@19
|
529 returnNode->_memPool = &_commentPool;
|
nuclear@19
|
530 p += xmlHeaderLen;
|
nuclear@19
|
531 }
|
nuclear@19
|
532 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
|
nuclear@19
|
533 returnNode = new (_commentPool.Alloc()) XMLComment( this );
|
nuclear@19
|
534 returnNode->_memPool = &_commentPool;
|
nuclear@19
|
535 p += commentHeaderLen;
|
nuclear@19
|
536 }
|
nuclear@19
|
537 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
|
nuclear@19
|
538 XMLText* text = new (_textPool.Alloc()) XMLText( this );
|
nuclear@19
|
539 returnNode = text;
|
nuclear@19
|
540 returnNode->_memPool = &_textPool;
|
nuclear@19
|
541 p += cdataHeaderLen;
|
nuclear@19
|
542 text->SetCData( true );
|
nuclear@19
|
543 }
|
nuclear@19
|
544 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
|
nuclear@19
|
545 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
|
nuclear@19
|
546 returnNode->_memPool = &_commentPool;
|
nuclear@19
|
547 p += dtdHeaderLen;
|
nuclear@19
|
548 }
|
nuclear@19
|
549 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
|
nuclear@19
|
550 returnNode = new (_elementPool.Alloc()) XMLElement( this );
|
nuclear@19
|
551 returnNode->_memPool = &_elementPool;
|
nuclear@19
|
552 p += elementHeaderLen;
|
nuclear@19
|
553 }
|
nuclear@19
|
554 else {
|
nuclear@19
|
555 returnNode = new (_textPool.Alloc()) XMLText( this );
|
nuclear@19
|
556 returnNode->_memPool = &_textPool;
|
nuclear@19
|
557 p = start; // Back it up, all the text counts.
|
nuclear@19
|
558 }
|
nuclear@19
|
559
|
nuclear@19
|
560 *node = returnNode;
|
nuclear@19
|
561 return p;
|
nuclear@19
|
562 }
|
nuclear@19
|
563
|
nuclear@19
|
564
|
nuclear@19
|
565 bool XMLDocument::Accept( XMLVisitor* visitor ) const
|
nuclear@19
|
566 {
|
nuclear@19
|
567 if ( visitor->VisitEnter( *this ) ) {
|
nuclear@19
|
568 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
|
nuclear@19
|
569 if ( !node->Accept( visitor ) ) {
|
nuclear@19
|
570 break;
|
nuclear@19
|
571 }
|
nuclear@19
|
572 }
|
nuclear@19
|
573 }
|
nuclear@19
|
574 return visitor->VisitExit( *this );
|
nuclear@19
|
575 }
|
nuclear@19
|
576
|
nuclear@19
|
577
|
nuclear@19
|
578 // --------- XMLNode ----------- //
|
nuclear@19
|
579
|
nuclear@19
|
580 XMLNode::XMLNode( XMLDocument* doc ) :
|
nuclear@19
|
581 _document( doc ),
|
nuclear@19
|
582 _parent( 0 ),
|
nuclear@19
|
583 _firstChild( 0 ), _lastChild( 0 ),
|
nuclear@19
|
584 _prev( 0 ), _next( 0 ),
|
nuclear@19
|
585 _memPool( 0 )
|
nuclear@19
|
586 {
|
nuclear@19
|
587 }
|
nuclear@19
|
588
|
nuclear@19
|
589
|
nuclear@19
|
590 XMLNode::~XMLNode()
|
nuclear@19
|
591 {
|
nuclear@19
|
592 DeleteChildren();
|
nuclear@19
|
593 if ( _parent ) {
|
nuclear@19
|
594 _parent->Unlink( this );
|
nuclear@19
|
595 }
|
nuclear@19
|
596 }
|
nuclear@19
|
597
|
nuclear@19
|
598
|
nuclear@19
|
599 void XMLNode::SetValue( const char* str, bool staticMem )
|
nuclear@19
|
600 {
|
nuclear@19
|
601 if ( staticMem ) {
|
nuclear@19
|
602 _value.SetInternedStr( str );
|
nuclear@19
|
603 }
|
nuclear@19
|
604 else {
|
nuclear@19
|
605 _value.SetStr( str );
|
nuclear@19
|
606 }
|
nuclear@19
|
607 }
|
nuclear@19
|
608
|
nuclear@19
|
609
|
nuclear@19
|
610 void XMLNode::DeleteChildren()
|
nuclear@19
|
611 {
|
nuclear@19
|
612 while( _firstChild ) {
|
nuclear@19
|
613 XMLNode* node = _firstChild;
|
nuclear@19
|
614 Unlink( node );
|
nuclear@19
|
615
|
nuclear@19
|
616 DELETE_NODE( node );
|
nuclear@19
|
617 }
|
nuclear@19
|
618 _firstChild = _lastChild = 0;
|
nuclear@19
|
619 }
|
nuclear@19
|
620
|
nuclear@19
|
621
|
nuclear@19
|
622 void XMLNode::Unlink( XMLNode* child )
|
nuclear@19
|
623 {
|
nuclear@19
|
624 TIXMLASSERT( child->_parent == this );
|
nuclear@19
|
625 if ( child == _firstChild ) {
|
nuclear@19
|
626 _firstChild = _firstChild->_next;
|
nuclear@19
|
627 }
|
nuclear@19
|
628 if ( child == _lastChild ) {
|
nuclear@19
|
629 _lastChild = _lastChild->_prev;
|
nuclear@19
|
630 }
|
nuclear@19
|
631
|
nuclear@19
|
632 if ( child->_prev ) {
|
nuclear@19
|
633 child->_prev->_next = child->_next;
|
nuclear@19
|
634 }
|
nuclear@19
|
635 if ( child->_next ) {
|
nuclear@19
|
636 child->_next->_prev = child->_prev;
|
nuclear@19
|
637 }
|
nuclear@19
|
638 child->_parent = 0;
|
nuclear@19
|
639 }
|
nuclear@19
|
640
|
nuclear@19
|
641
|
nuclear@19
|
642 void XMLNode::DeleteChild( XMLNode* node )
|
nuclear@19
|
643 {
|
nuclear@19
|
644 TIXMLASSERT( node->_parent == this );
|
nuclear@19
|
645 DELETE_NODE( node );
|
nuclear@19
|
646 }
|
nuclear@19
|
647
|
nuclear@19
|
648
|
nuclear@19
|
649 XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
|
nuclear@19
|
650 {
|
nuclear@19
|
651 if ( _lastChild ) {
|
nuclear@19
|
652 TIXMLASSERT( _firstChild );
|
nuclear@19
|
653 TIXMLASSERT( _lastChild->_next == 0 );
|
nuclear@19
|
654 _lastChild->_next = addThis;
|
nuclear@19
|
655 addThis->_prev = _lastChild;
|
nuclear@19
|
656 _lastChild = addThis;
|
nuclear@19
|
657
|
nuclear@19
|
658 addThis->_next = 0;
|
nuclear@19
|
659 }
|
nuclear@19
|
660 else {
|
nuclear@19
|
661 TIXMLASSERT( _firstChild == 0 );
|
nuclear@19
|
662 _firstChild = _lastChild = addThis;
|
nuclear@19
|
663
|
nuclear@19
|
664 addThis->_prev = 0;
|
nuclear@19
|
665 addThis->_next = 0;
|
nuclear@19
|
666 }
|
nuclear@19
|
667 addThis->_parent = this;
|
nuclear@19
|
668 addThis->_memPool->SetTracked();
|
nuclear@19
|
669 return addThis;
|
nuclear@19
|
670 }
|
nuclear@19
|
671
|
nuclear@19
|
672
|
nuclear@19
|
673 XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
|
nuclear@19
|
674 {
|
nuclear@19
|
675 if ( _firstChild ) {
|
nuclear@19
|
676 TIXMLASSERT( _lastChild );
|
nuclear@19
|
677 TIXMLASSERT( _firstChild->_prev == 0 );
|
nuclear@19
|
678
|
nuclear@19
|
679 _firstChild->_prev = addThis;
|
nuclear@19
|
680 addThis->_next = _firstChild;
|
nuclear@19
|
681 _firstChild = addThis;
|
nuclear@19
|
682
|
nuclear@19
|
683 addThis->_prev = 0;
|
nuclear@19
|
684 }
|
nuclear@19
|
685 else {
|
nuclear@19
|
686 TIXMLASSERT( _lastChild == 0 );
|
nuclear@19
|
687 _firstChild = _lastChild = addThis;
|
nuclear@19
|
688
|
nuclear@19
|
689 addThis->_prev = 0;
|
nuclear@19
|
690 addThis->_next = 0;
|
nuclear@19
|
691 }
|
nuclear@19
|
692 addThis->_parent = this;
|
nuclear@19
|
693 addThis->_memPool->SetTracked();
|
nuclear@19
|
694 return addThis;
|
nuclear@19
|
695 }
|
nuclear@19
|
696
|
nuclear@19
|
697
|
nuclear@19
|
698 XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
|
nuclear@19
|
699 {
|
nuclear@19
|
700 TIXMLASSERT( afterThis->_parent == this );
|
nuclear@19
|
701 if ( afterThis->_parent != this ) {
|
nuclear@19
|
702 return 0;
|
nuclear@19
|
703 }
|
nuclear@19
|
704
|
nuclear@19
|
705 if ( afterThis->_next == 0 ) {
|
nuclear@19
|
706 // The last node or the only node.
|
nuclear@19
|
707 return InsertEndChild( addThis );
|
nuclear@19
|
708 }
|
nuclear@19
|
709 addThis->_prev = afterThis;
|
nuclear@19
|
710 addThis->_next = afterThis->_next;
|
nuclear@19
|
711 afterThis->_next->_prev = addThis;
|
nuclear@19
|
712 afterThis->_next = addThis;
|
nuclear@19
|
713 addThis->_parent = this;
|
nuclear@19
|
714 addThis->_memPool->SetTracked();
|
nuclear@19
|
715 return addThis;
|
nuclear@19
|
716 }
|
nuclear@19
|
717
|
nuclear@19
|
718
|
nuclear@19
|
719
|
nuclear@19
|
720
|
nuclear@19
|
721 const XMLElement* XMLNode::FirstChildElement( const char* value ) const
|
nuclear@19
|
722 {
|
nuclear@19
|
723 for( XMLNode* node=_firstChild; node; node=node->_next ) {
|
nuclear@19
|
724 XMLElement* element = node->ToElement();
|
nuclear@19
|
725 if ( element ) {
|
nuclear@19
|
726 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
|
nuclear@19
|
727 return element;
|
nuclear@19
|
728 }
|
nuclear@19
|
729 }
|
nuclear@19
|
730 }
|
nuclear@19
|
731 return 0;
|
nuclear@19
|
732 }
|
nuclear@19
|
733
|
nuclear@19
|
734
|
nuclear@19
|
735 const XMLElement* XMLNode::LastChildElement( const char* value ) const
|
nuclear@19
|
736 {
|
nuclear@19
|
737 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
|
nuclear@19
|
738 XMLElement* element = node->ToElement();
|
nuclear@19
|
739 if ( element ) {
|
nuclear@19
|
740 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
|
nuclear@19
|
741 return element;
|
nuclear@19
|
742 }
|
nuclear@19
|
743 }
|
nuclear@19
|
744 }
|
nuclear@19
|
745 return 0;
|
nuclear@19
|
746 }
|
nuclear@19
|
747
|
nuclear@19
|
748
|
nuclear@19
|
749 const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
|
nuclear@19
|
750 {
|
nuclear@19
|
751 for( XMLNode* element=this->_next; element; element = element->_next ) {
|
nuclear@19
|
752 if ( element->ToElement()
|
nuclear@19
|
753 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
|
nuclear@19
|
754 return element->ToElement();
|
nuclear@19
|
755 }
|
nuclear@19
|
756 }
|
nuclear@19
|
757 return 0;
|
nuclear@19
|
758 }
|
nuclear@19
|
759
|
nuclear@19
|
760
|
nuclear@19
|
761 const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
|
nuclear@19
|
762 {
|
nuclear@19
|
763 for( XMLNode* element=_prev; element; element = element->_prev ) {
|
nuclear@19
|
764 if ( element->ToElement()
|
nuclear@19
|
765 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
|
nuclear@19
|
766 return element->ToElement();
|
nuclear@19
|
767 }
|
nuclear@19
|
768 }
|
nuclear@19
|
769 return 0;
|
nuclear@19
|
770 }
|
nuclear@19
|
771
|
nuclear@19
|
772
|
nuclear@19
|
773 char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
|
nuclear@19
|
774 {
|
nuclear@19
|
775 // This is a recursive method, but thinking about it "at the current level"
|
nuclear@19
|
776 // it is a pretty simple flat list:
|
nuclear@19
|
777 // <foo/>
|
nuclear@19
|
778 // <!-- comment -->
|
nuclear@19
|
779 //
|
nuclear@19
|
780 // With a special case:
|
nuclear@19
|
781 // <foo>
|
nuclear@19
|
782 // </foo>
|
nuclear@19
|
783 // <!-- comment -->
|
nuclear@19
|
784 //
|
nuclear@19
|
785 // Where the closing element (/foo) *must* be the next thing after the opening
|
nuclear@19
|
786 // element, and the names must match. BUT the tricky bit is that the closing
|
nuclear@19
|
787 // element will be read by the child.
|
nuclear@19
|
788 //
|
nuclear@19
|
789 // 'endTag' is the end tag for this node, it is returned by a call to a child.
|
nuclear@19
|
790 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
|
nuclear@19
|
791
|
nuclear@19
|
792 while( p && *p ) {
|
nuclear@19
|
793 XMLNode* node = 0;
|
nuclear@19
|
794
|
nuclear@19
|
795 p = _document->Identify( p, &node );
|
nuclear@19
|
796 if ( p == 0 || node == 0 ) {
|
nuclear@19
|
797 break;
|
nuclear@19
|
798 }
|
nuclear@19
|
799
|
nuclear@19
|
800 StrPair endTag;
|
nuclear@19
|
801 p = node->ParseDeep( p, &endTag );
|
nuclear@19
|
802 if ( !p ) {
|
nuclear@19
|
803 DELETE_NODE( node );
|
nuclear@19
|
804 node = 0;
|
nuclear@19
|
805 if ( !_document->Error() ) {
|
nuclear@19
|
806 _document->SetError( XML_ERROR_PARSING, 0, 0 );
|
nuclear@19
|
807 }
|
nuclear@19
|
808 break;
|
nuclear@19
|
809 }
|
nuclear@19
|
810
|
nuclear@19
|
811 // We read the end tag. Return it to the parent.
|
nuclear@19
|
812 if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
|
nuclear@19
|
813 if ( parentEnd ) {
|
nuclear@19
|
814 *parentEnd = static_cast<XMLElement*>(node)->_value;
|
nuclear@19
|
815 }
|
nuclear@19
|
816 node->_memPool->SetTracked(); // created and then immediately deleted.
|
nuclear@19
|
817 DELETE_NODE( node );
|
nuclear@19
|
818 return p;
|
nuclear@19
|
819 }
|
nuclear@19
|
820
|
nuclear@19
|
821 // Handle an end tag returned to this level.
|
nuclear@19
|
822 // And handle a bunch of annoying errors.
|
nuclear@19
|
823 XMLElement* ele = node->ToElement();
|
nuclear@19
|
824 if ( ele ) {
|
nuclear@19
|
825 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
|
nuclear@19
|
826 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
|
nuclear@19
|
827 p = 0;
|
nuclear@19
|
828 }
|
nuclear@19
|
829 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
|
nuclear@19
|
830 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
|
nuclear@19
|
831 p = 0;
|
nuclear@19
|
832 }
|
nuclear@19
|
833 else if ( !endTag.Empty() ) {
|
nuclear@19
|
834 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
|
nuclear@19
|
835 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
|
nuclear@19
|
836 p = 0;
|
nuclear@19
|
837 }
|
nuclear@19
|
838 }
|
nuclear@19
|
839 }
|
nuclear@19
|
840 if ( p == 0 ) {
|
nuclear@19
|
841 DELETE_NODE( node );
|
nuclear@19
|
842 node = 0;
|
nuclear@19
|
843 }
|
nuclear@19
|
844 if ( node ) {
|
nuclear@19
|
845 this->InsertEndChild( node );
|
nuclear@19
|
846 }
|
nuclear@19
|
847 }
|
nuclear@19
|
848 return 0;
|
nuclear@19
|
849 }
|
nuclear@19
|
850
|
nuclear@19
|
851 // --------- XMLText ---------- //
|
nuclear@19
|
852 char* XMLText::ParseDeep( char* p, StrPair* )
|
nuclear@19
|
853 {
|
nuclear@19
|
854 const char* start = p;
|
nuclear@19
|
855 if ( this->CData() ) {
|
nuclear@19
|
856 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
|
nuclear@19
|
857 if ( !p ) {
|
nuclear@19
|
858 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
|
nuclear@19
|
859 }
|
nuclear@19
|
860 return p;
|
nuclear@19
|
861 }
|
nuclear@19
|
862 else {
|
nuclear@19
|
863 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
|
nuclear@19
|
864 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
|
nuclear@19
|
865 flags |= StrPair::COLLAPSE_WHITESPACE;
|
nuclear@19
|
866 }
|
nuclear@19
|
867
|
nuclear@19
|
868 p = _value.ParseText( p, "<", flags );
|
nuclear@19
|
869 if ( !p ) {
|
nuclear@19
|
870 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
|
nuclear@19
|
871 }
|
nuclear@19
|
872 if ( p && *p ) {
|
nuclear@19
|
873 return p-1;
|
nuclear@19
|
874 }
|
nuclear@19
|
875 }
|
nuclear@19
|
876 return 0;
|
nuclear@19
|
877 }
|
nuclear@19
|
878
|
nuclear@19
|
879
|
nuclear@19
|
880 XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
|
nuclear@19
|
881 {
|
nuclear@19
|
882 if ( !doc ) {
|
nuclear@19
|
883 doc = _document;
|
nuclear@19
|
884 }
|
nuclear@19
|
885 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
|
nuclear@19
|
886 text->SetCData( this->CData() );
|
nuclear@19
|
887 return text;
|
nuclear@19
|
888 }
|
nuclear@19
|
889
|
nuclear@19
|
890
|
nuclear@19
|
891 bool XMLText::ShallowEqual( const XMLNode* compare ) const
|
nuclear@19
|
892 {
|
nuclear@19
|
893 return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
|
nuclear@19
|
894 }
|
nuclear@19
|
895
|
nuclear@19
|
896
|
nuclear@19
|
897 bool XMLText::Accept( XMLVisitor* visitor ) const
|
nuclear@19
|
898 {
|
nuclear@19
|
899 return visitor->Visit( *this );
|
nuclear@19
|
900 }
|
nuclear@19
|
901
|
nuclear@19
|
902
|
nuclear@19
|
903 // --------- XMLComment ---------- //
|
nuclear@19
|
904
|
nuclear@19
|
905 XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
|
nuclear@19
|
906 {
|
nuclear@19
|
907 }
|
nuclear@19
|
908
|
nuclear@19
|
909
|
nuclear@19
|
910 XMLComment::~XMLComment()
|
nuclear@19
|
911 {
|
nuclear@19
|
912 }
|
nuclear@19
|
913
|
nuclear@19
|
914
|
nuclear@19
|
915 char* XMLComment::ParseDeep( char* p, StrPair* )
|
nuclear@19
|
916 {
|
nuclear@19
|
917 // Comment parses as text.
|
nuclear@19
|
918 const char* start = p;
|
nuclear@19
|
919 p = _value.ParseText( p, "-->", StrPair::COMMENT );
|
nuclear@19
|
920 if ( p == 0 ) {
|
nuclear@19
|
921 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
|
nuclear@19
|
922 }
|
nuclear@19
|
923 return p;
|
nuclear@19
|
924 }
|
nuclear@19
|
925
|
nuclear@19
|
926
|
nuclear@19
|
927 XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
|
nuclear@19
|
928 {
|
nuclear@19
|
929 if ( !doc ) {
|
nuclear@19
|
930 doc = _document;
|
nuclear@19
|
931 }
|
nuclear@19
|
932 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
|
nuclear@19
|
933 return comment;
|
nuclear@19
|
934 }
|
nuclear@19
|
935
|
nuclear@19
|
936
|
nuclear@19
|
937 bool XMLComment::ShallowEqual( const XMLNode* compare ) const
|
nuclear@19
|
938 {
|
nuclear@19
|
939 return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() ));
|
nuclear@19
|
940 }
|
nuclear@19
|
941
|
nuclear@19
|
942
|
nuclear@19
|
943 bool XMLComment::Accept( XMLVisitor* visitor ) const
|
nuclear@19
|
944 {
|
nuclear@19
|
945 return visitor->Visit( *this );
|
nuclear@19
|
946 }
|
nuclear@19
|
947
|
nuclear@19
|
948
|
nuclear@19
|
949 // --------- XMLDeclaration ---------- //
|
nuclear@19
|
950
|
nuclear@19
|
951 XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
|
nuclear@19
|
952 {
|
nuclear@19
|
953 }
|
nuclear@19
|
954
|
nuclear@19
|
955
|
nuclear@19
|
956 XMLDeclaration::~XMLDeclaration()
|
nuclear@19
|
957 {
|
nuclear@19
|
958 //printf( "~XMLDeclaration\n" );
|
nuclear@19
|
959 }
|
nuclear@19
|
960
|
nuclear@19
|
961
|
nuclear@19
|
962 char* XMLDeclaration::ParseDeep( char* p, StrPair* )
|
nuclear@19
|
963 {
|
nuclear@19
|
964 // Declaration parses as text.
|
nuclear@19
|
965 const char* start = p;
|
nuclear@19
|
966 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
|
nuclear@19
|
967 if ( p == 0 ) {
|
nuclear@19
|
968 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
|
nuclear@19
|
969 }
|
nuclear@19
|
970 return p;
|
nuclear@19
|
971 }
|
nuclear@19
|
972
|
nuclear@19
|
973
|
nuclear@19
|
974 XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
|
nuclear@19
|
975 {
|
nuclear@19
|
976 if ( !doc ) {
|
nuclear@19
|
977 doc = _document;
|
nuclear@19
|
978 }
|
nuclear@19
|
979 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
|
nuclear@19
|
980 return dec;
|
nuclear@19
|
981 }
|
nuclear@19
|
982
|
nuclear@19
|
983
|
nuclear@19
|
984 bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
|
nuclear@19
|
985 {
|
nuclear@19
|
986 return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() ));
|
nuclear@19
|
987 }
|
nuclear@19
|
988
|
nuclear@19
|
989
|
nuclear@19
|
990
|
nuclear@19
|
991 bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
|
nuclear@19
|
992 {
|
nuclear@19
|
993 return visitor->Visit( *this );
|
nuclear@19
|
994 }
|
nuclear@19
|
995
|
nuclear@19
|
996 // --------- XMLUnknown ---------- //
|
nuclear@19
|
997
|
nuclear@19
|
998 XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
|
nuclear@19
|
999 {
|
nuclear@19
|
1000 }
|
nuclear@19
|
1001
|
nuclear@19
|
1002
|
nuclear@19
|
1003 XMLUnknown::~XMLUnknown()
|
nuclear@19
|
1004 {
|
nuclear@19
|
1005 }
|
nuclear@19
|
1006
|
nuclear@19
|
1007
|
nuclear@19
|
1008 char* XMLUnknown::ParseDeep( char* p, StrPair* )
|
nuclear@19
|
1009 {
|
nuclear@19
|
1010 // Unknown parses as text.
|
nuclear@19
|
1011 const char* start = p;
|
nuclear@19
|
1012
|
nuclear@19
|
1013 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
|
nuclear@19
|
1014 if ( !p ) {
|
nuclear@19
|
1015 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
|
nuclear@19
|
1016 }
|
nuclear@19
|
1017 return p;
|
nuclear@19
|
1018 }
|
nuclear@19
|
1019
|
nuclear@19
|
1020
|
nuclear@19
|
1021 XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
|
nuclear@19
|
1022 {
|
nuclear@19
|
1023 if ( !doc ) {
|
nuclear@19
|
1024 doc = _document;
|
nuclear@19
|
1025 }
|
nuclear@19
|
1026 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
|
nuclear@19
|
1027 return text;
|
nuclear@19
|
1028 }
|
nuclear@19
|
1029
|
nuclear@19
|
1030
|
nuclear@19
|
1031 bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
|
nuclear@19
|
1032 {
|
nuclear@19
|
1033 return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() ));
|
nuclear@19
|
1034 }
|
nuclear@19
|
1035
|
nuclear@19
|
1036
|
nuclear@19
|
1037 bool XMLUnknown::Accept( XMLVisitor* visitor ) const
|
nuclear@19
|
1038 {
|
nuclear@19
|
1039 return visitor->Visit( *this );
|
nuclear@19
|
1040 }
|
nuclear@19
|
1041
|
nuclear@19
|
1042 // --------- XMLAttribute ---------- //
|
nuclear@19
|
1043 char* XMLAttribute::ParseDeep( char* p, bool processEntities )
|
nuclear@19
|
1044 {
|
nuclear@19
|
1045 // Parse using the name rules: bug fix, was using ParseText before
|
nuclear@19
|
1046 p = _name.ParseName( p );
|
nuclear@19
|
1047 if ( !p || !*p ) {
|
nuclear@19
|
1048 return 0;
|
nuclear@19
|
1049 }
|
nuclear@19
|
1050
|
nuclear@19
|
1051 // Skip white space before =
|
nuclear@19
|
1052 p = XMLUtil::SkipWhiteSpace( p );
|
nuclear@19
|
1053 if ( !p || *p != '=' ) {
|
nuclear@19
|
1054 return 0;
|
nuclear@19
|
1055 }
|
nuclear@19
|
1056
|
nuclear@19
|
1057 ++p; // move up to opening quote
|
nuclear@19
|
1058 p = XMLUtil::SkipWhiteSpace( p );
|
nuclear@19
|
1059 if ( *p != '\"' && *p != '\'' ) {
|
nuclear@19
|
1060 return 0;
|
nuclear@19
|
1061 }
|
nuclear@19
|
1062
|
nuclear@19
|
1063 char endTag[2] = { *p, 0 };
|
nuclear@19
|
1064 ++p; // move past opening quote
|
nuclear@19
|
1065
|
nuclear@19
|
1066 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
|
nuclear@19
|
1067 return p;
|
nuclear@19
|
1068 }
|
nuclear@19
|
1069
|
nuclear@19
|
1070
|
nuclear@19
|
1071 void XMLAttribute::SetName( const char* n )
|
nuclear@19
|
1072 {
|
nuclear@19
|
1073 _name.SetStr( n );
|
nuclear@19
|
1074 }
|
nuclear@19
|
1075
|
nuclear@19
|
1076
|
nuclear@19
|
1077 XMLError XMLAttribute::QueryIntValue( int* value ) const
|
nuclear@19
|
1078 {
|
nuclear@19
|
1079 if ( XMLUtil::ToInt( Value(), value )) {
|
nuclear@19
|
1080 return XML_NO_ERROR;
|
nuclear@19
|
1081 }
|
nuclear@19
|
1082 return XML_WRONG_ATTRIBUTE_TYPE;
|
nuclear@19
|
1083 }
|
nuclear@19
|
1084
|
nuclear@19
|
1085
|
nuclear@19
|
1086 XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
|
nuclear@19
|
1087 {
|
nuclear@19
|
1088 if ( XMLUtil::ToUnsigned( Value(), value )) {
|
nuclear@19
|
1089 return XML_NO_ERROR;
|
nuclear@19
|
1090 }
|
nuclear@19
|
1091 return XML_WRONG_ATTRIBUTE_TYPE;
|
nuclear@19
|
1092 }
|
nuclear@19
|
1093
|
nuclear@19
|
1094
|
nuclear@19
|
1095 XMLError XMLAttribute::QueryBoolValue( bool* value ) const
|
nuclear@19
|
1096 {
|
nuclear@19
|
1097 if ( XMLUtil::ToBool( Value(), value )) {
|
nuclear@19
|
1098 return XML_NO_ERROR;
|
nuclear@19
|
1099 }
|
nuclear@19
|
1100 return XML_WRONG_ATTRIBUTE_TYPE;
|
nuclear@19
|
1101 }
|
nuclear@19
|
1102
|
nuclear@19
|
1103
|
nuclear@19
|
1104 XMLError XMLAttribute::QueryFloatValue( float* value ) const
|
nuclear@19
|
1105 {
|
nuclear@19
|
1106 if ( XMLUtil::ToFloat( Value(), value )) {
|
nuclear@19
|
1107 return XML_NO_ERROR;
|
nuclear@19
|
1108 }
|
nuclear@19
|
1109 return XML_WRONG_ATTRIBUTE_TYPE;
|
nuclear@19
|
1110 }
|
nuclear@19
|
1111
|
nuclear@19
|
1112
|
nuclear@19
|
1113 XMLError XMLAttribute::QueryDoubleValue( double* value ) const
|
nuclear@19
|
1114 {
|
nuclear@19
|
1115 if ( XMLUtil::ToDouble( Value(), value )) {
|
nuclear@19
|
1116 return XML_NO_ERROR;
|
nuclear@19
|
1117 }
|
nuclear@19
|
1118 return XML_WRONG_ATTRIBUTE_TYPE;
|
nuclear@19
|
1119 }
|
nuclear@19
|
1120
|
nuclear@19
|
1121
|
nuclear@19
|
1122 void XMLAttribute::SetAttribute( const char* v )
|
nuclear@19
|
1123 {
|
nuclear@19
|
1124 _value.SetStr( v );
|
nuclear@19
|
1125 }
|
nuclear@19
|
1126
|
nuclear@19
|
1127
|
nuclear@19
|
1128 void XMLAttribute::SetAttribute( int v )
|
nuclear@19
|
1129 {
|
nuclear@19
|
1130 char buf[BUF_SIZE];
|
nuclear@19
|
1131 XMLUtil::ToStr( v, buf, BUF_SIZE );
|
nuclear@19
|
1132 _value.SetStr( buf );
|
nuclear@19
|
1133 }
|
nuclear@19
|
1134
|
nuclear@19
|
1135
|
nuclear@19
|
1136 void XMLAttribute::SetAttribute( unsigned v )
|
nuclear@19
|
1137 {
|
nuclear@19
|
1138 char buf[BUF_SIZE];
|
nuclear@19
|
1139 XMLUtil::ToStr( v, buf, BUF_SIZE );
|
nuclear@19
|
1140 _value.SetStr( buf );
|
nuclear@19
|
1141 }
|
nuclear@19
|
1142
|
nuclear@19
|
1143
|
nuclear@19
|
1144 void XMLAttribute::SetAttribute( bool v )
|
nuclear@19
|
1145 {
|
nuclear@19
|
1146 char buf[BUF_SIZE];
|
nuclear@19
|
1147 XMLUtil::ToStr( v, buf, BUF_SIZE );
|
nuclear@19
|
1148 _value.SetStr( buf );
|
nuclear@19
|
1149 }
|
nuclear@19
|
1150
|
nuclear@19
|
1151 void XMLAttribute::SetAttribute( double v )
|
nuclear@19
|
1152 {
|
nuclear@19
|
1153 char buf[BUF_SIZE];
|
nuclear@19
|
1154 XMLUtil::ToStr( v, buf, BUF_SIZE );
|
nuclear@19
|
1155 _value.SetStr( buf );
|
nuclear@19
|
1156 }
|
nuclear@19
|
1157
|
nuclear@19
|
1158 void XMLAttribute::SetAttribute( float v )
|
nuclear@19
|
1159 {
|
nuclear@19
|
1160 char buf[BUF_SIZE];
|
nuclear@19
|
1161 XMLUtil::ToStr( v, buf, BUF_SIZE );
|
nuclear@19
|
1162 _value.SetStr( buf );
|
nuclear@19
|
1163 }
|
nuclear@19
|
1164
|
nuclear@19
|
1165
|
nuclear@19
|
1166 // --------- XMLElement ---------- //
|
nuclear@19
|
1167 XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
|
nuclear@19
|
1168 _closingType( 0 ),
|
nuclear@19
|
1169 _rootAttribute( 0 )
|
nuclear@19
|
1170 {
|
nuclear@19
|
1171 }
|
nuclear@19
|
1172
|
nuclear@19
|
1173
|
nuclear@19
|
1174 XMLElement::~XMLElement()
|
nuclear@19
|
1175 {
|
nuclear@19
|
1176 while( _rootAttribute ) {
|
nuclear@19
|
1177 XMLAttribute* next = _rootAttribute->_next;
|
nuclear@19
|
1178 DELETE_ATTRIBUTE( _rootAttribute );
|
nuclear@19
|
1179 _rootAttribute = next;
|
nuclear@19
|
1180 }
|
nuclear@19
|
1181 }
|
nuclear@19
|
1182
|
nuclear@19
|
1183
|
nuclear@19
|
1184 XMLAttribute* XMLElement::FindAttribute( const char* name )
|
nuclear@19
|
1185 {
|
nuclear@19
|
1186 XMLAttribute* a = 0;
|
nuclear@19
|
1187 for( a=_rootAttribute; a; a = a->_next ) {
|
nuclear@19
|
1188 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
|
nuclear@19
|
1189 return a;
|
nuclear@19
|
1190 }
|
nuclear@19
|
1191 }
|
nuclear@19
|
1192 return 0;
|
nuclear@19
|
1193 }
|
nuclear@19
|
1194
|
nuclear@19
|
1195
|
nuclear@19
|
1196 const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
|
nuclear@19
|
1197 {
|
nuclear@19
|
1198 XMLAttribute* a = 0;
|
nuclear@19
|
1199 for( a=_rootAttribute; a; a = a->_next ) {
|
nuclear@19
|
1200 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
|
nuclear@19
|
1201 return a;
|
nuclear@19
|
1202 }
|
nuclear@19
|
1203 }
|
nuclear@19
|
1204 return 0;
|
nuclear@19
|
1205 }
|
nuclear@19
|
1206
|
nuclear@19
|
1207
|
nuclear@19
|
1208 const char* XMLElement::Attribute( const char* name, const char* value ) const
|
nuclear@19
|
1209 {
|
nuclear@19
|
1210 const XMLAttribute* a = FindAttribute( name );
|
nuclear@19
|
1211 if ( !a ) {
|
nuclear@19
|
1212 return 0;
|
nuclear@19
|
1213 }
|
nuclear@19
|
1214 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
|
nuclear@19
|
1215 return a->Value();
|
nuclear@19
|
1216 }
|
nuclear@19
|
1217 return 0;
|
nuclear@19
|
1218 }
|
nuclear@19
|
1219
|
nuclear@19
|
1220
|
nuclear@19
|
1221 const char* XMLElement::GetText() const
|
nuclear@19
|
1222 {
|
nuclear@19
|
1223 if ( FirstChild() && FirstChild()->ToText() ) {
|
nuclear@19
|
1224 return FirstChild()->ToText()->Value();
|
nuclear@19
|
1225 }
|
nuclear@19
|
1226 return 0;
|
nuclear@19
|
1227 }
|
nuclear@19
|
1228
|
nuclear@19
|
1229
|
nuclear@19
|
1230 XMLError XMLElement::QueryIntText( int* ival ) const
|
nuclear@19
|
1231 {
|
nuclear@19
|
1232 if ( FirstChild() && FirstChild()->ToText() ) {
|
nuclear@19
|
1233 const char* t = FirstChild()->ToText()->Value();
|
nuclear@19
|
1234 if ( XMLUtil::ToInt( t, ival ) ) {
|
nuclear@19
|
1235 return XML_SUCCESS;
|
nuclear@19
|
1236 }
|
nuclear@19
|
1237 return XML_CAN_NOT_CONVERT_TEXT;
|
nuclear@19
|
1238 }
|
nuclear@19
|
1239 return XML_NO_TEXT_NODE;
|
nuclear@19
|
1240 }
|
nuclear@19
|
1241
|
nuclear@19
|
1242
|
nuclear@19
|
1243 XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
|
nuclear@19
|
1244 {
|
nuclear@19
|
1245 if ( FirstChild() && FirstChild()->ToText() ) {
|
nuclear@19
|
1246 const char* t = FirstChild()->ToText()->Value();
|
nuclear@19
|
1247 if ( XMLUtil::ToUnsigned( t, uval ) ) {
|
nuclear@19
|
1248 return XML_SUCCESS;
|
nuclear@19
|
1249 }
|
nuclear@19
|
1250 return XML_CAN_NOT_CONVERT_TEXT;
|
nuclear@19
|
1251 }
|
nuclear@19
|
1252 return XML_NO_TEXT_NODE;
|
nuclear@19
|
1253 }
|
nuclear@19
|
1254
|
nuclear@19
|
1255
|
nuclear@19
|
1256 XMLError XMLElement::QueryBoolText( bool* bval ) const
|
nuclear@19
|
1257 {
|
nuclear@19
|
1258 if ( FirstChild() && FirstChild()->ToText() ) {
|
nuclear@19
|
1259 const char* t = FirstChild()->ToText()->Value();
|
nuclear@19
|
1260 if ( XMLUtil::ToBool( t, bval ) ) {
|
nuclear@19
|
1261 return XML_SUCCESS;
|
nuclear@19
|
1262 }
|
nuclear@19
|
1263 return XML_CAN_NOT_CONVERT_TEXT;
|
nuclear@19
|
1264 }
|
nuclear@19
|
1265 return XML_NO_TEXT_NODE;
|
nuclear@19
|
1266 }
|
nuclear@19
|
1267
|
nuclear@19
|
1268
|
nuclear@19
|
1269 XMLError XMLElement::QueryDoubleText( double* dval ) const
|
nuclear@19
|
1270 {
|
nuclear@19
|
1271 if ( FirstChild() && FirstChild()->ToText() ) {
|
nuclear@19
|
1272 const char* t = FirstChild()->ToText()->Value();
|
nuclear@19
|
1273 if ( XMLUtil::ToDouble( t, dval ) ) {
|
nuclear@19
|
1274 return XML_SUCCESS;
|
nuclear@19
|
1275 }
|
nuclear@19
|
1276 return XML_CAN_NOT_CONVERT_TEXT;
|
nuclear@19
|
1277 }
|
nuclear@19
|
1278 return XML_NO_TEXT_NODE;
|
nuclear@19
|
1279 }
|
nuclear@19
|
1280
|
nuclear@19
|
1281
|
nuclear@19
|
1282 XMLError XMLElement::QueryFloatText( float* fval ) const
|
nuclear@19
|
1283 {
|
nuclear@19
|
1284 if ( FirstChild() && FirstChild()->ToText() ) {
|
nuclear@19
|
1285 const char* t = FirstChild()->ToText()->Value();
|
nuclear@19
|
1286 if ( XMLUtil::ToFloat( t, fval ) ) {
|
nuclear@19
|
1287 return XML_SUCCESS;
|
nuclear@19
|
1288 }
|
nuclear@19
|
1289 return XML_CAN_NOT_CONVERT_TEXT;
|
nuclear@19
|
1290 }
|
nuclear@19
|
1291 return XML_NO_TEXT_NODE;
|
nuclear@19
|
1292 }
|
nuclear@19
|
1293
|
nuclear@19
|
1294
|
nuclear@19
|
1295
|
nuclear@19
|
1296 XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
|
nuclear@19
|
1297 {
|
nuclear@19
|
1298 XMLAttribute* last = 0;
|
nuclear@19
|
1299 XMLAttribute* attrib = 0;
|
nuclear@19
|
1300 for( attrib = _rootAttribute;
|
nuclear@19
|
1301 attrib;
|
nuclear@19
|
1302 last = attrib, attrib = attrib->_next ) {
|
nuclear@19
|
1303 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
|
nuclear@19
|
1304 break;
|
nuclear@19
|
1305 }
|
nuclear@19
|
1306 }
|
nuclear@19
|
1307 if ( !attrib ) {
|
nuclear@19
|
1308 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
|
nuclear@19
|
1309 attrib->_memPool = &_document->_attributePool;
|
nuclear@19
|
1310 if ( last ) {
|
nuclear@19
|
1311 last->_next = attrib;
|
nuclear@19
|
1312 }
|
nuclear@19
|
1313 else {
|
nuclear@19
|
1314 _rootAttribute = attrib;
|
nuclear@19
|
1315 }
|
nuclear@19
|
1316 attrib->SetName( name );
|
nuclear@19
|
1317 attrib->_memPool->SetTracked(); // always created and linked.
|
nuclear@19
|
1318 }
|
nuclear@19
|
1319 return attrib;
|
nuclear@19
|
1320 }
|
nuclear@19
|
1321
|
nuclear@19
|
1322
|
nuclear@19
|
1323 void XMLElement::DeleteAttribute( const char* name )
|
nuclear@19
|
1324 {
|
nuclear@19
|
1325 XMLAttribute* prev = 0;
|
nuclear@19
|
1326 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
|
nuclear@19
|
1327 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
|
nuclear@19
|
1328 if ( prev ) {
|
nuclear@19
|
1329 prev->_next = a->_next;
|
nuclear@19
|
1330 }
|
nuclear@19
|
1331 else {
|
nuclear@19
|
1332 _rootAttribute = a->_next;
|
nuclear@19
|
1333 }
|
nuclear@19
|
1334 DELETE_ATTRIBUTE( a );
|
nuclear@19
|
1335 break;
|
nuclear@19
|
1336 }
|
nuclear@19
|
1337 prev = a;
|
nuclear@19
|
1338 }
|
nuclear@19
|
1339 }
|
nuclear@19
|
1340
|
nuclear@19
|
1341
|
nuclear@19
|
1342 char* XMLElement::ParseAttributes( char* p )
|
nuclear@19
|
1343 {
|
nuclear@19
|
1344 const char* start = p;
|
nuclear@19
|
1345 XMLAttribute* prevAttribute = 0;
|
nuclear@19
|
1346
|
nuclear@19
|
1347 // Read the attributes.
|
nuclear@19
|
1348 while( p ) {
|
nuclear@19
|
1349 p = XMLUtil::SkipWhiteSpace( p );
|
nuclear@19
|
1350 if ( !p || !(*p) ) {
|
nuclear@19
|
1351 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
|
nuclear@19
|
1352 return 0;
|
nuclear@19
|
1353 }
|
nuclear@19
|
1354
|
nuclear@19
|
1355 // attribute.
|
nuclear@19
|
1356 if (XMLUtil::IsNameStartChar( *p ) ) {
|
nuclear@19
|
1357 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
|
nuclear@19
|
1358 attrib->_memPool = &_document->_attributePool;
|
nuclear@19
|
1359 attrib->_memPool->SetTracked();
|
nuclear@19
|
1360
|
nuclear@19
|
1361 p = attrib->ParseDeep( p, _document->ProcessEntities() );
|
nuclear@19
|
1362 if ( !p || Attribute( attrib->Name() ) ) {
|
nuclear@19
|
1363 DELETE_ATTRIBUTE( attrib );
|
nuclear@19
|
1364 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
|
nuclear@19
|
1365 return 0;
|
nuclear@19
|
1366 }
|
nuclear@19
|
1367 // There is a minor bug here: if the attribute in the source xml
|
nuclear@19
|
1368 // document is duplicated, it will not be detected and the
|
nuclear@19
|
1369 // attribute will be doubly added. However, tracking the 'prevAttribute'
|
nuclear@19
|
1370 // avoids re-scanning the attribute list. Preferring performance for
|
nuclear@19
|
1371 // now, may reconsider in the future.
|
nuclear@19
|
1372 if ( prevAttribute ) {
|
nuclear@19
|
1373 prevAttribute->_next = attrib;
|
nuclear@19
|
1374 }
|
nuclear@19
|
1375 else {
|
nuclear@19
|
1376 _rootAttribute = attrib;
|
nuclear@19
|
1377 }
|
nuclear@19
|
1378 prevAttribute = attrib;
|
nuclear@19
|
1379 }
|
nuclear@19
|
1380 // end of the tag
|
nuclear@19
|
1381 else if ( *p == '/' && *(p+1) == '>' ) {
|
nuclear@19
|
1382 _closingType = CLOSED;
|
nuclear@19
|
1383 return p+2; // done; sealed element.
|
nuclear@19
|
1384 }
|
nuclear@19
|
1385 // end of the tag
|
nuclear@19
|
1386 else if ( *p == '>' ) {
|
nuclear@19
|
1387 ++p;
|
nuclear@19
|
1388 break;
|
nuclear@19
|
1389 }
|
nuclear@19
|
1390 else {
|
nuclear@19
|
1391 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
|
nuclear@19
|
1392 return 0;
|
nuclear@19
|
1393 }
|
nuclear@19
|
1394 }
|
nuclear@19
|
1395 return p;
|
nuclear@19
|
1396 }
|
nuclear@19
|
1397
|
nuclear@19
|
1398
|
nuclear@19
|
1399 //
|
nuclear@19
|
1400 // <ele></ele>
|
nuclear@19
|
1401 // <ele>foo<b>bar</b></ele>
|
nuclear@19
|
1402 //
|
nuclear@19
|
1403 char* XMLElement::ParseDeep( char* p, StrPair* strPair )
|
nuclear@19
|
1404 {
|
nuclear@19
|
1405 // Read the element name.
|
nuclear@19
|
1406 p = XMLUtil::SkipWhiteSpace( p );
|
nuclear@19
|
1407 if ( !p ) {
|
nuclear@19
|
1408 return 0;
|
nuclear@19
|
1409 }
|
nuclear@19
|
1410
|
nuclear@19
|
1411 // The closing element is the </element> form. It is
|
nuclear@19
|
1412 // parsed just like a regular element then deleted from
|
nuclear@19
|
1413 // the DOM.
|
nuclear@19
|
1414 if ( *p == '/' ) {
|
nuclear@19
|
1415 _closingType = CLOSING;
|
nuclear@19
|
1416 ++p;
|
nuclear@19
|
1417 }
|
nuclear@19
|
1418
|
nuclear@19
|
1419 p = _value.ParseName( p );
|
nuclear@19
|
1420 if ( _value.Empty() ) {
|
nuclear@19
|
1421 return 0;
|
nuclear@19
|
1422 }
|
nuclear@19
|
1423
|
nuclear@19
|
1424 p = ParseAttributes( p );
|
nuclear@19
|
1425 if ( !p || !*p || _closingType ) {
|
nuclear@19
|
1426 return p;
|
nuclear@19
|
1427 }
|
nuclear@19
|
1428
|
nuclear@19
|
1429 p = XMLNode::ParseDeep( p, strPair );
|
nuclear@19
|
1430 return p;
|
nuclear@19
|
1431 }
|
nuclear@19
|
1432
|
nuclear@19
|
1433
|
nuclear@19
|
1434
|
nuclear@19
|
1435 XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
|
nuclear@19
|
1436 {
|
nuclear@19
|
1437 if ( !doc ) {
|
nuclear@19
|
1438 doc = _document;
|
nuclear@19
|
1439 }
|
nuclear@19
|
1440 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
|
nuclear@19
|
1441 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
|
nuclear@19
|
1442 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
|
nuclear@19
|
1443 }
|
nuclear@19
|
1444 return element;
|
nuclear@19
|
1445 }
|
nuclear@19
|
1446
|
nuclear@19
|
1447
|
nuclear@19
|
1448 bool XMLElement::ShallowEqual( const XMLNode* compare ) const
|
nuclear@19
|
1449 {
|
nuclear@19
|
1450 const XMLElement* other = compare->ToElement();
|
nuclear@19
|
1451 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
|
nuclear@19
|
1452
|
nuclear@19
|
1453 const XMLAttribute* a=FirstAttribute();
|
nuclear@19
|
1454 const XMLAttribute* b=other->FirstAttribute();
|
nuclear@19
|
1455
|
nuclear@19
|
1456 while ( a && b ) {
|
nuclear@19
|
1457 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
|
nuclear@19
|
1458 return false;
|
nuclear@19
|
1459 }
|
nuclear@19
|
1460 a = a->Next();
|
nuclear@19
|
1461 b = b->Next();
|
nuclear@19
|
1462 }
|
nuclear@19
|
1463 if ( a || b ) {
|
nuclear@19
|
1464 // different count
|
nuclear@19
|
1465 return false;
|
nuclear@19
|
1466 }
|
nuclear@19
|
1467 return true;
|
nuclear@19
|
1468 }
|
nuclear@19
|
1469 return false;
|
nuclear@19
|
1470 }
|
nuclear@19
|
1471
|
nuclear@19
|
1472
|
nuclear@19
|
1473 bool XMLElement::Accept( XMLVisitor* visitor ) const
|
nuclear@19
|
1474 {
|
nuclear@19
|
1475 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
|
nuclear@19
|
1476 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
|
nuclear@19
|
1477 if ( !node->Accept( visitor ) ) {
|
nuclear@19
|
1478 break;
|
nuclear@19
|
1479 }
|
nuclear@19
|
1480 }
|
nuclear@19
|
1481 }
|
nuclear@19
|
1482 return visitor->VisitExit( *this );
|
nuclear@19
|
1483 }
|
nuclear@19
|
1484
|
nuclear@19
|
1485
|
nuclear@19
|
1486 // --------- XMLDocument ----------- //
|
nuclear@19
|
1487 XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
|
nuclear@19
|
1488 XMLNode( 0 ),
|
nuclear@19
|
1489 _writeBOM( false ),
|
nuclear@19
|
1490 _processEntities( processEntities ),
|
nuclear@19
|
1491 _errorID( XML_NO_ERROR ),
|
nuclear@19
|
1492 _whitespace( whitespace ),
|
nuclear@19
|
1493 _errorStr1( 0 ),
|
nuclear@19
|
1494 _errorStr2( 0 ),
|
nuclear@19
|
1495 _charBuffer( 0 )
|
nuclear@19
|
1496 {
|
nuclear@19
|
1497 _document = this; // avoid warning about 'this' in initializer list
|
nuclear@19
|
1498 }
|
nuclear@19
|
1499
|
nuclear@19
|
1500
|
nuclear@19
|
1501 XMLDocument::~XMLDocument()
|
nuclear@19
|
1502 {
|
nuclear@19
|
1503 DeleteChildren();
|
nuclear@19
|
1504 delete [] _charBuffer;
|
nuclear@19
|
1505
|
nuclear@19
|
1506 #if 0
|
nuclear@19
|
1507 _textPool.Trace( "text" );
|
nuclear@19
|
1508 _elementPool.Trace( "element" );
|
nuclear@19
|
1509 _commentPool.Trace( "comment" );
|
nuclear@19
|
1510 _attributePool.Trace( "attribute" );
|
nuclear@19
|
1511 #endif
|
nuclear@19
|
1512
|
nuclear@19
|
1513 #ifdef DEBUG
|
nuclear@19
|
1514 if ( Error() == false ) {
|
nuclear@19
|
1515 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
|
nuclear@19
|
1516 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
|
nuclear@19
|
1517 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
|
nuclear@19
|
1518 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
|
nuclear@19
|
1519 }
|
nuclear@19
|
1520 #endif
|
nuclear@19
|
1521 }
|
nuclear@19
|
1522
|
nuclear@19
|
1523
|
nuclear@19
|
1524 void XMLDocument::Clear()
|
nuclear@19
|
1525 {
|
nuclear@19
|
1526 DeleteChildren();
|
nuclear@19
|
1527
|
nuclear@19
|
1528 _errorID = XML_NO_ERROR;
|
nuclear@19
|
1529 _errorStr1 = 0;
|
nuclear@19
|
1530 _errorStr2 = 0;
|
nuclear@19
|
1531
|
nuclear@19
|
1532 delete [] _charBuffer;
|
nuclear@19
|
1533 _charBuffer = 0;
|
nuclear@19
|
1534 }
|
nuclear@19
|
1535
|
nuclear@19
|
1536
|
nuclear@19
|
1537 XMLElement* XMLDocument::NewElement( const char* name )
|
nuclear@19
|
1538 {
|
nuclear@19
|
1539 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
|
nuclear@19
|
1540 ele->_memPool = &_elementPool;
|
nuclear@19
|
1541 ele->SetName( name );
|
nuclear@19
|
1542 return ele;
|
nuclear@19
|
1543 }
|
nuclear@19
|
1544
|
nuclear@19
|
1545
|
nuclear@19
|
1546 XMLComment* XMLDocument::NewComment( const char* str )
|
nuclear@19
|
1547 {
|
nuclear@19
|
1548 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
|
nuclear@19
|
1549 comment->_memPool = &_commentPool;
|
nuclear@19
|
1550 comment->SetValue( str );
|
nuclear@19
|
1551 return comment;
|
nuclear@19
|
1552 }
|
nuclear@19
|
1553
|
nuclear@19
|
1554
|
nuclear@19
|
1555 XMLText* XMLDocument::NewText( const char* str )
|
nuclear@19
|
1556 {
|
nuclear@19
|
1557 XMLText* text = new (_textPool.Alloc()) XMLText( this );
|
nuclear@19
|
1558 text->_memPool = &_textPool;
|
nuclear@19
|
1559 text->SetValue( str );
|
nuclear@19
|
1560 return text;
|
nuclear@19
|
1561 }
|
nuclear@19
|
1562
|
nuclear@19
|
1563
|
nuclear@19
|
1564 XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
|
nuclear@19
|
1565 {
|
nuclear@19
|
1566 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
|
nuclear@19
|
1567 dec->_memPool = &_commentPool;
|
nuclear@19
|
1568 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
|
nuclear@19
|
1569 return dec;
|
nuclear@19
|
1570 }
|
nuclear@19
|
1571
|
nuclear@19
|
1572
|
nuclear@19
|
1573 XMLUnknown* XMLDocument::NewUnknown( const char* str )
|
nuclear@19
|
1574 {
|
nuclear@19
|
1575 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
|
nuclear@19
|
1576 unk->_memPool = &_commentPool;
|
nuclear@19
|
1577 unk->SetValue( str );
|
nuclear@19
|
1578 return unk;
|
nuclear@19
|
1579 }
|
nuclear@19
|
1580
|
nuclear@19
|
1581
|
nuclear@19
|
1582 XMLError XMLDocument::LoadFile( const char* filename )
|
nuclear@19
|
1583 {
|
nuclear@19
|
1584 Clear();
|
nuclear@19
|
1585 FILE* fp = 0;
|
nuclear@19
|
1586
|
nuclear@19
|
1587 #if defined(_MSC_VER) && (_MSC_VER >= 1400 )
|
nuclear@19
|
1588 errno_t err = fopen_s(&fp, filename, "rb" );
|
nuclear@19
|
1589 if ( !fp || err) {
|
nuclear@19
|
1590 #else
|
nuclear@19
|
1591 fp = fopen( filename, "rb" );
|
nuclear@19
|
1592 if ( !fp) {
|
nuclear@19
|
1593 #endif
|
nuclear@19
|
1594 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
|
nuclear@19
|
1595 return _errorID;
|
nuclear@19
|
1596 }
|
nuclear@19
|
1597 LoadFile( fp );
|
nuclear@19
|
1598 fclose( fp );
|
nuclear@19
|
1599 return _errorID;
|
nuclear@19
|
1600 }
|
nuclear@19
|
1601
|
nuclear@19
|
1602
|
nuclear@19
|
1603 XMLError XMLDocument::LoadFile( FILE* fp )
|
nuclear@19
|
1604 {
|
nuclear@19
|
1605 Clear();
|
nuclear@19
|
1606
|
nuclear@19
|
1607 fseek( fp, 0, SEEK_END );
|
nuclear@19
|
1608 size_t size = ftell( fp );
|
nuclear@19
|
1609 fseek( fp, 0, SEEK_SET );
|
nuclear@19
|
1610
|
nuclear@19
|
1611 if ( size == 0 ) {
|
nuclear@19
|
1612 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
|
nuclear@19
|
1613 return _errorID;
|
nuclear@19
|
1614 }
|
nuclear@19
|
1615
|
nuclear@19
|
1616 _charBuffer = new char[size+1];
|
nuclear@19
|
1617 size_t read = fread( _charBuffer, 1, size, fp );
|
nuclear@19
|
1618 if ( read != size ) {
|
nuclear@19
|
1619 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
|
nuclear@19
|
1620 return _errorID;
|
nuclear@19
|
1621 }
|
nuclear@19
|
1622
|
nuclear@19
|
1623 _charBuffer[size] = 0;
|
nuclear@19
|
1624
|
nuclear@19
|
1625 const char* p = _charBuffer;
|
nuclear@19
|
1626 p = XMLUtil::SkipWhiteSpace( p );
|
nuclear@19
|
1627 p = XMLUtil::ReadBOM( p, &_writeBOM );
|
nuclear@19
|
1628 if ( !p || !*p ) {
|
nuclear@19
|
1629 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
|
nuclear@19
|
1630 return _errorID;
|
nuclear@19
|
1631 }
|
nuclear@19
|
1632
|
nuclear@19
|
1633 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
|
nuclear@19
|
1634 return _errorID;
|
nuclear@19
|
1635 }
|
nuclear@19
|
1636
|
nuclear@19
|
1637
|
nuclear@19
|
1638 XMLError XMLDocument::SaveFile( const char* filename, bool compact )
|
nuclear@19
|
1639 {
|
nuclear@19
|
1640 FILE* fp = 0;
|
nuclear@19
|
1641 #if defined(_MSC_VER) && (_MSC_VER >= 1400 )
|
nuclear@19
|
1642 errno_t err = fopen_s(&fp, filename, "w" );
|
nuclear@19
|
1643 if ( !fp || err) {
|
nuclear@19
|
1644 #else
|
nuclear@19
|
1645 fp = fopen( filename, "w" );
|
nuclear@19
|
1646 if ( !fp) {
|
nuclear@19
|
1647 #endif
|
nuclear@19
|
1648 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
|
nuclear@19
|
1649 return _errorID;
|
nuclear@19
|
1650 }
|
nuclear@19
|
1651 SaveFile(fp, compact);
|
nuclear@19
|
1652 fclose( fp );
|
nuclear@19
|
1653 return _errorID;
|
nuclear@19
|
1654 }
|
nuclear@19
|
1655
|
nuclear@19
|
1656
|
nuclear@19
|
1657 XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
|
nuclear@19
|
1658 {
|
nuclear@19
|
1659 XMLPrinter stream( fp, compact );
|
nuclear@19
|
1660 Print( &stream );
|
nuclear@19
|
1661 return _errorID;
|
nuclear@19
|
1662 }
|
nuclear@19
|
1663
|
nuclear@19
|
1664
|
nuclear@19
|
1665 XMLError XMLDocument::Parse( const char* p, size_t len )
|
nuclear@19
|
1666 {
|
nuclear@19
|
1667 const char* start = p;
|
nuclear@19
|
1668 Clear();
|
nuclear@19
|
1669
|
nuclear@19
|
1670 if ( !p || !*p ) {
|
nuclear@19
|
1671 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
|
nuclear@19
|
1672 return _errorID;
|
nuclear@19
|
1673 }
|
nuclear@19
|
1674 if ( len == (size_t)(-1) ) {
|
nuclear@19
|
1675 len = strlen( p );
|
nuclear@19
|
1676 }
|
nuclear@19
|
1677 _charBuffer = new char[ len+1 ];
|
nuclear@19
|
1678 memcpy( _charBuffer, p, len );
|
nuclear@19
|
1679 _charBuffer[len] = 0;
|
nuclear@19
|
1680
|
nuclear@19
|
1681 p = XMLUtil::SkipWhiteSpace( p );
|
nuclear@19
|
1682 p = XMLUtil::ReadBOM( p, &_writeBOM );
|
nuclear@19
|
1683 if ( !p || !*p ) {
|
nuclear@19
|
1684 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
|
nuclear@19
|
1685 return _errorID;
|
nuclear@19
|
1686 }
|
nuclear@19
|
1687
|
nuclear@19
|
1688 ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
|
nuclear@19
|
1689 ParseDeep( _charBuffer+delta, 0 );
|
nuclear@19
|
1690 return _errorID;
|
nuclear@19
|
1691 }
|
nuclear@19
|
1692
|
nuclear@19
|
1693
|
nuclear@19
|
1694 void XMLDocument::Print( XMLPrinter* streamer ) const
|
nuclear@19
|
1695 {
|
nuclear@19
|
1696 XMLPrinter stdStreamer( stdout );
|
nuclear@19
|
1697 if ( !streamer ) {
|
nuclear@19
|
1698 streamer = &stdStreamer;
|
nuclear@19
|
1699 }
|
nuclear@19
|
1700 Accept( streamer );
|
nuclear@19
|
1701 }
|
nuclear@19
|
1702
|
nuclear@19
|
1703
|
nuclear@19
|
1704 void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
|
nuclear@19
|
1705 {
|
nuclear@19
|
1706 _errorID = error;
|
nuclear@19
|
1707 _errorStr1 = str1;
|
nuclear@19
|
1708 _errorStr2 = str2;
|
nuclear@19
|
1709 }
|
nuclear@19
|
1710
|
nuclear@19
|
1711
|
nuclear@19
|
1712 void XMLDocument::PrintError() const
|
nuclear@19
|
1713 {
|
nuclear@19
|
1714 if ( _errorID ) {
|
nuclear@19
|
1715 static const int LEN = 20;
|
nuclear@19
|
1716 char buf1[LEN] = { 0 };
|
nuclear@19
|
1717 char buf2[LEN] = { 0 };
|
nuclear@19
|
1718
|
nuclear@19
|
1719 if ( _errorStr1 ) {
|
nuclear@19
|
1720 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
|
nuclear@19
|
1721 }
|
nuclear@19
|
1722 if ( _errorStr2 ) {
|
nuclear@19
|
1723 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
|
nuclear@19
|
1724 }
|
nuclear@19
|
1725
|
nuclear@19
|
1726 printf( "XMLDocument error id=%d str1=%s str2=%s\n",
|
nuclear@19
|
1727 _errorID, buf1, buf2 );
|
nuclear@19
|
1728 }
|
nuclear@19
|
1729 }
|
nuclear@19
|
1730
|
nuclear@19
|
1731
|
nuclear@19
|
1732 XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
|
nuclear@19
|
1733 _elementJustOpened( false ),
|
nuclear@19
|
1734 _firstElement( true ),
|
nuclear@19
|
1735 _fp( file ),
|
nuclear@19
|
1736 _depth( depth ),
|
nuclear@19
|
1737 _textDepth( -1 ),
|
nuclear@19
|
1738 _processEntities( true ),
|
nuclear@19
|
1739 _compactMode( compact )
|
nuclear@19
|
1740 {
|
nuclear@19
|
1741 for( int i=0; i<ENTITY_RANGE; ++i ) {
|
nuclear@19
|
1742 _entityFlag[i] = false;
|
nuclear@19
|
1743 _restrictedEntityFlag[i] = false;
|
nuclear@19
|
1744 }
|
nuclear@19
|
1745 for( int i=0; i<NUM_ENTITIES; ++i ) {
|
nuclear@19
|
1746 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
|
nuclear@19
|
1747 if ( entities[i].value < ENTITY_RANGE ) {
|
nuclear@19
|
1748 _entityFlag[ (int)entities[i].value ] = true;
|
nuclear@19
|
1749 }
|
nuclear@19
|
1750 }
|
nuclear@19
|
1751 _restrictedEntityFlag[(int)'&'] = true;
|
nuclear@19
|
1752 _restrictedEntityFlag[(int)'<'] = true;
|
nuclear@19
|
1753 _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
|
nuclear@19
|
1754 _buffer.Push( 0 );
|
nuclear@19
|
1755 }
|
nuclear@19
|
1756
|
nuclear@19
|
1757
|
nuclear@19
|
1758 void XMLPrinter::Print( const char* format, ... )
|
nuclear@19
|
1759 {
|
nuclear@19
|
1760 va_list va;
|
nuclear@19
|
1761 va_start( va, format );
|
nuclear@19
|
1762
|
nuclear@19
|
1763 if ( _fp ) {
|
nuclear@19
|
1764 vfprintf( _fp, format, va );
|
nuclear@19
|
1765 }
|
nuclear@19
|
1766 else {
|
nuclear@19
|
1767 // This seems brutally complex. Haven't figured out a better
|
nuclear@19
|
1768 // way on windows.
|
nuclear@19
|
1769 #ifdef _MSC_VER
|
nuclear@19
|
1770 int len = -1;
|
nuclear@19
|
1771 int expand = 1000;
|
nuclear@19
|
1772 while ( len < 0 ) {
|
nuclear@19
|
1773 len = vsnprintf_s( _accumulator.Mem(), _accumulator.Capacity(), _TRUNCATE, format, va );
|
nuclear@19
|
1774 if ( len < 0 ) {
|
nuclear@19
|
1775 expand *= 3/2;
|
nuclear@19
|
1776 _accumulator.PushArr( expand );
|
nuclear@19
|
1777 }
|
nuclear@19
|
1778 }
|
nuclear@19
|
1779 char* p = _buffer.PushArr( len ) - 1;
|
nuclear@19
|
1780 memcpy( p, _accumulator.Mem(), len+1 );
|
nuclear@19
|
1781 #else
|
nuclear@19
|
1782 int len = vsnprintf( 0, 0, format, va );
|
nuclear@19
|
1783 // Close out and re-start the va-args
|
nuclear@19
|
1784 va_end( va );
|
nuclear@19
|
1785 va_start( va, format );
|
nuclear@19
|
1786 char* p = _buffer.PushArr( len ) - 1;
|
nuclear@19
|
1787 vsnprintf( p, len+1, format, va );
|
nuclear@19
|
1788 #endif
|
nuclear@19
|
1789 }
|
nuclear@19
|
1790 va_end( va );
|
nuclear@19
|
1791 }
|
nuclear@19
|
1792
|
nuclear@19
|
1793
|
nuclear@19
|
1794 void XMLPrinter::PrintSpace( int depth )
|
nuclear@19
|
1795 {
|
nuclear@19
|
1796 for( int i=0; i<depth; ++i ) {
|
nuclear@19
|
1797 Print( " " );
|
nuclear@19
|
1798 }
|
nuclear@19
|
1799 }
|
nuclear@19
|
1800
|
nuclear@19
|
1801
|
nuclear@19
|
1802 void XMLPrinter::PrintString( const char* p, bool restricted )
|
nuclear@19
|
1803 {
|
nuclear@19
|
1804 // Look for runs of bytes between entities to print.
|
nuclear@19
|
1805 const char* q = p;
|
nuclear@19
|
1806 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
|
nuclear@19
|
1807
|
nuclear@19
|
1808 if ( _processEntities ) {
|
nuclear@19
|
1809 while ( *q ) {
|
nuclear@19
|
1810 // Remember, char is sometimes signed. (How many times has that bitten me?)
|
nuclear@19
|
1811 if ( *q > 0 && *q < ENTITY_RANGE ) {
|
nuclear@19
|
1812 // Check for entities. If one is found, flush
|
nuclear@19
|
1813 // the stream up until the entity, write the
|
nuclear@19
|
1814 // entity, and keep looking.
|
nuclear@19
|
1815 if ( flag[(unsigned)(*q)] ) {
|
nuclear@19
|
1816 while ( p < q ) {
|
nuclear@19
|
1817 Print( "%c", *p );
|
nuclear@19
|
1818 ++p;
|
nuclear@19
|
1819 }
|
nuclear@19
|
1820 for( int i=0; i<NUM_ENTITIES; ++i ) {
|
nuclear@19
|
1821 if ( entities[i].value == *q ) {
|
nuclear@19
|
1822 Print( "&%s;", entities[i].pattern );
|
nuclear@19
|
1823 break;
|
nuclear@19
|
1824 }
|
nuclear@19
|
1825 }
|
nuclear@19
|
1826 ++p;
|
nuclear@19
|
1827 }
|
nuclear@19
|
1828 }
|
nuclear@19
|
1829 ++q;
|
nuclear@19
|
1830 }
|
nuclear@19
|
1831 }
|
nuclear@19
|
1832 // Flush the remaining string. This will be the entire
|
nuclear@19
|
1833 // string if an entity wasn't found.
|
nuclear@19
|
1834 if ( !_processEntities || (q-p > 0) ) {
|
nuclear@19
|
1835 Print( "%s", p );
|
nuclear@19
|
1836 }
|
nuclear@19
|
1837 }
|
nuclear@19
|
1838
|
nuclear@19
|
1839
|
nuclear@19
|
1840 void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
|
nuclear@19
|
1841 {
|
nuclear@19
|
1842 if ( writeBOM ) {
|
nuclear@19
|
1843 static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
|
nuclear@19
|
1844 Print( "%s", bom );
|
nuclear@19
|
1845 }
|
nuclear@19
|
1846 if ( writeDec ) {
|
nuclear@19
|
1847 PushDeclaration( "xml version=\"1.0\"" );
|
nuclear@19
|
1848 }
|
nuclear@19
|
1849 }
|
nuclear@19
|
1850
|
nuclear@19
|
1851
|
nuclear@19
|
1852 void XMLPrinter::OpenElement( const char* name )
|
nuclear@19
|
1853 {
|
nuclear@19
|
1854 if ( _elementJustOpened ) {
|
nuclear@19
|
1855 SealElement();
|
nuclear@19
|
1856 }
|
nuclear@19
|
1857 _stack.Push( name );
|
nuclear@19
|
1858
|
nuclear@19
|
1859 if ( _textDepth < 0 && !_firstElement && !_compactMode ) {
|
nuclear@19
|
1860 Print( "\n" );
|
nuclear@19
|
1861 }
|
nuclear@19
|
1862 if ( !_compactMode ) {
|
nuclear@19
|
1863 PrintSpace( _depth );
|
nuclear@19
|
1864 }
|
nuclear@19
|
1865
|
nuclear@19
|
1866 Print( "<%s", name );
|
nuclear@19
|
1867 _elementJustOpened = true;
|
nuclear@19
|
1868 _firstElement = false;
|
nuclear@19
|
1869 ++_depth;
|
nuclear@19
|
1870 }
|
nuclear@19
|
1871
|
nuclear@19
|
1872
|
nuclear@19
|
1873 void XMLPrinter::PushAttribute( const char* name, const char* value )
|
nuclear@19
|
1874 {
|
nuclear@19
|
1875 TIXMLASSERT( _elementJustOpened );
|
nuclear@19
|
1876 Print( " %s=\"", name );
|
nuclear@19
|
1877 PrintString( value, false );
|
nuclear@19
|
1878 Print( "\"" );
|
nuclear@19
|
1879 }
|
nuclear@19
|
1880
|
nuclear@19
|
1881
|
nuclear@19
|
1882 void XMLPrinter::PushAttribute( const char* name, int v )
|
nuclear@19
|
1883 {
|
nuclear@19
|
1884 char buf[BUF_SIZE];
|
nuclear@19
|
1885 XMLUtil::ToStr( v, buf, BUF_SIZE );
|
nuclear@19
|
1886 PushAttribute( name, buf );
|
nuclear@19
|
1887 }
|
nuclear@19
|
1888
|
nuclear@19
|
1889
|
nuclear@19
|
1890 void XMLPrinter::PushAttribute( const char* name, unsigned v )
|
nuclear@19
|
1891 {
|
nuclear@19
|
1892 char buf[BUF_SIZE];
|
nuclear@19
|
1893 XMLUtil::ToStr( v, buf, BUF_SIZE );
|
nuclear@19
|
1894 PushAttribute( name, buf );
|
nuclear@19
|
1895 }
|
nuclear@19
|
1896
|
nuclear@19
|
1897
|
nuclear@19
|
1898 void XMLPrinter::PushAttribute( const char* name, bool v )
|
nuclear@19
|
1899 {
|
nuclear@19
|
1900 char buf[BUF_SIZE];
|
nuclear@19
|
1901 XMLUtil::ToStr( v, buf, BUF_SIZE );
|
nuclear@19
|
1902 PushAttribute( name, buf );
|
nuclear@19
|
1903 }
|
nuclear@19
|
1904
|
nuclear@19
|
1905
|
nuclear@19
|
1906 void XMLPrinter::PushAttribute( const char* name, double v )
|
nuclear@19
|
1907 {
|
nuclear@19
|
1908 char buf[BUF_SIZE];
|
nuclear@19
|
1909 XMLUtil::ToStr( v, buf, BUF_SIZE );
|
nuclear@19
|
1910 PushAttribute( name, buf );
|
nuclear@19
|
1911 }
|
nuclear@19
|
1912
|
nuclear@19
|
1913
|
nuclear@19
|
1914 void XMLPrinter::CloseElement()
|
nuclear@19
|
1915 {
|
nuclear@19
|
1916 --_depth;
|
nuclear@19
|
1917 const char* name = _stack.Pop();
|
nuclear@19
|
1918
|
nuclear@19
|
1919 if ( _elementJustOpened ) {
|
nuclear@19
|
1920 Print( "/>" );
|
nuclear@19
|
1921 }
|
nuclear@19
|
1922 else {
|
nuclear@19
|
1923 if ( _textDepth < 0 && !_compactMode) {
|
nuclear@19
|
1924 Print( "\n" );
|
nuclear@19
|
1925 PrintSpace( _depth );
|
nuclear@19
|
1926 }
|
nuclear@19
|
1927 Print( "</%s>", name );
|
nuclear@19
|
1928 }
|
nuclear@19
|
1929
|
nuclear@19
|
1930 if ( _textDepth == _depth ) {
|
nuclear@19
|
1931 _textDepth = -1;
|
nuclear@19
|
1932 }
|
nuclear@19
|
1933 if ( _depth == 0 && !_compactMode) {
|
nuclear@19
|
1934 Print( "\n" );
|
nuclear@19
|
1935 }
|
nuclear@19
|
1936 _elementJustOpened = false;
|
nuclear@19
|
1937 }
|
nuclear@19
|
1938
|
nuclear@19
|
1939
|
nuclear@19
|
1940 void XMLPrinter::SealElement()
|
nuclear@19
|
1941 {
|
nuclear@19
|
1942 _elementJustOpened = false;
|
nuclear@19
|
1943 Print( ">" );
|
nuclear@19
|
1944 }
|
nuclear@19
|
1945
|
nuclear@19
|
1946
|
nuclear@19
|
1947 void XMLPrinter::PushText( const char* text, bool cdata )
|
nuclear@19
|
1948 {
|
nuclear@19
|
1949 _textDepth = _depth-1;
|
nuclear@19
|
1950
|
nuclear@19
|
1951 if ( _elementJustOpened ) {
|
nuclear@19
|
1952 SealElement();
|
nuclear@19
|
1953 }
|
nuclear@19
|
1954 if ( cdata ) {
|
nuclear@19
|
1955 Print( "<![CDATA[" );
|
nuclear@19
|
1956 Print( "%s", text );
|
nuclear@19
|
1957 Print( "]]>" );
|
nuclear@19
|
1958 }
|
nuclear@19
|
1959 else {
|
nuclear@19
|
1960 PrintString( text, true );
|
nuclear@19
|
1961 }
|
nuclear@19
|
1962 }
|
nuclear@19
|
1963
|
nuclear@19
|
1964 void XMLPrinter::PushText( int value )
|
nuclear@19
|
1965 {
|
nuclear@19
|
1966 char buf[BUF_SIZE];
|
nuclear@19
|
1967 XMLUtil::ToStr( value, buf, BUF_SIZE );
|
nuclear@19
|
1968 PushText( buf, false );
|
nuclear@19
|
1969 }
|
nuclear@19
|
1970
|
nuclear@19
|
1971
|
nuclear@19
|
1972 void XMLPrinter::PushText( unsigned value )
|
nuclear@19
|
1973 {
|
nuclear@19
|
1974 char buf[BUF_SIZE];
|
nuclear@19
|
1975 XMLUtil::ToStr( value, buf, BUF_SIZE );
|
nuclear@19
|
1976 PushText( buf, false );
|
nuclear@19
|
1977 }
|
nuclear@19
|
1978
|
nuclear@19
|
1979
|
nuclear@19
|
1980 void XMLPrinter::PushText( bool value )
|
nuclear@19
|
1981 {
|
nuclear@19
|
1982 char buf[BUF_SIZE];
|
nuclear@19
|
1983 XMLUtil::ToStr( value, buf, BUF_SIZE );
|
nuclear@19
|
1984 PushText( buf, false );
|
nuclear@19
|
1985 }
|
nuclear@19
|
1986
|
nuclear@19
|
1987
|
nuclear@19
|
1988 void XMLPrinter::PushText( float value )
|
nuclear@19
|
1989 {
|
nuclear@19
|
1990 char buf[BUF_SIZE];
|
nuclear@19
|
1991 XMLUtil::ToStr( value, buf, BUF_SIZE );
|
nuclear@19
|
1992 PushText( buf, false );
|
nuclear@19
|
1993 }
|
nuclear@19
|
1994
|
nuclear@19
|
1995
|
nuclear@19
|
1996 void XMLPrinter::PushText( double value )
|
nuclear@19
|
1997 {
|
nuclear@19
|
1998 char buf[BUF_SIZE];
|
nuclear@19
|
1999 XMLUtil::ToStr( value, buf, BUF_SIZE );
|
nuclear@19
|
2000 PushText( buf, false );
|
nuclear@19
|
2001 }
|
nuclear@19
|
2002
|
nuclear@19
|
2003
|
nuclear@19
|
2004 void XMLPrinter::PushComment( const char* comment )
|
nuclear@19
|
2005 {
|
nuclear@19
|
2006 if ( _elementJustOpened ) {
|
nuclear@19
|
2007 SealElement();
|
nuclear@19
|
2008 }
|
nuclear@19
|
2009 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
|
nuclear@19
|
2010 Print( "\n" );
|
nuclear@19
|
2011 PrintSpace( _depth );
|
nuclear@19
|
2012 }
|
nuclear@19
|
2013 _firstElement = false;
|
nuclear@19
|
2014 Print( "<!--%s-->", comment );
|
nuclear@19
|
2015 }
|
nuclear@19
|
2016
|
nuclear@19
|
2017
|
nuclear@19
|
2018 void XMLPrinter::PushDeclaration( const char* value )
|
nuclear@19
|
2019 {
|
nuclear@19
|
2020 if ( _elementJustOpened ) {
|
nuclear@19
|
2021 SealElement();
|
nuclear@19
|
2022 }
|
nuclear@19
|
2023 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
|
nuclear@19
|
2024 Print( "\n" );
|
nuclear@19
|
2025 PrintSpace( _depth );
|
nuclear@19
|
2026 }
|
nuclear@19
|
2027 _firstElement = false;
|
nuclear@19
|
2028 Print( "<?%s?>", value );
|
nuclear@19
|
2029 }
|
nuclear@19
|
2030
|
nuclear@19
|
2031
|
nuclear@19
|
2032 void XMLPrinter::PushUnknown( const char* value )
|
nuclear@19
|
2033 {
|
nuclear@19
|
2034 if ( _elementJustOpened ) {
|
nuclear@19
|
2035 SealElement();
|
nuclear@19
|
2036 }
|
nuclear@19
|
2037 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
|
nuclear@19
|
2038 Print( "\n" );
|
nuclear@19
|
2039 PrintSpace( _depth );
|
nuclear@19
|
2040 }
|
nuclear@19
|
2041 _firstElement = false;
|
nuclear@19
|
2042 Print( "<!%s>", value );
|
nuclear@19
|
2043 }
|
nuclear@19
|
2044
|
nuclear@19
|
2045
|
nuclear@19
|
2046 bool XMLPrinter::VisitEnter( const XMLDocument& doc )
|
nuclear@19
|
2047 {
|
nuclear@19
|
2048 _processEntities = doc.ProcessEntities();
|
nuclear@19
|
2049 if ( doc.HasBOM() ) {
|
nuclear@19
|
2050 PushHeader( true, false );
|
nuclear@19
|
2051 }
|
nuclear@19
|
2052 return true;
|
nuclear@19
|
2053 }
|
nuclear@19
|
2054
|
nuclear@19
|
2055
|
nuclear@19
|
2056 bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
|
nuclear@19
|
2057 {
|
nuclear@19
|
2058 OpenElement( element.Name() );
|
nuclear@19
|
2059 while ( attribute ) {
|
nuclear@19
|
2060 PushAttribute( attribute->Name(), attribute->Value() );
|
nuclear@19
|
2061 attribute = attribute->Next();
|
nuclear@19
|
2062 }
|
nuclear@19
|
2063 return true;
|
nuclear@19
|
2064 }
|
nuclear@19
|
2065
|
nuclear@19
|
2066
|
nuclear@19
|
2067 bool XMLPrinter::VisitExit( const XMLElement& )
|
nuclear@19
|
2068 {
|
nuclear@19
|
2069 CloseElement();
|
nuclear@19
|
2070 return true;
|
nuclear@19
|
2071 }
|
nuclear@19
|
2072
|
nuclear@19
|
2073
|
nuclear@19
|
2074 bool XMLPrinter::Visit( const XMLText& text )
|
nuclear@19
|
2075 {
|
nuclear@19
|
2076 PushText( text.Value(), text.CData() );
|
nuclear@19
|
2077 return true;
|
nuclear@19
|
2078 }
|
nuclear@19
|
2079
|
nuclear@19
|
2080
|
nuclear@19
|
2081 bool XMLPrinter::Visit( const XMLComment& comment )
|
nuclear@19
|
2082 {
|
nuclear@19
|
2083 PushComment( comment.Value() );
|
nuclear@19
|
2084 return true;
|
nuclear@19
|
2085 }
|
nuclear@19
|
2086
|
nuclear@19
|
2087 bool XMLPrinter::Visit( const XMLDeclaration& declaration )
|
nuclear@19
|
2088 {
|
nuclear@19
|
2089 PushDeclaration( declaration.Value() );
|
nuclear@19
|
2090 return true;
|
nuclear@19
|
2091 }
|
nuclear@19
|
2092
|
nuclear@19
|
2093
|
nuclear@19
|
2094 bool XMLPrinter::Visit( const XMLUnknown& unknown )
|
nuclear@19
|
2095 {
|
nuclear@19
|
2096 PushUnknown( unknown.Value() );
|
nuclear@19
|
2097 return true;
|
nuclear@19
|
2098 }
|
nuclear@19
|
2099
|
nuclear@19
|
2100 } // namespace tinyxml2
|
nuclear@19
|
2101
|