~hikiko/nux/arb-srgba-shader

« back to all changes in this revision

Viewing changes to NuxCore/TinyXML/tinyxmlparser.cpp

  • Committer: Neil Jagdish Patel
  • Date: 2010-09-01 19:25:37 UTC
  • Revision ID: neil.patel@canonical.com-20100901192537-mfz7rm6q262pewg6
Import and build NuxCore

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
www.sourceforge.net/projects/tinyxml
 
3
Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com)
 
4
 
 
5
This software is provided 'as-is', without any express or implied 
 
6
warranty. In no event will the authors be held liable for any 
 
7
damages arising from the use of this software.
 
8
 
 
9
Permission is granted to anyone to use this software for any 
 
10
purpose, including commercial applications, and to alter it and 
 
11
redistribute it freely, subject to the following restrictions:
 
12
 
 
13
1. The origin of this software must not be misrepresented; you must 
 
14
not claim that you wrote the original software. If you use this
 
15
software in a product, an acknowledgment in the product documentation
 
16
would be appreciated but is not required.
 
17
 
 
18
2. Altered source versions must be plainly marked as such, and 
 
19
must not be misrepresented as being the original software.
 
20
 
 
21
3. This notice may not be removed or altered from any source 
 
22
distribution.
 
23
*/
 
24
 
 
25
#include <ctype.h>
 
26
#include <stddef.h>
 
27
 
 
28
#include "tinyxml.h"
 
29
 
 
30
//#define DEBUG_PARSER
 
31
#if defined( DEBUG_PARSER )
 
32
#       if defined( DEBUG ) && defined( _MSC_VER )
 
33
#               include <windows.h>
 
34
#               define TIXML_LOG OutputDebugString
 
35
#       else
 
36
#               define TIXML_LOG printf
 
37
#       endif
 
38
#endif
 
39
 
 
40
// Note tha "PutString" hardcodes the same list. This
 
41
// is less flexible than it appears. Changing the entries
 
42
// or order will break putstring.       
 
43
TiXmlBase::Entity TiXmlBase::entity[ NUM_ENTITY ] = 
 
44
{
 
45
        { "&amp;",  5, '&' },
 
46
        { "&lt;",   4, '<' },
 
47
        { "&gt;",   4, '>' },
 
48
        { "&quot;", 6, '\"' },
 
49
        { "&apos;", 6, '\'' }
 
50
};
 
51
 
 
52
// Bunch of unicode info at:
 
53
//              http://www.unicode.org/faq/utf_bom.html
 
54
// Including the basic of this table, which determines the #bytes in the
 
55
// sequence from the lead byte. 1 placed for invalid sequences --
 
56
// although the result will be junk, pass it through as much as possible.
 
57
// Beware of the non-characters in UTF-8:       
 
58
//                              ef bb bf (Microsoft "lead bytes")
 
59
//                              ef bf be
 
60
//                              ef bf bf 
 
61
 
 
62
const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
 
63
const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
 
64
const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
 
65
 
 
66
const int TiXmlBase::utf8ByteTable[256] = 
 
67
{
 
68
        //      0       1       2       3       4       5       6       7       8       9       a       b       c       d       e       f
 
69
                1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      // 0x00
 
70
                1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      // 0x10
 
71
                1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      // 0x20
 
72
                1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      // 0x30
 
73
                1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      // 0x40
 
74
                1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      // 0x50
 
75
                1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      // 0x60
 
76
                1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      // 0x70 End of ASCII range
 
77
                1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      // 0x80 0x80 to 0xc1 invalid
 
78
                1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      // 0x90 
 
79
                1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      // 0xa0 
 
80
                1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      // 0xb0 
 
81
                1,      1,      2,      2,      2,      2,      2,      2,      2,      2,      2,      2,      2,      2,      2,      2,      // 0xc0 0xc2 to 0xdf 2 byte
 
82
                2,      2,      2,      2,      2,      2,      2,      2,      2,      2,      2,      2,      2,      2,      2,      2,      // 0xd0
 
83
                3,      3,      3,      3,      3,      3,      3,      3,      3,      3,      3,      3,      3,      3,      3,      3,      // 0xe0 0xe0 to 0xef 3 byte
 
84
                4,      4,      4,      4,      4,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1       // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid
 
85
};
 
86
 
 
87
 
 
88
void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
 
89
{
 
90
        const unsigned long BYTE_MASK = 0xBF;
 
91
        const unsigned long BYTE_MARK = 0x80;
 
92
        const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
 
93
 
 
94
        if (input < 0x80) 
 
95
                *length = 1;
 
96
        else if ( input < 0x800 )
 
97
                *length = 2;
 
98
        else if ( input < 0x10000 )
 
99
                *length = 3;
 
100
        else if ( input < 0x200000 )
 
101
                *length = 4;
 
102
        else
 
103
                { *length = 0; return; }        // This code won't covert this correctly anyway.
 
104
 
 
105
        output += *length;
 
106
 
 
107
        // Scary scary fall throughs.
 
108
        switch (*length) 
 
109
        {
 
110
                case 4:
 
111
                        --output; 
 
112
                        *output = (char)((input | BYTE_MARK) & BYTE_MASK); 
 
113
                        input >>= 6;
 
114
                case 3:
 
115
                        --output; 
 
116
                        *output = (char)((input | BYTE_MARK) & BYTE_MASK); 
 
117
                        input >>= 6;
 
118
                case 2:
 
119
                        --output; 
 
120
                        *output = (char)((input | BYTE_MARK) & BYTE_MASK); 
 
121
                        input >>= 6;
 
122
                case 1:
 
123
                        --output; 
 
124
                        *output = (char)(input | FIRST_BYTE_MARK[*length]);
 
125
        }
 
126
}
 
127
 
 
128
 
 
129
/*static*/ int TiXmlBase::IsAlpha( unsigned char anyByte, TiXmlEncoding /*encoding*/ )
 
130
{
 
131
        // This will only work for low-ascii, everything else is assumed to be a valid
 
132
        // letter. I'm not sure this is the best approach, but it is quite tricky trying
 
133
        // to figure out alhabetical vs. not across encoding. So take a very 
 
134
        // conservative approach.
 
135
 
 
136
//      if ( encoding == TIXML_ENCODING_UTF8 )
 
137
//      {
 
138
                if ( anyByte < 127 )
 
139
                        return isalpha( anyByte );
 
140
                else
 
141
                        return 1;       // What else to do? The unicode set is huge...get the english ones right.
 
142
//      }
 
143
//      else
 
144
//      {
 
145
//              return isalpha( anyByte );
 
146
//      }
 
147
}
 
148
 
 
149
 
 
150
/*static*/ int TiXmlBase::IsAlphaNum( unsigned char anyByte, TiXmlEncoding /*encoding*/ )
 
151
{
 
152
        // This will only work for low-ascii, everything else is assumed to be a valid
 
153
        // letter. I'm not sure this is the best approach, but it is quite tricky trying
 
154
        // to figure out alhabetical vs. not across encoding. So take a very 
 
155
        // conservative approach.
 
156
 
 
157
//      if ( encoding == TIXML_ENCODING_UTF8 )
 
158
//      {
 
159
                if ( anyByte < 127 )
 
160
                        return isalnum( anyByte );
 
161
                else
 
162
                        return 1;       // What else to do? The unicode set is huge...get the english ones right.
 
163
//      }
 
164
//      else
 
165
//      {
 
166
//              return isalnum( anyByte );
 
167
//      }
 
168
}
 
169
 
 
170
 
 
171
class TiXmlParsingData
 
172
{
 
173
        friend class TiXmlDocument;
 
174
  public:
 
175
        void Stamp( const char* now, TiXmlEncoding encoding );
 
176
 
 
177
        const TiXmlCursor& Cursor()     { return cursor; }
 
178
 
 
179
  private:
 
180
        // Only used by the document!
 
181
        TiXmlParsingData( const char* start, int _tabsize, int row, int col )
 
182
        {
 
183
                assert( start );
 
184
                stamp = start;
 
185
                tabsize = _tabsize;
 
186
                cursor.row = row;
 
187
                cursor.col = col;
 
188
        }
 
189
 
 
190
        TiXmlCursor             cursor;
 
191
        const char*             stamp;
 
192
        int                             tabsize;
 
193
};
 
194
 
 
195
 
 
196
void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding )
 
197
{
 
198
        assert( now );
 
199
 
 
200
        // Do nothing if the tabsize is 0.
 
201
        if ( tabsize < 1 )
 
202
        {
 
203
                return;
 
204
        }
 
205
 
 
206
        // Get the current row, column.
 
207
        int row = cursor.row;
 
208
        int col = cursor.col;
 
209
        const char* p = stamp;
 
210
        assert( p );
 
211
 
 
212
        while ( p < now )
 
213
        {
 
214
                // Treat p as unsigned, so we have a happy compiler.
 
215
                const unsigned char* pU = (const unsigned char*)p;
 
216
 
 
217
                // Code contributed by Fletcher Dunn: (modified by lee)
 
218
                switch (*pU) {
 
219
                        case 0:
 
220
                                // We *should* never get here, but in case we do, don't
 
221
                                // advance past the terminating null character, ever
 
222
                                return;
 
223
 
 
224
                        case '\r':
 
225
                                // bump down to the next line
 
226
                                ++row;
 
227
                                col = 0;                                
 
228
                                // Eat the character
 
229
                                ++p;
 
230
 
 
231
                                // Check for \r\n sequence, and treat this as a single character
 
232
                                if (*p == '\n') {
 
233
                                        ++p;
 
234
                                }
 
235
                                break;
 
236
 
 
237
                        case '\n':
 
238
                                // bump down to the next line
 
239
                                ++row;
 
240
                                col = 0;
 
241
 
 
242
                                // Eat the character
 
243
                                ++p;
 
244
 
 
245
                                // Check for \n\r sequence, and treat this as a single
 
246
                                // character.  (Yes, this bizarre thing does occur still
 
247
                                // on some arcane platforms...)
 
248
                                if (*p == '\r') {
 
249
                                        ++p;
 
250
                                }
 
251
                                break;
 
252
 
 
253
                        case '\t':
 
254
                                // Eat the character
 
255
                                ++p;
 
256
 
 
257
                                // Skip to next tab stop
 
258
                                col = (col / tabsize + 1) * tabsize;
 
259
                                break;
 
260
 
 
261
                        case TIXML_UTF_LEAD_0:
 
262
                                if ( encoding == TIXML_ENCODING_UTF8 )
 
263
                                {
 
264
                                        if ( *(p+1) && *(p+2) )
 
265
                                        {
 
266
                                                // In these cases, don't advance the column. These are
 
267
                                                // 0-width spaces.
 
268
                                                if ( *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 )
 
269
                                                        p += 3; 
 
270
                                                else if ( *(pU+1)==0xbfU && *(pU+2)==0xbeU )
 
271
                                                        p += 3; 
 
272
                                                else if ( *(pU+1)==0xbfU && *(pU+2)==0xbfU )
 
273
                                                        p += 3; 
 
274
                                                else
 
275
                                                        { p +=3; ++col; }       // A normal character.
 
276
                                        }
 
277
                                }
 
278
                                else
 
279
                                {
 
280
                                        ++p;
 
281
                                        ++col;
 
282
                                }
 
283
                                break;
 
284
 
 
285
                        default:
 
286
                                if ( encoding == TIXML_ENCODING_UTF8 )
 
287
                                {
 
288
                                        // Eat the 1 to 4 byte utf8 character.
 
289
                                        int step = TiXmlBase::utf8ByteTable[*((const unsigned char*)p)];
 
290
                                        if ( step == 0 )
 
291
                                                step = 1;               // Error case from bad encoding, but handle gracefully.
 
292
                                        p += step;
 
293
 
 
294
                                        // Just advance one column, of course.
 
295
                                        ++col;
 
296
                                }
 
297
                                else
 
298
                                {
 
299
                                        ++p;
 
300
                                        ++col;
 
301
                                }
 
302
                                break;
 
303
                }
 
304
        }
 
305
        cursor.row = row;
 
306
        cursor.col = col;
 
307
        assert( cursor.row >= -1 );
 
308
        assert( cursor.col >= -1 );
 
309
        stamp = p;
 
310
        assert( stamp );
 
311
}
 
312
 
 
313
 
 
314
const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding )
 
315
{
 
316
        if ( !p || !*p )
 
317
        {
 
318
                return 0;
 
319
        }
 
320
        if ( encoding == TIXML_ENCODING_UTF8 )
 
321
        {
 
322
                while ( *p )
 
323
                {
 
324
                        const unsigned char* pU = (const unsigned char*)p;
 
325
                        
 
326
                        // Skip the stupid Microsoft UTF-8 Byte order marks
 
327
                        if (    *(pU+0)==TIXML_UTF_LEAD_0
 
328
                                 && *(pU+1)==TIXML_UTF_LEAD_1 
 
329
                                 && *(pU+2)==TIXML_UTF_LEAD_2 )
 
330
                        {
 
331
                                p += 3;
 
332
                                continue;
 
333
                        }
 
334
                        else if(*(pU+0)==TIXML_UTF_LEAD_0
 
335
                                 && *(pU+1)==0xbfU
 
336
                                 && *(pU+2)==0xbeU )
 
337
                        {
 
338
                                p += 3;
 
339
                                continue;
 
340
                        }
 
341
                        else if(*(pU+0)==TIXML_UTF_LEAD_0
 
342
                                 && *(pU+1)==0xbfU
 
343
                                 && *(pU+2)==0xbfU )
 
344
                        {
 
345
                                p += 3;
 
346
                                continue;
 
347
                        }
 
348
 
 
349
                        if ( IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' )            // Still using old rules for white space.
 
350
                                ++p;
 
351
                        else
 
352
                                break;
 
353
                }
 
354
        }
 
355
        else
 
356
        {
 
357
                while ( *p && IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' )
 
358
                        ++p;
 
359
        }
 
360
 
 
361
        return p;
 
362
}
 
363
 
 
364
#ifdef TIXML_USE_STL
 
365
/*static*/ bool TiXmlBase::StreamWhiteSpace( std::istream * in, TIXML_STRING * tag )
 
366
{
 
367
        for( ;; )
 
368
        {
 
369
                if ( !in->good() ) return false;
 
370
 
 
371
                int c = in->peek();
 
372
                // At this scope, we can't get to a document. So fail silently.
 
373
                if ( !IsWhiteSpace( c ) || c <= 0 )
 
374
                        return true;
 
375
 
 
376
                *tag += (char) in->get();
 
377
        }
 
378
}
 
379
 
 
380
/*static*/ bool TiXmlBase::StreamTo( std::istream * in, int character, TIXML_STRING * tag )
 
381
{
 
382
        //assert( character > 0 && character < 128 );   // else it won't work in utf-8
 
383
        while ( in->good() )
 
384
        {
 
385
                int c = in->peek();
 
386
                if ( c == character )
 
387
                        return true;
 
388
                if ( c <= 0 )           // Silent failure: can't get document at this scope
 
389
                        return false;
 
390
 
 
391
                in->get();
 
392
                *tag += (char) c;
 
393
        }
 
394
        return false;
 
395
}
 
396
#endif
 
397
 
 
398
// One of TinyXML's more performance demanding functions. Try to keep the memory overhead down. The
 
399
// "assign" optimization removes over 10% of the execution time.
 
400
//
 
401
const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncoding encoding )
 
402
{
 
403
        // Oddly, not supported on some comilers,
 
404
        //name->clear();
 
405
        // So use this:
 
406
        *name = "";
 
407
        assert( p );
 
408
 
 
409
        // Names start with letters or underscores.
 
410
        // Of course, in unicode, tinyxml has no idea what a letter *is*. The
 
411
        // algorithm is generous.
 
412
        //
 
413
        // After that, they can be letters, underscores, numbers,
 
414
        // hyphens, or colons. (Colons are valid ony for namespaces,
 
415
        // but tinyxml can't tell namespaces from names.)
 
416
        if (    p && *p 
 
417
                 && ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) )
 
418
        {
 
419
                const char* start = p;
 
420
                while(          p && *p
 
421
                                &&      (               IsAlphaNum( (unsigned char ) *p, encoding ) 
 
422
                                                 || *p == '_'
 
423
                                                 || *p == '-'
 
424
                                                 || *p == '.'
 
425
                                                 || *p == ':' ) )
 
426
                {
 
427
                        //(*name) += *p; // expensive
 
428
                        ++p;
 
429
                }
 
430
                if ( p-start > 0 ) {
 
431
                        name->assign( start, p-start );
 
432
                }
 
433
                return p;
 
434
        }
 
435
        return 0;
 
436
}
 
437
 
 
438
const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXmlEncoding encoding )
 
439
{
 
440
        // Presume an entity, and pull it out.
 
441
    TIXML_STRING ent;
 
442
        int i;
 
443
        *length = 0;
 
444
 
 
445
        if ( *(p+1) && *(p+1) == '#' && *(p+2) )
 
446
        {
 
447
                unsigned long ucs = 0;
 
448
                ptrdiff_t delta = 0;
 
449
                unsigned mult = 1;
 
450
 
 
451
                if ( *(p+2) == 'x' )
 
452
                {
 
453
                        // Hexadecimal.
 
454
                        if ( !*(p+3) ) return 0;
 
455
 
 
456
                        const char* q = p+3;
 
457
                        q = strchr( q, ';' );
 
458
 
 
459
                        if ( !q || !*q ) return 0;
 
460
 
 
461
                        delta = q-p;
 
462
                        --q;
 
463
 
 
464
                        while ( *q != 'x' )
 
465
                        {
 
466
                                if ( *q >= '0' && *q <= '9' )
 
467
                                        ucs += mult * (*q - '0');
 
468
                                else if ( *q >= 'a' && *q <= 'f' )
 
469
                                        ucs += mult * (*q - 'a' + 10);
 
470
                                else if ( *q >= 'A' && *q <= 'F' )
 
471
                                        ucs += mult * (*q - 'A' + 10 );
 
472
                                else 
 
473
                                        return 0;
 
474
                                mult *= 16;
 
475
                                --q;
 
476
                        }
 
477
                }
 
478
                else
 
479
                {
 
480
                        // Decimal.
 
481
                        if ( !*(p+2) ) return 0;
 
482
 
 
483
                        const char* q = p+2;
 
484
                        q = strchr( q, ';' );
 
485
 
 
486
                        if ( !q || !*q ) return 0;
 
487
 
 
488
                        delta = q-p;
 
489
                        --q;
 
490
 
 
491
                        while ( *q != '#' )
 
492
                        {
 
493
                                if ( *q >= '0' && *q <= '9' )
 
494
                                        ucs += mult * (*q - '0');
 
495
                                else 
 
496
                                        return 0;
 
497
                                mult *= 10;
 
498
                                --q;
 
499
                        }
 
500
                }
 
501
                if ( encoding == TIXML_ENCODING_UTF8 )
 
502
                {
 
503
                        // convert the UCS to UTF-8
 
504
                        ConvertUTF32ToUTF8( ucs, value, length );
 
505
                }
 
506
                else
 
507
                {
 
508
                        *value = (char)ucs;
 
509
                        *length = 1;
 
510
                }
 
511
                return p + delta + 1;
 
512
        }
 
513
 
 
514
        // Now try to match it.
 
515
        for( i=0; i<NUM_ENTITY; ++i )
 
516
        {
 
517
                if ( strncmp( entity[i].str, p, entity[i].strLength ) == 0 )
 
518
                {
 
519
                        assert( strlen( entity[i].str ) == entity[i].strLength );
 
520
                        *value = entity[i].chr;
 
521
                        *length = 1;
 
522
                        return ( p + entity[i].strLength );
 
523
                }
 
524
        }
 
525
 
 
526
        // So it wasn't an entity, its unrecognized, or something like that.
 
527
        *value = *p;    // Don't put back the last one, since we return it!
 
528
        //*length = 1;  // Leave unrecognized entities - this doesn't really work.
 
529
                                        // Just writes strange XML.
 
530
        return p+1;
 
531
}
 
532
 
 
533
 
 
534
bool TiXmlBase::StringEqual( const char* p,
 
535
                                                         const char* tag,
 
536
                                                         bool ignoreCase,
 
537
                                                         TiXmlEncoding encoding )
 
538
{
 
539
        assert( p );
 
540
        assert( tag );
 
541
        if ( !p || !*p )
 
542
        {
 
543
                assert( 0 );
 
544
                return false;
 
545
        }
 
546
 
 
547
        const char* q = p;
 
548
 
 
549
        if ( ignoreCase )
 
550
        {
 
551
                while ( *q && *tag && ToLower( *q, encoding ) == ToLower( *tag, encoding ) )
 
552
                {
 
553
                        ++q;
 
554
                        ++tag;
 
555
                }
 
556
 
 
557
                if ( *tag == 0 )
 
558
                        return true;
 
559
        }
 
560
        else
 
561
        {
 
562
                while ( *q && *tag && *q == *tag )
 
563
                {
 
564
                        ++q;
 
565
                        ++tag;
 
566
                }
 
567
 
 
568
                if ( *tag == 0 )                // Have we found the end of the tag, and everything equal?
 
569
                        return true;
 
570
        }
 
571
        return false;
 
572
}
 
573
 
 
574
const char* TiXmlBase::ReadText(        const char* p, 
 
575
                                                                        TIXML_STRING * text, 
 
576
                                                                        bool trimWhiteSpace, 
 
577
                                                                        const char* endTag, 
 
578
                                                                        bool caseInsensitive,
 
579
                                                                        TiXmlEncoding encoding )
 
580
{
 
581
    *text = "";
 
582
        if (    !trimWhiteSpace                 // certain tags always keep whitespace
 
583
                 || !condenseWhiteSpace )       // if true, whitespace is always kept
 
584
        {
 
585
                // Keep all the white space.
 
586
                while (    p && *p
 
587
                                && !StringEqual( p, endTag, caseInsensitive, encoding )
 
588
                          )
 
589
                {
 
590
                        int len;
 
591
                        char cArr[4] = { 0, 0, 0, 0 };
 
592
                        p = GetChar( p, cArr, &len, encoding );
 
593
                        text->append( cArr, len );
 
594
                }
 
595
        }
 
596
        else
 
597
        {
 
598
                bool whitespace = false;
 
599
 
 
600
                // Remove leading white space:
 
601
                p = SkipWhiteSpace( p, encoding );
 
602
                while (    p && *p
 
603
                                && !StringEqual( p, endTag, caseInsensitive, encoding ) )
 
604
                {
 
605
                        if ( *p == '\r' || *p == '\n' )
 
606
                        {
 
607
                                whitespace = true;
 
608
                                ++p;
 
609
                        }
 
610
                        else if ( IsWhiteSpace( *p ) )
 
611
                        {
 
612
                                whitespace = true;
 
613
                                ++p;
 
614
                        }
 
615
                        else
 
616
                        {
 
617
                                // If we've found whitespace, add it before the
 
618
                                // new character. Any whitespace just becomes a space.
 
619
                                if ( whitespace )
 
620
                                {
 
621
                                        (*text) += ' ';
 
622
                                        whitespace = false;
 
623
                                }
 
624
                                int len;
 
625
                                char cArr[4] = { 0, 0, 0, 0 };
 
626
                                p = GetChar( p, cArr, &len, encoding );
 
627
                                if ( len == 1 )
 
628
                                        (*text) += cArr[0];     // more efficient
 
629
                                else
 
630
                                        text->append( cArr, len );
 
631
                        }
 
632
                }
 
633
        }
 
634
        if ( p ) 
 
635
                p += strlen( endTag );
 
636
        return p;
 
637
}
 
638
 
 
639
#ifdef TIXML_USE_STL
 
640
 
 
641
void TiXmlDocument::StreamIn( std::istream * in, TIXML_STRING * tag )
 
642
{
 
643
        // The basic issue with a document is that we don't know what we're
 
644
        // streaming. Read something presumed to be a tag (and hope), then
 
645
        // identify it, and call the appropriate stream method on the tag.
 
646
        //
 
647
        // This "pre-streaming" will never read the closing ">" so the
 
648
        // sub-tag can orient itself.
 
649
 
 
650
        if ( !StreamTo( in, '<', tag ) ) 
 
651
        {
 
652
                SetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
 
653
                return;
 
654
        }
 
655
 
 
656
        while ( in->good() )
 
657
        {
 
658
                int tagIndex = (int) tag->length();
 
659
                while ( in->good() && in->peek() != '>' )
 
660
                {
 
661
                        int c = in->get();
 
662
                        if ( c <= 0 )
 
663
                        {
 
664
                                SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
 
665
                                break;
 
666
                        }
 
667
                        (*tag) += (char) c;
 
668
                }
 
669
 
 
670
                if ( in->good() )
 
671
                {
 
672
                        // We now have something we presume to be a node of 
 
673
                        // some sort. Identify it, and call the node to
 
674
                        // continue streaming.
 
675
                        TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING );
 
676
 
 
677
                        if ( node )
 
678
                        {
 
679
                                node->StreamIn( in, tag );
 
680
                                bool isElement = node->ToElement() != 0;
 
681
                                delete node;
 
682
                                node = 0;
 
683
 
 
684
                                // If this is the root element, we're done. Parsing will be
 
685
                                // done by the >> operator.
 
686
                                if ( isElement )
 
687
                                {
 
688
                                        return;
 
689
                                }
 
690
                        }
 
691
                        else
 
692
                        {
 
693
                                SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN );
 
694
                                return;
 
695
                        }
 
696
                }
 
697
        }
 
698
        // We should have returned sooner.
 
699
        SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN );
 
700
}
 
701
 
 
702
#endif
 
703
 
 
704
const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiXmlEncoding encoding )
 
705
{
 
706
        ClearError();
 
707
 
 
708
        // Parse away, at the document level. Since a document
 
709
        // contains nothing but other tags, most of what happens
 
710
        // here is skipping white space.
 
711
        if ( !p || !*p )
 
712
        {
 
713
                SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
 
714
                return 0;
 
715
        }
 
716
 
 
717
        // Note that, for a document, this needs to come
 
718
        // before the while space skip, so that parsing
 
719
        // starts from the pointer we are given.
 
720
        location.Clear();
 
721
        if ( prevData )
 
722
        {
 
723
                location.row = prevData->cursor.row;
 
724
                location.col = prevData->cursor.col;
 
725
        }
 
726
        else
 
727
        {
 
728
                location.row = 0;
 
729
                location.col = 0;
 
730
        }
 
731
        TiXmlParsingData data( p, TabSize(), location.row, location.col );
 
732
        location = data.Cursor();
 
733
 
 
734
        if ( encoding == TIXML_ENCODING_UNKNOWN )
 
735
        {
 
736
                // Check for the Microsoft UTF-8 lead bytes.
 
737
                const unsigned char* pU = (const unsigned char*)p;
 
738
                if (    *(pU+0) && *(pU+0) == TIXML_UTF_LEAD_0
 
739
                         && *(pU+1) && *(pU+1) == TIXML_UTF_LEAD_1
 
740
                         && *(pU+2) && *(pU+2) == TIXML_UTF_LEAD_2 )
 
741
                {
 
742
                        encoding = TIXML_ENCODING_UTF8;
 
743
                        useMicrosoftBOM = true;
 
744
                }
 
745
        }
 
746
 
 
747
    p = SkipWhiteSpace( p, encoding );
 
748
        if ( !p )
 
749
        {
 
750
                SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
 
751
                return 0;
 
752
        }
 
753
 
 
754
        while ( p && *p )
 
755
        {
 
756
                TiXmlNode* node = Identify( p, encoding );
 
757
                if ( node )
 
758
                {
 
759
                        p = node->Parse( p, &data, encoding );
 
760
                        LinkEndChild( node );
 
761
                }
 
762
                else
 
763
                {
 
764
                        break;
 
765
                }
 
766
 
 
767
                // Did we get encoding info?
 
768
                if (    encoding == TIXML_ENCODING_UNKNOWN
 
769
                         && node->ToDeclaration() )
 
770
                {
 
771
                        TiXmlDeclaration* dec = node->ToDeclaration();
 
772
                        const char* enc = dec->Encoding();
 
773
                        assert( enc );
 
774
 
 
775
                        if ( *enc == 0 )
 
776
                                encoding = TIXML_ENCODING_UTF8;
 
777
                        else if ( StringEqual( enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN ) )
 
778
                                encoding = TIXML_ENCODING_UTF8;
 
779
                        else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) )
 
780
                                encoding = TIXML_ENCODING_UTF8; // incorrect, but be nice
 
781
                        else 
 
782
                                encoding = TIXML_ENCODING_LEGACY;
 
783
                }
 
784
 
 
785
                p = SkipWhiteSpace( p, encoding );
 
786
        }
 
787
 
 
788
        // Was this empty?
 
789
        if ( !firstChild ) {
 
790
                SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, encoding );
 
791
                return 0;
 
792
        }
 
793
 
 
794
        // All is well.
 
795
        return p;
 
796
}
 
797
 
 
798
void TiXmlDocument::SetError( int err, const char* pError, TiXmlParsingData* data, TiXmlEncoding encoding )
 
799
{       
 
800
        // The first error in a chain is more accurate - don't set again!
 
801
        if ( error )
 
802
                return;
 
803
 
 
804
        assert( err > 0 && err < TIXML_ERROR_STRING_COUNT );
 
805
        error   = true;
 
806
        errorId = err;
 
807
        errorDesc = errorString[ errorId ];
 
808
 
 
809
        errorLocation.Clear();
 
810
        if ( pError && data )
 
811
        {
 
812
                data->Stamp( pError, encoding );
 
813
                errorLocation = data->Cursor();
 
814
        }
 
815
}
 
816
 
 
817
 
 
818
TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding )
 
819
{
 
820
        TiXmlNode* returnNode = 0;
 
821
 
 
822
        p = SkipWhiteSpace( p, encoding );
 
823
        if( !p || !*p || *p != '<' )
 
824
        {
 
825
                return 0;
 
826
        }
 
827
 
 
828
        TiXmlDocument* doc = GetDocument();
 
829
        p = SkipWhiteSpace( p, encoding );
 
830
 
 
831
        if ( !p || !*p )
 
832
        {
 
833
                return 0;
 
834
        }
 
835
 
 
836
        // What is this thing? 
 
837
        // - Elements start with a letter or underscore, but xml is reserved.
 
838
        // - Comments: <!--
 
839
        // - Decleration: <?xml
 
840
        // - Everthing else is unknown to tinyxml.
 
841
        //
 
842
 
 
843
        const char* xmlHeader = { "<?xml" };
 
844
        const char* commentHeader = { "<!--" };
 
845
        const char* dtdHeader = { "<!" };
 
846
        const char* cdataHeader = { "<![CDATA[" };
 
847
 
 
848
        if ( StringEqual( p, xmlHeader, true, encoding ) )
 
849
        {
 
850
                #ifdef DEBUG_PARSER
 
851
                        TIXML_LOG( "XML parsing Declaration\n" );
 
852
                #endif
 
853
                returnNode = new TiXmlDeclaration();
 
854
        }
 
855
        else if ( StringEqual( p, commentHeader, false, encoding ) )
 
856
        {
 
857
                #ifdef DEBUG_PARSER
 
858
                        TIXML_LOG( "XML parsing Comment\n" );
 
859
                #endif
 
860
                returnNode = new TiXmlComment();
 
861
        }
 
862
        else if ( StringEqual( p, cdataHeader, false, encoding ) )
 
863
        {
 
864
                #ifdef DEBUG_PARSER
 
865
                        TIXML_LOG( "XML parsing CDATA\n" );
 
866
                #endif
 
867
                TiXmlText* text = new TiXmlText( "" );
 
868
                text->SetCDATA( true );
 
869
                returnNode = text;
 
870
        }
 
871
        else if ( StringEqual( p, dtdHeader, false, encoding ) )
 
872
        {
 
873
                #ifdef DEBUG_PARSER
 
874
                        TIXML_LOG( "XML parsing Unknown(1)\n" );
 
875
                #endif
 
876
                returnNode = new TiXmlUnknown();
 
877
        }
 
878
        else if (    IsAlpha( *(p+1), encoding )
 
879
                          || *(p+1) == '_' )
 
880
        {
 
881
                #ifdef DEBUG_PARSER
 
882
                        TIXML_LOG( "XML parsing Element\n" );
 
883
                #endif
 
884
                returnNode = new TiXmlElement( "" );
 
885
        }
 
886
        else
 
887
        {
 
888
                #ifdef DEBUG_PARSER
 
889
                        TIXML_LOG( "XML parsing Unknown(2)\n" );
 
890
                #endif
 
891
                returnNode = new TiXmlUnknown();
 
892
        }
 
893
 
 
894
        if ( returnNode )
 
895
        {
 
896
                // Set the parent, so it can report errors
 
897
                returnNode->parent = this;
 
898
        }
 
899
        else
 
900
        {
 
901
                if ( doc )
 
902
                        doc->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN );
 
903
        }
 
904
        return returnNode;
 
905
}
 
906
 
 
907
#ifdef TIXML_USE_STL
 
908
 
 
909
void TiXmlElement::StreamIn (std::istream * in, TIXML_STRING * tag)
 
910
{
 
911
        // We're called with some amount of pre-parsing. That is, some of "this"
 
912
        // element is in "tag". Go ahead and stream to the closing ">"
 
913
        while( in->good() )
 
914
        {
 
915
                int c = in->get();
 
916
                if ( c <= 0 )
 
917
                {
 
918
                        TiXmlDocument* document = GetDocument();
 
919
                        if ( document )
 
920
                                document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
 
921
                        return;
 
922
                }
 
923
                (*tag) += (char) c ;
 
924
                
 
925
                if ( c == '>' )
 
926
                        break;
 
927
        }
 
928
 
 
929
        if ( tag->length() < 3 ) return;
 
930
 
 
931
        // Okay...if we are a "/>" tag, then we're done. We've read a complete tag.
 
932
        // If not, identify and stream.
 
933
 
 
934
        if (    tag->at( tag->length() - 1 ) == '>' 
 
935
                 && tag->at( tag->length() - 2 ) == '/' )
 
936
        {
 
937
                // All good!
 
938
                return;
 
939
        }
 
940
        else if ( tag->at( tag->length() - 1 ) == '>' )
 
941
        {
 
942
                // There is more. Could be:
 
943
                //              text
 
944
                //              cdata text (which looks like another node)
 
945
                //              closing tag
 
946
                //              another node.
 
947
                for ( ;; )
 
948
                {
 
949
                        StreamWhiteSpace( in, tag );
 
950
 
 
951
                        // Do we have text?
 
952
                        if ( in->good() && in->peek() != '<' ) 
 
953
                        {
 
954
                                // Yep, text.
 
955
                                TiXmlText text( "" );
 
956
                                text.StreamIn( in, tag );
 
957
 
 
958
                                // What follows text is a closing tag or another node.
 
959
                                // Go around again and figure it out.
 
960
                                continue;
 
961
                        }
 
962
 
 
963
                        // We now have either a closing tag...or another node.
 
964
                        // We should be at a "<", regardless.
 
965
                        if ( !in->good() ) return;
 
966
                        assert( in->peek() == '<' );
 
967
                        int tagIndex = (int) tag->length();
 
968
 
 
969
                        bool closingTag = false;
 
970
                        bool firstCharFound = false;
 
971
 
 
972
                        for( ;; )
 
973
                        {
 
974
                                if ( !in->good() )
 
975
                                        return;
 
976
 
 
977
                                int c = in->peek();
 
978
                                if ( c <= 0 )
 
979
                                {
 
980
                                        TiXmlDocument* document = GetDocument();
 
981
                                        if ( document )
 
982
                                                document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
 
983
                                        return;
 
984
                                }
 
985
                                
 
986
                                if ( c == '>' )
 
987
                                        break;
 
988
 
 
989
                                *tag += (char) c;
 
990
                                in->get();
 
991
 
 
992
                                // Early out if we find the CDATA id.
 
993
                                if ( c == '[' && tag->size() >= 9 )
 
994
                                {
 
995
                                        size_t len = tag->size();
 
996
                                        const char* start = tag->c_str() + len - 9;
 
997
                                        if ( strcmp( start, "<![CDATA[" ) == 0 ) {
 
998
                                                assert( !closingTag );
 
999
                                                break;
 
1000
                                        }
 
1001
                                }
 
1002
 
 
1003
                                if ( !firstCharFound && c != '<' && !IsWhiteSpace( c ) )
 
1004
                                {
 
1005
                                        firstCharFound = true;
 
1006
                                        if ( c == '/' )
 
1007
                                                closingTag = true;
 
1008
                                }
 
1009
                        }
 
1010
                        // If it was a closing tag, then read in the closing '>' to clean up the input stream.
 
1011
                        // If it was not, the streaming will be done by the tag.
 
1012
                        if ( closingTag )
 
1013
                        {
 
1014
                                if ( !in->good() )
 
1015
                                        return;
 
1016
 
 
1017
                                int c = in->get();
 
1018
                                if ( c <= 0 )
 
1019
                                {
 
1020
                                        TiXmlDocument* document = GetDocument();
 
1021
                                        if ( document )
 
1022
                                                document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
 
1023
                                        return;
 
1024
                                }
 
1025
                                assert( c == '>' );
 
1026
                                *tag += (char) c;
 
1027
 
 
1028
                                // We are done, once we've found our closing tag.
 
1029
                                return;
 
1030
                        }
 
1031
                        else
 
1032
                        {
 
1033
                                // If not a closing tag, id it, and stream.
 
1034
                                const char* tagloc = tag->c_str() + tagIndex;
 
1035
                                TiXmlNode* node = Identify( tagloc, TIXML_DEFAULT_ENCODING );
 
1036
                                if ( !node )
 
1037
                                        return;
 
1038
                                node->StreamIn( in, tag );
 
1039
                                delete node;
 
1040
                                node = 0;
 
1041
 
 
1042
                                // No return: go around from the beginning: text, closing tag, or node.
 
1043
                        }
 
1044
                }
 
1045
        }
 
1046
}
 
1047
#endif
 
1048
 
 
1049
const char* TiXmlElement::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
 
1050
{
 
1051
        p = SkipWhiteSpace( p, encoding );
 
1052
        TiXmlDocument* document = GetDocument();
 
1053
 
 
1054
        if ( !p || !*p )
 
1055
        {
 
1056
                if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, 0, 0, encoding );
 
1057
                return 0;
 
1058
        }
 
1059
 
 
1060
        if ( data )
 
1061
        {
 
1062
                data->Stamp( p, encoding );
 
1063
                location = data->Cursor();
 
1064
        }
 
1065
 
 
1066
        if ( *p != '<' )
 
1067
        {
 
1068
                if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, p, data, encoding );
 
1069
                return 0;
 
1070
        }
 
1071
 
 
1072
        p = SkipWhiteSpace( p+1, encoding );
 
1073
 
 
1074
        // Read the name.
 
1075
        const char* pErr = p;
 
1076
 
 
1077
    p = ReadName( p, &value, encoding );
 
1078
        if ( !p || !*p )
 
1079
        {
 
1080
                if ( document ) document->SetError( TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, pErr, data, encoding );
 
1081
                return 0;
 
1082
        }
 
1083
 
 
1084
    TIXML_STRING endTag ("</");
 
1085
        endTag += value;
 
1086
        endTag += ">";
 
1087
 
 
1088
        // Check for and read attributes. Also look for an empty
 
1089
        // tag or an end tag.
 
1090
        while ( p && *p )
 
1091
        {
 
1092
                pErr = p;
 
1093
                p = SkipWhiteSpace( p, encoding );
 
1094
                if ( !p || !*p )
 
1095
                {
 
1096
                        if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding );
 
1097
                        return 0;
 
1098
                }
 
1099
                if ( *p == '/' )
 
1100
                {
 
1101
                        ++p;
 
1102
                        // Empty tag.
 
1103
                        if ( *p  != '>' )
 
1104
                        {
 
1105
                                if ( document ) document->SetError( TIXML_ERROR_PARSING_EMPTY, p, data, encoding );             
 
1106
                                return 0;
 
1107
                        }
 
1108
                        return (p+1);
 
1109
                }
 
1110
                else if ( *p == '>' )
 
1111
                {
 
1112
                        // Done with attributes (if there were any.)
 
1113
                        // Read the value -- which can include other
 
1114
                        // elements -- read the end tag, and return.
 
1115
                        ++p;
 
1116
                        p = ReadValue( p, data, encoding );             // Note this is an Element method, and will set the error if one happens.
 
1117
                        if ( !p || !*p ) {
 
1118
                                // We were looking for the end tag, but found nothing.
 
1119
                                // Fix for [ 1663758 ] Failure to report error on bad XML
 
1120
                                if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding );
 
1121
                                return 0;
 
1122
                        }
 
1123
 
 
1124
                        // We should find the end tag now
 
1125
                        if ( StringEqual( p, endTag.c_str(), false, encoding ) )
 
1126
                        {
 
1127
                                p += endTag.length();
 
1128
                                return p;
 
1129
                        }
 
1130
                        else
 
1131
                        {
 
1132
                                if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding );
 
1133
                                return 0;
 
1134
                        }
 
1135
                }
 
1136
                else
 
1137
                {
 
1138
                        // Try to read an attribute:
 
1139
                        TiXmlAttribute* attrib = new TiXmlAttribute();
 
1140
                        if ( !attrib )
 
1141
                        {
 
1142
                                if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, pErr, data, encoding );
 
1143
                                return 0;
 
1144
                        }
 
1145
 
 
1146
                        attrib->SetDocument( document );
 
1147
                        pErr = p;
 
1148
                        p = attrib->Parse( p, data, encoding );
 
1149
 
 
1150
                        if ( !p || !*p )
 
1151
                        {
 
1152
                                if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, pErr, data, encoding );
 
1153
                                delete attrib;
 
1154
                                return 0;
 
1155
                        }
 
1156
 
 
1157
                        // Handle the strange case of double attributes:
 
1158
                        #ifdef TIXML_USE_STL
 
1159
                        TiXmlAttribute* node = attributeSet.Find( attrib->NameTStr() );
 
1160
                        #else
 
1161
                        TiXmlAttribute* node = attributeSet.Find( attrib->Name() );
 
1162
                        #endif
 
1163
                        if ( node )
 
1164
                        {
 
1165
                                node->SetValue( attrib->Value() );
 
1166
                                delete attrib;
 
1167
                                return 0;
 
1168
                        }
 
1169
 
 
1170
                        attributeSet.Add( attrib );
 
1171
                }
 
1172
        }
 
1173
        return p;
 
1174
}
 
1175
 
 
1176
 
 
1177
const char* TiXmlElement::ReadValue( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
 
1178
{
 
1179
        TiXmlDocument* document = GetDocument();
 
1180
 
 
1181
        // Read in text and elements in any order.
 
1182
        const char* pWithWhiteSpace = p;
 
1183
        p = SkipWhiteSpace( p, encoding );
 
1184
 
 
1185
        while ( p && *p )
 
1186
        {
 
1187
                if ( *p != '<' )
 
1188
                {
 
1189
                        // Take what we have, make a text element.
 
1190
                        TiXmlText* textNode = new TiXmlText( "" );
 
1191
 
 
1192
                        if ( !textNode )
 
1193
                        {
 
1194
                                if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, encoding );
 
1195
                                    return 0;
 
1196
                        }
 
1197
 
 
1198
                        if ( TiXmlBase::IsWhiteSpaceCondensed() )
 
1199
                        {
 
1200
                                p = textNode->Parse( p, data, encoding );
 
1201
                        }
 
1202
                        else
 
1203
                        {
 
1204
                                // Special case: we want to keep the white space
 
1205
                                // so that leading spaces aren't removed.
 
1206
                                p = textNode->Parse( pWithWhiteSpace, data, encoding );
 
1207
                        }
 
1208
 
 
1209
                        if ( !textNode->Blank() )
 
1210
                                LinkEndChild( textNode );
 
1211
                        else
 
1212
                                delete textNode;
 
1213
                } 
 
1214
                else 
 
1215
                {
 
1216
                        // We hit a '<'
 
1217
                        // Have we hit a new element or an end tag? This could also be
 
1218
                        // a TiXmlText in the "CDATA" style.
 
1219
                        if ( StringEqual( p, "</", false, encoding ) )
 
1220
                        {
 
1221
                                return p;
 
1222
                        }
 
1223
                        else
 
1224
                        {
 
1225
                                TiXmlNode* node = Identify( p, encoding );
 
1226
                                if ( node )
 
1227
                                {
 
1228
                                        p = node->Parse( p, data, encoding );
 
1229
                                        LinkEndChild( node );
 
1230
                                }                               
 
1231
                                else
 
1232
                                {
 
1233
                                        return 0;
 
1234
                                }
 
1235
                        }
 
1236
                }
 
1237
                pWithWhiteSpace = p;
 
1238
                p = SkipWhiteSpace( p, encoding );
 
1239
        }
 
1240
 
 
1241
        if ( !p )
 
1242
        {
 
1243
                if ( document ) document->SetError( TIXML_ERROR_READING_ELEMENT_VALUE, 0, 0, encoding );
 
1244
        }       
 
1245
        return p;
 
1246
}
 
1247
 
 
1248
 
 
1249
#ifdef TIXML_USE_STL
 
1250
void TiXmlUnknown::StreamIn( std::istream * in, TIXML_STRING * tag )
 
1251
{
 
1252
        while ( in->good() )
 
1253
        {
 
1254
                int c = in->get();      
 
1255
                if ( c <= 0 )
 
1256
                {
 
1257
                        TiXmlDocument* document = GetDocument();
 
1258
                        if ( document )
 
1259
                                document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
 
1260
                        return;
 
1261
                }
 
1262
                (*tag) += (char) c;
 
1263
 
 
1264
                if ( c == '>' )
 
1265
                {
 
1266
                        // All is well.
 
1267
                        return;         
 
1268
                }
 
1269
        }
 
1270
}
 
1271
#endif
 
1272
 
 
1273
 
 
1274
const char* TiXmlUnknown::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
 
1275
{
 
1276
        TiXmlDocument* document = GetDocument();
 
1277
        p = SkipWhiteSpace( p, encoding );
 
1278
 
 
1279
        if ( data )
 
1280
        {
 
1281
                data->Stamp( p, encoding );
 
1282
                location = data->Cursor();
 
1283
        }
 
1284
        if ( !p || !*p || *p != '<' )
 
1285
        {
 
1286
                if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, p, data, encoding );
 
1287
                return 0;
 
1288
        }
 
1289
        ++p;
 
1290
    value = "";
 
1291
 
 
1292
        while ( p && *p && *p != '>' )
 
1293
        {
 
1294
                value += *p;
 
1295
                ++p;
 
1296
        }
 
1297
 
 
1298
        if ( !p )
 
1299
        {
 
1300
                if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, 0, 0, encoding );
 
1301
        }
 
1302
        if ( *p == '>' )
 
1303
                return p+1;
 
1304
        return p;
 
1305
}
 
1306
 
 
1307
#ifdef TIXML_USE_STL
 
1308
void TiXmlComment::StreamIn( std::istream * in, TIXML_STRING * tag )
 
1309
{
 
1310
        while ( in->good() )
 
1311
        {
 
1312
                int c = in->get();      
 
1313
                if ( c <= 0 )
 
1314
                {
 
1315
                        TiXmlDocument* document = GetDocument();
 
1316
                        if ( document )
 
1317
                                document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
 
1318
                        return;
 
1319
                }
 
1320
 
 
1321
                (*tag) += (char) c;
 
1322
 
 
1323
                if ( c == '>' 
 
1324
                         && tag->at( tag->length() - 2 ) == '-'
 
1325
                         && tag->at( tag->length() - 3 ) == '-' )
 
1326
                {
 
1327
                        // All is well.
 
1328
                        return;         
 
1329
                }
 
1330
        }
 
1331
}
 
1332
#endif
 
1333
 
 
1334
 
 
1335
const char* TiXmlComment::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
 
1336
{
 
1337
        TiXmlDocument* document = GetDocument();
 
1338
        value = "";
 
1339
 
 
1340
        p = SkipWhiteSpace( p, encoding );
 
1341
 
 
1342
        if ( data )
 
1343
        {
 
1344
                data->Stamp( p, encoding );
 
1345
                location = data->Cursor();
 
1346
        }
 
1347
        const char* startTag = "<!--";
 
1348
        const char* endTag   = "-->";
 
1349
 
 
1350
        if ( !StringEqual( p, startTag, false, encoding ) )
 
1351
        {
 
1352
                document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding );
 
1353
                return 0;
 
1354
        }
 
1355
        p += strlen( startTag );
 
1356
 
 
1357
        // [ 1475201 ] TinyXML parses entities in comments
 
1358
        // Oops - ReadText doesn't work, because we don't want to parse the entities.
 
1359
        // p = ReadText( p, &value, false, endTag, false, encoding );
 
1360
        //
 
1361
        // from the XML spec:
 
1362
        /*
 
1363
         [Definition: Comments may appear anywhere in a document outside other markup; in addition, 
 
1364
                      they may appear within the document type declaration at places allowed by the grammar. 
 
1365
                                  They are not part of the document's character data; an XML processor MAY, but need not, 
 
1366
                                  make it possible for an application to retrieve the text of comments. For compatibility, 
 
1367
                                  the string "--" (double-hyphen) MUST NOT occur within comments.] Parameter entity 
 
1368
                                  references MUST NOT be recognized within comments.
 
1369
 
 
1370
                                  An example of a comment:
 
1371
 
 
1372
                                  <!-- declarations for <head> & <body> -->
 
1373
        */
 
1374
 
 
1375
    value = "";
 
1376
        // Keep all the white space.
 
1377
        while ( p && *p && !StringEqual( p, endTag, false, encoding ) )
 
1378
        {
 
1379
                value.append( p, 1 );
 
1380
                ++p;
 
1381
        }
 
1382
        if ( p ) 
 
1383
                p += strlen( endTag );
 
1384
 
 
1385
        return p;
 
1386
}
 
1387
 
 
1388
 
 
1389
const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
 
1390
{
 
1391
        p = SkipWhiteSpace( p, encoding );
 
1392
        if ( !p || !*p ) return 0;
 
1393
 
 
1394
//      int tabsize = 4;
 
1395
//      if ( document )
 
1396
//              tabsize = document->TabSize();
 
1397
 
 
1398
        if ( data )
 
1399
        {
 
1400
                data->Stamp( p, encoding );
 
1401
                location = data->Cursor();
 
1402
        }
 
1403
        // Read the name, the '=' and the value.
 
1404
        const char* pErr = p;
 
1405
        p = ReadName( p, &name, encoding );
 
1406
        if ( !p || !*p )
 
1407
        {
 
1408
                if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding );
 
1409
                return 0;
 
1410
        }
 
1411
        p = SkipWhiteSpace( p, encoding );
 
1412
        if ( !p || !*p || *p != '=' )
 
1413
        {
 
1414
                if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );
 
1415
                return 0;
 
1416
        }
 
1417
 
 
1418
        ++p;    // skip '='
 
1419
        p = SkipWhiteSpace( p, encoding );
 
1420
        if ( !p || !*p )
 
1421
        {
 
1422
                if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );
 
1423
                return 0;
 
1424
        }
 
1425
        
 
1426
        const char* end;
 
1427
        const char SINGLE_QUOTE = '\'';
 
1428
        const char DOUBLE_QUOTE = '\"';
 
1429
 
 
1430
        if ( *p == SINGLE_QUOTE )
 
1431
        {
 
1432
                ++p;
 
1433
                end = "\'";             // single quote in string
 
1434
                p = ReadText( p, &value, false, end, false, encoding );
 
1435
        }
 
1436
        else if ( *p == DOUBLE_QUOTE )
 
1437
        {
 
1438
                ++p;
 
1439
                end = "\"";             // double quote in string
 
1440
                p = ReadText( p, &value, false, end, false, encoding );
 
1441
        }
 
1442
        else
 
1443
        {
 
1444
                // All attribute values should be in single or double quotes.
 
1445
                // But this is such a common error that the parser will try
 
1446
                // its best, even without them.
 
1447
                value = "";
 
1448
                while (    p && *p                                                                                      // existence
 
1449
                                && !IsWhiteSpace( *p ) && *p != '\n' && *p != '\r'      // whitespace
 
1450
                                && *p != '/' && *p != '>' )                                                     // tag end
 
1451
                {
 
1452
                        if ( *p == SINGLE_QUOTE || *p == DOUBLE_QUOTE ) {
 
1453
                                // [ 1451649 ] Attribute values with trailing quotes not handled correctly
 
1454
                                // We did not have an opening quote but seem to have a 
 
1455
                                // closing one. Give up and throw an error.
 
1456
                                if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );
 
1457
                                return 0;
 
1458
                        }
 
1459
                        value += *p;
 
1460
                        ++p;
 
1461
                }
 
1462
        }
 
1463
        return p;
 
1464
}
 
1465
 
 
1466
#ifdef TIXML_USE_STL
 
1467
void TiXmlText::StreamIn( std::istream * in, TIXML_STRING * tag )
 
1468
{
 
1469
        while ( in->good() )
 
1470
        {
 
1471
                int c = in->peek();     
 
1472
                if ( !cdata && (c == '<' ) ) 
 
1473
                {
 
1474
                        return;
 
1475
                }
 
1476
                if ( c <= 0 )
 
1477
                {
 
1478
                        TiXmlDocument* document = GetDocument();
 
1479
                        if ( document )
 
1480
                                document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
 
1481
                        return;
 
1482
                }
 
1483
 
 
1484
                (*tag) += (char) c;
 
1485
                in->get();      // "commits" the peek made above
 
1486
 
 
1487
                if ( cdata && c == '>' && tag->size() >= 3 ) {
 
1488
                        size_t len = tag->size();
 
1489
                        if ( (*tag)[len-2] == ']' && (*tag)[len-3] == ']' ) {
 
1490
                                // terminator of cdata.
 
1491
                                return;
 
1492
                        }
 
1493
                }    
 
1494
        }
 
1495
}
 
1496
#endif
 
1497
 
 
1498
const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
 
1499
{
 
1500
        value = "";
 
1501
        TiXmlDocument* document = GetDocument();
 
1502
 
 
1503
        if ( data )
 
1504
        {
 
1505
                data->Stamp( p, encoding );
 
1506
                location = data->Cursor();
 
1507
        }
 
1508
 
 
1509
        const char* const startTag = "<![CDATA[";
 
1510
        const char* const endTag   = "]]>";
 
1511
 
 
1512
        if ( cdata || StringEqual( p, startTag, false, encoding ) )
 
1513
        {
 
1514
                cdata = true;
 
1515
 
 
1516
                if ( !StringEqual( p, startTag, false, encoding ) )
 
1517
                {
 
1518
                        document->SetError( TIXML_ERROR_PARSING_CDATA, p, data, encoding );
 
1519
                        return 0;
 
1520
                }
 
1521
                p += strlen( startTag );
 
1522
 
 
1523
                // Keep all the white space, ignore the encoding, etc.
 
1524
                while (    p && *p
 
1525
                                && !StringEqual( p, endTag, false, encoding )
 
1526
                          )
 
1527
                {
 
1528
                        value += *p;
 
1529
                        ++p;
 
1530
                }
 
1531
 
 
1532
                TIXML_STRING dummy; 
 
1533
                p = ReadText( p, &dummy, false, endTag, false, encoding );
 
1534
                return p;
 
1535
        }
 
1536
        else
 
1537
        {
 
1538
                bool ignoreWhite = true;
 
1539
 
 
1540
                const char* end = "<";
 
1541
                p = ReadText( p, &value, ignoreWhite, end, false, encoding );
 
1542
                if ( p )
 
1543
                        return p-1;     // don't truncate the '<'
 
1544
                return 0;
 
1545
        }
 
1546
}
 
1547
 
 
1548
#ifdef TIXML_USE_STL
 
1549
void TiXmlDeclaration::StreamIn( std::istream * in, TIXML_STRING * tag )
 
1550
{
 
1551
        while ( in->good() )
 
1552
        {
 
1553
                int c = in->get();
 
1554
                if ( c <= 0 )
 
1555
                {
 
1556
                        TiXmlDocument* document = GetDocument();
 
1557
                        if ( document )
 
1558
                                document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
 
1559
                        return;
 
1560
                }
 
1561
                (*tag) += (char) c;
 
1562
 
 
1563
                if ( c == '>' )
 
1564
                {
 
1565
                        // All is well.
 
1566
                        return;
 
1567
                }
 
1568
        }
 
1569
}
 
1570
#endif
 
1571
 
 
1572
const char* TiXmlDeclaration::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding )
 
1573
{
 
1574
        p = SkipWhiteSpace( p, _encoding );
 
1575
        // Find the beginning, find the end, and look for
 
1576
        // the stuff in-between.
 
1577
        TiXmlDocument* document = GetDocument();
 
1578
        if ( !p || !*p || !StringEqual( p, "<?xml", true, _encoding ) )
 
1579
        {
 
1580
                if ( document ) document->SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding );
 
1581
                return 0;
 
1582
        }
 
1583
        if ( data )
 
1584
        {
 
1585
                data->Stamp( p, _encoding );
 
1586
                location = data->Cursor();
 
1587
        }
 
1588
        p += 5;
 
1589
 
 
1590
        version = "";
 
1591
        encoding = "";
 
1592
        standalone = "";
 
1593
 
 
1594
        while ( p && *p )
 
1595
        {
 
1596
                if ( *p == '>' )
 
1597
                {
 
1598
                        ++p;
 
1599
                        return p;
 
1600
                }
 
1601
 
 
1602
                p = SkipWhiteSpace( p, _encoding );
 
1603
                if ( StringEqual( p, "version", true, _encoding ) )
 
1604
                {
 
1605
                        TiXmlAttribute attrib;
 
1606
                        p = attrib.Parse( p, data, _encoding );         
 
1607
                        version = attrib.Value();
 
1608
                }
 
1609
                else if ( StringEqual( p, "encoding", true, _encoding ) )
 
1610
                {
 
1611
                        TiXmlAttribute attrib;
 
1612
                        p = attrib.Parse( p, data, _encoding );         
 
1613
                        encoding = attrib.Value();
 
1614
                }
 
1615
                else if ( StringEqual( p, "standalone", true, _encoding ) )
 
1616
                {
 
1617
                        TiXmlAttribute attrib;
 
1618
                        p = attrib.Parse( p, data, _encoding );         
 
1619
                        standalone = attrib.Value();
 
1620
                }
 
1621
                else
 
1622
                {
 
1623
                        // Read over whatever it is.
 
1624
                        while( p && *p && *p != '>' && !IsWhiteSpace( *p ) )
 
1625
                                ++p;
 
1626
                }
 
1627
        }
 
1628
        return 0;
 
1629
}
 
1630
 
 
1631
bool TiXmlText::Blank() const
 
1632
{
 
1633
        for ( unsigned i=0; i<value.length(); i++ )
 
1634
                if ( !IsWhiteSpace( value[i] ) )
 
1635
                        return false;
 
1636
        return true;
 
1637
}
 
1638