~ubuntu-branches/debian/sid/ember/sid

« back to all changes in this revision

Viewing changes to src/framework/tinyxml/tinyxmlparser.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michael Koch
  • Date: 2009-07-23 07:46:40 UTC
  • Revision ID: james.westby@ubuntu.com-20090723074640-wh0ukzis0kda36qv
Tags: upstream-0.5.6
ImportĀ upstreamĀ versionĀ 0.5.6

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