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