Coverage Report

Created: 2025-08-26 06:29

/src/behaviortreecpp/3rdparty/tinyxml2/tinyxml2.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
Original code by Lee Thomason (www.grinninglizard.com)
3
4
This software is provided 'as-is', without any express or implied
5
warranty. In no event will the authors be held liable for any
6
damages arising from the use of this software.
7
8
Permission is granted to anyone to use this software for any
9
purpose, including commercial applications, and to alter it and
10
redistribute it freely, subject to the following restrictions:
11
12
1. The origin of this software must not be misrepresented; you must
13
not claim that you wrote the original software. If you use this
14
software in a product, an acknowledgment in the product documentation
15
would be appreciated but is not required.
16
17
2. Altered source versions must be plainly marked as such, and
18
must not be misrepresented as being the original software.
19
20
3. This notice may not be removed or altered from any source
21
distribution.
22
*/
23
24
#include "tinyxml2.h"
25
26
#include <new>    // yes, this one new style header, is in the Android SDK.
27
#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)
28
#   include <stddef.h>
29
#   include <stdarg.h>
30
#else
31
#   include <cstddef>
32
#   include <cstdarg>
33
#endif
34
35
#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
36
  // Microsoft Visual Studio, version 2005 and higher. Not WinCE.
37
  /*int _snprintf_s(
38
     char *buffer,
39
     size_t sizeOfBuffer,
40
     size_t count,
41
     const char *format [,
42
      argument] ...
43
  );*/
44
  static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
45
  {
46
    va_list va;
47
    va_start( va, format );
48
    const int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
49
    va_end( va );
50
    return result;
51
  }
52
53
  static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va )
54
  {
55
    const int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
56
    return result;
57
  }
58
59
  #define TIXML_VSCPRINTF _vscprintf
60
  #define TIXML_SSCANF  sscanf_s
61
#elif defined _MSC_VER
62
  // Microsoft Visual Studio 2003 and earlier or WinCE
63
  #define TIXML_SNPRINTF  _snprintf
64
  #define TIXML_VSNPRINTF _vsnprintf
65
  #define TIXML_SSCANF  sscanf
66
  #if (_MSC_VER < 1400 ) && (!defined WINCE)
67
    // Microsoft Visual Studio 2003 and not WinCE.
68
    #define TIXML_VSCPRINTF   _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have.
69
  #else
70
    // Microsoft Visual Studio 2003 and earlier or WinCE.
71
    static inline int TIXML_VSCPRINTF( const char* format, va_list va )
72
    {
73
      int len = 512;
74
      for (;;) {
75
        len = len*2;
76
        char* str = new char[len]();
77
        const int required = _vsnprintf(str, len, format, va);
78
        delete[] str;
79
        if ( required != -1 ) {
80
          TIXMLASSERT( required >= 0 );
81
          len = required;
82
          break;
83
        }
84
      }
85
      TIXMLASSERT( len >= 0 );
86
      return len;
87
    }
88
  #endif
89
#else
90
  // GCC version 3 and higher
91
  //#warning( "Using sn* functions." )
92
1.87k
  #define TIXML_SNPRINTF  snprintf
93
554
  #define TIXML_VSNPRINTF vsnprintf
94
  static inline int TIXML_VSCPRINTF( const char* format, va_list va )
95
0
  {
96
0
    int len = vsnprintf( 0, 0, format, va );
97
0
    TIXMLASSERT( len >= 0 );
98
0
    return len;
99
0
  }
100
0
  #define TIXML_SSCANF   sscanf
101
#endif
102
103
#if defined(_WIN64)
104
  #define TIXML_FSEEK _fseeki64
105
  #define TIXML_FTELL _ftelli64
106
#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__CYGWIN__)
107
  #define TIXML_FSEEK fseeko
108
  #define TIXML_FTELL ftello
109
#elif defined(__ANDROID__) 
110
    #if __ANDROID_API__ > 24
111
        #define TIXML_FSEEK fseeko64
112
        #define TIXML_FTELL ftello64
113
    #else
114
        #define TIXML_FSEEK fseeko
115
        #define TIXML_FTELL ftello
116
    #endif
117
#else
118
0
  #define TIXML_FSEEK fseek
119
0
  #define TIXML_FTELL ftell
120
#endif
121
122
123
static const char LINE_FEED       = static_cast<char>(0x0a);      // all line endings are normalized to LF
124
static const char LF = LINE_FEED;
125
static const char CARRIAGE_RETURN   = static_cast<char>(0x0d);      // CR gets filtered out
126
static const char CR = CARRIAGE_RETURN;
127
static const char SINGLE_QUOTE      = '\'';
128
static const char DOUBLE_QUOTE      = '\"';
129
130
// Bunch of unicode info at:
131
//    http://www.unicode.org/faq/utf_bom.html
132
//  ef bb bf (Microsoft "lead bytes") - designates UTF-8
133
134
static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
135
static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
136
static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
137
138
namespace tinyxml2
139
{
140
141
struct Entity {
142
    const char* pattern;
143
    int length;
144
    char value;
145
};
146
147
static const int NUM_ENTITIES = 5;
148
static const Entity entities[NUM_ENTITIES] = {
149
    { "quot", 4,  DOUBLE_QUOTE },
150
    { "amp", 3,   '&'  },
151
    { "apos", 4,  SINGLE_QUOTE },
152
    { "lt", 2,    '<'  },
153
    { "gt", 2,    '>'  }
154
};
155
156
157
StrPair::~StrPair()
158
20.8M
{
159
20.8M
    Reset();
160
20.8M
}
161
162
163
void StrPair::TransferTo( StrPair* other )
164
1.25M
{
165
1.25M
    if ( this == other ) {
166
0
        return;
167
0
    }
168
    // This in effect implements the assignment operator by "moving"
169
    // ownership (as in auto_ptr).
170
171
1.25M
    TIXMLASSERT( other != 0 );
172
1.25M
    TIXMLASSERT( other->_flags == 0 );
173
1.25M
    TIXMLASSERT( other->_start == 0 );
174
1.25M
    TIXMLASSERT( other->_end == 0 );
175
176
1.25M
    other->Reset();
177
178
1.25M
    other->_flags = _flags;
179
1.25M
    other->_start = _start;
180
1.25M
    other->_end = _end;
181
182
1.25M
    _flags = 0;
183
1.25M
    _start = 0;
184
1.25M
    _end = 0;
185
1.25M
}
186
187
188
void StrPair::Reset()
189
32.9M
{
190
32.9M
    if ( _flags & NEEDS_DELETE ) {
191
1.32k
        delete [] _start;
192
1.32k
    }
193
32.9M
    _flags = 0;
194
32.9M
    _start = 0;
195
32.9M
    _end = 0;
196
32.9M
}
197
198
199
void StrPair::SetStr( const char* str, int flags )
200
1.32k
{
201
1.32k
    TIXMLASSERT( str );
202
1.32k
    Reset();
203
1.32k
    size_t len = strlen( str );
204
1.32k
    TIXMLASSERT( _start == 0 );
205
1.32k
    _start = new char[ len+1 ];
206
1.32k
    memcpy( _start, str, len+1 );
207
1.32k
    _end = _start + len;
208
1.32k
    _flags = flags | NEEDS_DELETE;
209
1.32k
}
210
211
212
char* StrPair::ParseText( char* p, const char* endTag, int strFlags, int* curLineNumPtr )
213
6.61M
{
214
6.61M
    TIXMLASSERT( p );
215
6.61M
    TIXMLASSERT( endTag && *endTag );
216
6.61M
  TIXMLASSERT(curLineNumPtr);
217
218
6.61M
    char* start = p;
219
6.61M
    const char  endChar = *endTag;
220
6.61M
    size_t length = strlen( endTag );
221
222
    // Inner loop of text parsing.
223
20.5M
    while ( *p ) {
224
20.5M
        if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
225
6.61M
            Set( start, p, strFlags );
226
6.61M
            return p + length;
227
13.9M
        } else if (*p == '\n') {
228
1.02M
            ++(*curLineNumPtr);
229
1.02M
        }
230
13.9M
        ++p;
231
13.9M
        TIXMLASSERT( p );
232
13.9M
    }
233
516
    return 0;
234
6.61M
}
235
236
237
char* StrPair::ParseName( char* p )
238
4.13M
{
239
4.13M
    if ( !p || !(*p) ) {
240
41
        return 0;
241
41
    }
242
4.13M
    if ( !XMLUtil::IsNameStartChar( (unsigned char) *p ) ) {
243
42
        return 0;
244
42
    }
245
246
4.13M
    char* const start = p;
247
4.13M
    ++p;
248
13.8M
    while ( *p && XMLUtil::IsNameChar( (unsigned char) *p ) ) {
249
9.66M
        ++p;
250
9.66M
    }
251
252
4.13M
    Set( start, p, 0 );
253
4.13M
    return p;
254
4.13M
}
255
256
257
void StrPair::CollapseWhitespace()
258
0
{
259
    // Adjusting _start would cause undefined behavior on delete[]
260
0
    TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
261
    // Trim leading space.
262
0
    _start = XMLUtil::SkipWhiteSpace( _start, 0 );
263
264
0
    if ( *_start ) {
265
0
        const char* p = _start; // the read pointer
266
0
        char* q = _start; // the write pointer
267
268
0
        while( *p ) {
269
0
            if ( XMLUtil::IsWhiteSpace( *p )) {
270
0
                p = XMLUtil::SkipWhiteSpace( p, 0 );
271
0
                if ( *p == 0 ) {
272
0
                    break;    // don't write to q; this trims the trailing space.
273
0
                }
274
0
                *q = ' ';
275
0
                ++q;
276
0
            }
277
0
            *q = *p;
278
0
            ++q;
279
0
            ++p;
280
0
        }
281
0
        *q = 0;
282
0
    }
283
0
}
284
285
286
const char* StrPair::GetStr()
287
6.59M
{
288
6.59M
    TIXMLASSERT( _start );
289
6.59M
    TIXMLASSERT( _end );
290
6.59M
    if ( _flags & NEEDS_FLUSH ) {
291
5.43M
        *_end = 0;
292
5.43M
        _flags ^= NEEDS_FLUSH;
293
294
5.43M
        if ( _flags ) {
295
2.33M
            const char* p = _start; // the read pointer
296
2.33M
            char* q = _start; // the write pointer
297
298
6.89M
            while( p < _end ) {
299
4.56M
                if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
300
                    // CR-LF pair becomes LF
301
                    // CR alone becomes LF
302
                    // LF-CR becomes LF
303
6.92k
                    if ( *(p+1) == LF ) {
304
201
                        p += 2;
305
201
                    }
306
6.72k
                    else {
307
6.72k
                        ++p;
308
6.72k
                    }
309
6.92k
                    *q = LF;
310
6.92k
                    ++q;
311
6.92k
                }
312
4.55M
                else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
313
3.43k
                    if ( *(p+1) == CR ) {
314
323
                        p += 2;
315
323
                    }
316
3.11k
                    else {
317
3.11k
                        ++p;
318
3.11k
                    }
319
3.43k
                    *q = LF;
320
3.43k
                    ++q;
321
3.43k
                }
322
4.55M
                else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
323
                    // Entities handled by tinyXML2:
324
                    // - special entities in the entity table [in/out]
325
                    // - numeric character reference [in]
326
                    //   &#20013; or &#x4e2d;
327
328
46.2k
                    if ( *(p+1) == '#' ) {
329
6.36k
                        const int buflen = 10;
330
6.36k
                        char buf[buflen] = { 0 };
331
6.36k
                        int len = 0;
332
6.36k
                        const char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
333
6.36k
                        if ( adjusted == 0 ) {
334
4.11k
                            *q = *p;
335
4.11k
                            ++p;
336
4.11k
                            ++q;
337
4.11k
                        }
338
2.25k
                        else {
339
2.25k
                            TIXMLASSERT( 0 <= len && len <= buflen );
340
2.25k
                            TIXMLASSERT( q + len <= adjusted );
341
2.25k
                            p = adjusted;
342
2.25k
                            memcpy( q, buf, len );
343
2.25k
                            q += len;
344
2.25k
                        }
345
6.36k
                    }
346
39.8k
                    else {
347
39.8k
                        bool entityFound = false;
348
227k
                        for( int i = 0; i < NUM_ENTITIES; ++i ) {
349
194k
                            const Entity& entity = entities[i];
350
194k
                            if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
351
194k
                                    && *( p + entity.length + 1 ) == ';' ) {
352
                                // Found an entity - convert.
353
6.18k
                                *q = entity.value;
354
6.18k
                                ++q;
355
6.18k
                                p += entity.length + 2;
356
6.18k
                                entityFound = true;
357
6.18k
                                break;
358
6.18k
                            }
359
194k
                        }
360
39.8k
                        if ( !entityFound ) {
361
                            // fixme: treat as error?
362
33.6k
                            ++p;
363
33.6k
                            ++q;
364
33.6k
                        }
365
39.8k
                    }
366
46.2k
                }
367
4.50M
                else {
368
4.50M
                    *q = *p;
369
4.50M
                    ++p;
370
4.50M
                    ++q;
371
4.50M
                }
372
4.56M
            }
373
2.33M
            *q = 0;
374
2.33M
        }
375
        // The loop below has plenty going on, and this
376
        // is a less useful mode. Break it out.
377
5.43M
        if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
378
0
            CollapseWhitespace();
379
0
        }
380
5.43M
        _flags = (_flags & NEEDS_DELETE);
381
5.43M
    }
382
6.59M
    TIXMLASSERT( _start );
383
6.59M
    return _start;
384
6.59M
}
385
386
387
388
389
// --------- XMLUtil ----------- //
390
391
const char* XMLUtil::writeBoolTrue  = "true";
392
const char* XMLUtil::writeBoolFalse = "false";
393
394
void XMLUtil::SetBoolSerialization(const char* writeTrue, const char* writeFalse)
395
0
{
396
0
  static const char* defTrue  = "true";
397
0
  static const char* defFalse = "false";
398
399
0
  writeBoolTrue = (writeTrue) ? writeTrue : defTrue;
400
0
  writeBoolFalse = (writeFalse) ? writeFalse : defFalse;
401
0
}
402
403
404
const char* XMLUtil::ReadBOM( const char* p, bool* bom )
405
20.5k
{
406
20.5k
    TIXMLASSERT( p );
407
20.5k
    TIXMLASSERT( bom );
408
20.5k
    *bom = false;
409
20.5k
    const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
410
    // Check for BOM:
411
20.5k
    if (    *(pu+0) == TIXML_UTF_LEAD_0
412
20.5k
            && *(pu+1) == TIXML_UTF_LEAD_1
413
20.5k
            && *(pu+2) == TIXML_UTF_LEAD_2 ) {
414
3
        *bom = true;
415
3
        p += 3;
416
3
    }
417
20.5k
    TIXMLASSERT( p );
418
20.5k
    return p;
419
20.5k
}
420
421
422
void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
423
2.02k
{
424
2.02k
    const unsigned long BYTE_MASK = 0xBF;
425
2.02k
    const unsigned long BYTE_MARK = 0x80;
426
2.02k
    const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
427
428
2.02k
    if (input < 0x80) {
429
1.06k
        *length = 1;
430
1.06k
    }
431
967
    else if ( input < 0x800 ) {
432
260
        *length = 2;
433
260
    }
434
707
    else if ( input < 0x10000 ) {
435
217
        *length = 3;
436
217
    }
437
490
    else if ( input < 0x200000 ) {
438
265
        *length = 4;
439
265
    }
440
225
    else {
441
225
        *length = 0;    // This code won't convert this correctly anyway.
442
225
        return;
443
225
    }
444
445
1.80k
    output += *length;
446
447
    // Scary scary fall throughs are annotated with carefully designed comments
448
    // to suppress compiler warnings such as -Wimplicit-fallthrough in gcc
449
1.80k
    switch (*length) {
450
265
        case 4:
451
265
            --output;
452
265
            *output = static_cast<char>((input | BYTE_MARK) & BYTE_MASK);
453
265
            input >>= 6;
454
            //fall through
455
482
        case 3:
456
482
            --output;
457
482
            *output = static_cast<char>((input | BYTE_MARK) & BYTE_MASK);
458
482
            input >>= 6;
459
            //fall through
460
742
        case 2:
461
742
            --output;
462
742
            *output = static_cast<char>((input | BYTE_MARK) & BYTE_MASK);
463
742
            input >>= 6;
464
            //fall through
465
1.80k
        case 1:
466
1.80k
            --output;
467
1.80k
            *output = static_cast<char>(input | FIRST_BYTE_MARK[*length]);
468
1.80k
            break;
469
0
        default:
470
0
            TIXMLASSERT( false );
471
1.80k
    }
472
1.80k
}
473
474
475
const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
476
6.36k
{
477
    // Presume an entity, and pull it out.
478
6.36k
    *length = 0;
479
480
6.36k
    if ( *(p+1) == '#' && *(p+2) ) {
481
6.14k
        unsigned long ucs = 0;
482
6.14k
        TIXMLASSERT( sizeof( ucs ) >= 4 );
483
6.14k
        ptrdiff_t delta = 0;
484
6.14k
        unsigned mult = 1;
485
6.14k
        static const char SEMICOLON = ';';
486
487
6.14k
        if ( *(p+2) == 'x' ) {
488
            // Hexadecimal.
489
3.81k
            const char* q = p+3;
490
3.81k
            if ( !(*q) ) {
491
1.74k
                return 0;
492
1.74k
            }
493
494
2.07k
            q = strchr( q, SEMICOLON );
495
496
2.07k
            if ( !q ) {
497
295
                return 0;
498
295
            }
499
1.78k
            TIXMLASSERT( *q == SEMICOLON );
500
501
1.78k
            delta = q-p;
502
1.78k
            --q;
503
504
6.36k
            while ( *q != 'x' ) {
505
5.42k
                unsigned int digit = 0;
506
507
5.42k
                if ( *q >= '0' && *q <= '9' ) {
508
2.99k
                    digit = *q - '0';
509
2.99k
                }
510
2.43k
                else if ( *q >= 'a' && *q <= 'f' ) {
511
551
                    digit = *q - 'a' + 10;
512
551
                }
513
1.88k
                else if ( *q >= 'A' && *q <= 'F' ) {
514
1.03k
                    digit = *q - 'A' + 10;
515
1.03k
                }
516
845
                else {
517
845
                    return 0;
518
845
                }
519
4.57k
                TIXMLASSERT( digit < 16 );
520
4.57k
                TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
521
4.57k
                const unsigned int digitScaled = mult * digit;
522
4.57k
                TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
523
4.57k
                ucs += digitScaled;
524
4.57k
                TIXMLASSERT( mult <= UINT_MAX / 16 );
525
4.57k
                mult *= 16;
526
4.57k
                --q;
527
4.57k
            }
528
1.78k
        }
529
2.32k
        else {
530
            // Decimal.
531
2.32k
            const char* q = p+2;
532
2.32k
            if ( !(*q) ) {
533
0
                return 0;
534
0
            }
535
536
2.32k
            q = strchr( q, SEMICOLON );
537
538
2.32k
            if ( !q ) {
539
551
                return 0;
540
551
            }
541
1.77k
            TIXMLASSERT( *q == SEMICOLON );
542
543
1.77k
            delta = q-p;
544
1.77k
            --q;
545
546
4.50k
            while ( *q != '#' ) {
547
3.41k
                if ( *q >= '0' && *q <= '9' ) {
548
2.72k
                    const unsigned int digit = *q - '0';
549
2.72k
                    TIXMLASSERT( digit < 10 );
550
2.72k
                    TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
551
2.72k
                    const unsigned int digitScaled = mult * digit;
552
2.72k
                    TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
553
2.72k
                    ucs += digitScaled;
554
2.72k
                }
555
686
                else {
556
686
                    return 0;
557
686
                }
558
2.72k
                TIXMLASSERT( mult <= UINT_MAX / 10 );
559
2.72k
                mult *= 10;
560
2.72k
                --q;
561
2.72k
            }
562
1.77k
        }
563
        // convert the UCS to UTF-8
564
2.02k
        ConvertUTF32ToUTF8( ucs, value, length );
565
2.02k
        return p + delta + 1;
566
6.14k
    }
567
222
    return p+1;
568
6.36k
}
569
570
571
void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
572
0
{
573
0
    TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
574
0
}
575
576
577
void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
578
0
{
579
0
    TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
580
0
}
581
582
583
void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
584
0
{
585
0
    TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? writeBoolTrue : writeBoolFalse);
586
0
}
587
588
/*
589
  ToStr() of a number is a very tricky topic.
590
  https://github.com/leethomason/tinyxml2/issues/106
591
*/
592
void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
593
0
{
594
0
    TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
595
0
}
596
597
598
void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
599
0
{
600
0
    TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
601
0
}
602
603
604
void XMLUtil::ToStr( int64_t v, char* buffer, int bufferSize )
605
0
{
606
  // horrible syntax trick to make the compiler happy about %lld
607
0
  TIXML_SNPRINTF(buffer, bufferSize, "%lld", static_cast<long long>(v));
608
0
}
609
610
void XMLUtil::ToStr( uint64_t v, char* buffer, int bufferSize )
611
0
{
612
    // horrible syntax trick to make the compiler happy about %llu
613
0
    TIXML_SNPRINTF(buffer, bufferSize, "%llu", (long long)v);
614
0
}
615
616
bool XMLUtil::ToInt(const char* str, int* value)
617
0
{
618
0
    if (IsPrefixHex(str)) {
619
0
        unsigned v;
620
0
        if (TIXML_SSCANF(str, "%x", &v) == 1) {
621
0
            *value = static_cast<int>(v);
622
0
            return true;
623
0
        }
624
0
    }
625
0
    else {
626
0
        if (TIXML_SSCANF(str, "%d", value) == 1) {
627
0
            return true;
628
0
        }
629
0
    }
630
0
    return false;
631
0
}
632
633
bool XMLUtil::ToUnsigned(const char* str, unsigned* value)
634
0
{
635
0
    if (TIXML_SSCANF(str, IsPrefixHex(str) ? "%x" : "%u", value) == 1) {
636
0
        return true;
637
0
    }
638
0
    return false;
639
0
}
640
641
bool XMLUtil::ToBool( const char* str, bool* value )
642
0
{
643
0
    int ival = 0;
644
0
    if ( ToInt( str, &ival )) {
645
0
        *value = (ival==0) ? false : true;
646
0
        return true;
647
0
    }
648
0
    static const char* TRUE_VALS[] = { "true", "True", "TRUE", 0 };
649
0
    static const char* FALSE_VALS[] = { "false", "False", "FALSE", 0 };
650
651
0
    for (int i = 0; TRUE_VALS[i]; ++i) {
652
0
        if (StringEqual(str, TRUE_VALS[i])) {
653
0
            *value = true;
654
0
            return true;
655
0
        }
656
0
    }
657
0
    for (int i = 0; FALSE_VALS[i]; ++i) {
658
0
        if (StringEqual(str, FALSE_VALS[i])) {
659
0
            *value = false;
660
0
            return true;
661
0
        }
662
0
    }
663
0
    return false;
664
0
}
665
666
667
bool XMLUtil::ToFloat( const char* str, float* value )
668
0
{
669
0
    if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
670
0
        return true;
671
0
    }
672
0
    return false;
673
0
}
674
675
676
bool XMLUtil::ToDouble( const char* str, double* value )
677
0
{
678
0
    if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
679
0
        return true;
680
0
    }
681
0
    return false;
682
0
}
683
684
685
bool XMLUtil::ToInt64(const char* str, int64_t* value)
686
0
{
687
0
    if (IsPrefixHex(str)) {
688
0
        unsigned long long v = 0; // horrible syntax trick to make the compiler happy about %llx
689
0
        if (TIXML_SSCANF(str, "%llx", &v) == 1) {
690
0
            *value = static_cast<int64_t>(v);
691
0
            return true;
692
0
        }
693
0
    }
694
0
    else {
695
0
        long long v = 0;  // horrible syntax trick to make the compiler happy about %lld
696
0
        if (TIXML_SSCANF(str, "%lld", &v) == 1) {
697
0
            *value = static_cast<int64_t>(v);
698
0
            return true;
699
0
        }
700
0
    }
701
0
  return false;
702
0
}
703
704
705
0
bool XMLUtil::ToUnsigned64(const char* str, uint64_t* value) {
706
0
    unsigned long long v = 0; // horrible syntax trick to make the compiler happy about %llu
707
0
    if(TIXML_SSCANF(str, IsPrefixHex(str) ? "%llx" : "%llu", &v) == 1) {
708
0
        *value = (uint64_t)v;
709
0
        return true;
710
0
    }
711
0
    return false;
712
0
}
713
714
715
char* XMLDocument::Identify( char* p, XMLNode** node, bool first )
716
10.0M
{
717
10.0M
    TIXMLASSERT( node );
718
10.0M
    TIXMLASSERT( p );
719
10.0M
    char* const start = p;
720
10.0M
    int const startLine = _parseCurLineNum;
721
10.0M
    p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
722
10.0M
    if( !*p ) {
723
9.50k
        *node = 0;
724
9.50k
        TIXMLASSERT( p );
725
9.50k
        return p;
726
9.50k
    }
727
728
    // These strings define the matching patterns:
729
10.0M
    static const char* xmlHeader    = { "<?" };
730
10.0M
    static const char* commentHeader  = { "<!--" };
731
10.0M
    static const char* cdataHeader    = { "<![CDATA[" };
732
10.0M
    static const char* dtdHeader    = { "<!" };
733
10.0M
    static const char* elementHeader  = { "<" };  // and a header for everything else; check last.
734
735
10.0M
    static const int xmlHeaderLen   = 2;
736
10.0M
    static const int commentHeaderLen = 4;
737
10.0M
    static const int cdataHeaderLen   = 9;
738
10.0M
    static const int dtdHeaderLen   = 2;
739
10.0M
    static const int elementHeaderLen = 1;
740
741
10.0M
    TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) );   // use same memory pool
742
10.0M
    TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
743
10.0M
    XMLNode* returnNode = 0;
744
10.0M
    if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
745
1.19k
        returnNode = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
746
1.19k
        returnNode->_parseLineNum = _parseCurLineNum;
747
1.19k
        p += xmlHeaderLen;
748
1.19k
    }
749
10.0M
    else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
750
1.76k
        returnNode = CreateUnlinkedNode<XMLComment>( _commentPool );
751
1.76k
        returnNode->_parseLineNum = _parseCurLineNum;
752
1.76k
        p += commentHeaderLen;
753
1.76k
    }
754
10.0M
    else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
755
707
        XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
756
707
        returnNode = text;
757
707
        returnNode->_parseLineNum = _parseCurLineNum;
758
707
        p += cdataHeaderLen;
759
707
        text->SetCData( true );
760
707
    }
761
10.0M
    else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
762
3.29M
        returnNode = CreateUnlinkedNode<XMLUnknown>( _commentPool );
763
3.29M
        returnNode->_parseLineNum = _parseCurLineNum;
764
3.29M
        p += dtdHeaderLen;
765
3.29M
    }
766
6.77M
    else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
767
768
        // Preserve whitespace pedantically before closing tag, when it's immediately after opening tag
769
3.79M
        if (WhitespaceMode() == PEDANTIC_WHITESPACE && first && p != start && *(p + elementHeaderLen) == '/') {
770
0
            returnNode = CreateUnlinkedNode<XMLText>(_textPool);
771
0
            returnNode->_parseLineNum = startLine;
772
0
            p = start;  // Back it up, all the text counts.
773
0
            _parseCurLineNum = startLine;
774
0
        }
775
3.79M
        else {
776
3.79M
            returnNode = CreateUnlinkedNode<XMLElement>(_elementPool);
777
3.79M
            returnNode->_parseLineNum = _parseCurLineNum;
778
3.79M
            p += elementHeaderLen;
779
3.79M
        }
780
3.79M
    }
781
2.98M
    else {
782
2.98M
        returnNode = CreateUnlinkedNode<XMLText>( _textPool );
783
2.98M
        returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character
784
2.98M
        p = start;  // Back it up, all the text counts.
785
2.98M
        _parseCurLineNum = startLine;
786
2.98M
    }
787
788
10.0M
    TIXMLASSERT( returnNode );
789
10.0M
    TIXMLASSERT( p );
790
10.0M
    *node = returnNode;
791
10.0M
    return p;
792
10.0M
}
793
794
795
bool XMLDocument::Accept( XMLVisitor* visitor ) const
796
9.59k
{
797
9.59k
    TIXMLASSERT( visitor );
798
9.59k
    if ( visitor->VisitEnter( *this ) ) {
799
2.41M
        for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
800
2.40M
            if ( !node->Accept( visitor ) ) {
801
0
                break;
802
0
            }
803
2.40M
        }
804
9.59k
    }
805
9.59k
    return visitor->VisitExit( *this );
806
9.59k
}
807
808
809
// --------- XMLNode ----------- //
810
811
XMLNode::XMLNode( XMLDocument* doc ) :
812
10.0M
    _document( doc ),
813
10.0M
    _parent( 0 ),
814
10.0M
    _value(),
815
10.0M
    _parseLineNum( 0 ),
816
10.0M
    _firstChild( 0 ), _lastChild( 0 ),
817
10.0M
    _prev( 0 ), _next( 0 ),
818
10.0M
  _userData( 0 ),
819
10.0M
    _memPool( 0 )
820
10.0M
{
821
10.0M
}
822
823
824
XMLNode::~XMLNode()
825
10.0M
{
826
10.0M
    DeleteChildren();
827
10.0M
    if ( _parent ) {
828
0
        _parent->Unlink( this );
829
0
    }
830
10.0M
}
831
832
// ChildElementCount was originally suggested by msteiger on the sourceforge page for TinyXML and modified by KB1SPH for TinyXML-2.
833
834
0
int XMLNode::ChildElementCount(const char *value) const {
835
0
  int count = 0;
836
837
0
  const XMLElement *e = FirstChildElement(value);
838
839
0
  while (e) {
840
0
    e = e->NextSiblingElement(value);
841
0
    count++;
842
0
  }
843
844
0
  return count;
845
0
}
846
847
0
int XMLNode::ChildElementCount() const {
848
0
  int count = 0;
849
850
0
  const XMLElement *e = FirstChildElement();
851
852
0
  while (e) {
853
0
    e = e->NextSiblingElement();
854
0
    count++;
855
0
  }
856
857
0
  return count;
858
0
}
859
860
const char* XMLNode::Value() const
861
4.43M
{
862
    // Edge case: XMLDocuments don't have a Value. Return null.
863
4.43M
    if ( this->ToDocument() )
864
0
        return 0;
865
4.43M
    return _value.GetStr();
866
4.43M
}
867
868
void XMLNode::SetValue( const char* str, bool staticMem )
869
0
{
870
0
    if ( staticMem ) {
871
0
        _value.SetInternedStr( str );
872
0
    }
873
0
    else {
874
0
        _value.SetStr( str );
875
0
    }
876
0
}
877
878
XMLNode* XMLNode::DeepClone(XMLDocument* target) const
879
0
{
880
0
  XMLNode* clone = this->ShallowClone(target);
881
0
  if (!clone) return 0;
882
883
0
  for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) {
884
0
    XMLNode* childClone = child->DeepClone(target);
885
0
    TIXMLASSERT(childClone);
886
0
    clone->InsertEndChild(childClone);
887
0
  }
888
0
  return clone;
889
0
}
890
891
void XMLNode::DeleteChildren()
892
10.1M
{
893
18.9M
    while( _firstChild ) {
894
8.79M
        TIXMLASSERT( _lastChild );
895
8.79M
        DeleteChild( _firstChild );
896
8.79M
    }
897
10.1M
    _firstChild = _lastChild = 0;
898
10.1M
}
899
900
901
void XMLNode::Unlink( XMLNode* child )
902
8.79M
{
903
8.79M
    TIXMLASSERT( child );
904
8.79M
    TIXMLASSERT( child->_document == _document );
905
8.79M
    TIXMLASSERT( child->_parent == this );
906
8.79M
    if ( child == _firstChild ) {
907
8.79M
        _firstChild = _firstChild->_next;
908
8.79M
    }
909
8.79M
    if ( child == _lastChild ) {
910
1.26M
        _lastChild = _lastChild->_prev;
911
1.26M
    }
912
913
8.79M
    if ( child->_prev ) {
914
0
        child->_prev->_next = child->_next;
915
0
    }
916
8.79M
    if ( child->_next ) {
917
7.52M
        child->_next->_prev = child->_prev;
918
7.52M
    }
919
8.79M
  child->_next = 0;
920
8.79M
  child->_prev = 0;
921
8.79M
  child->_parent = 0;
922
8.79M
}
923
924
925
void XMLNode::DeleteChild( XMLNode* node )
926
8.79M
{
927
8.79M
    TIXMLASSERT( node );
928
8.79M
    TIXMLASSERT( node->_document == _document );
929
8.79M
    TIXMLASSERT( node->_parent == this );
930
8.79M
    Unlink( node );
931
8.79M
  TIXMLASSERT(node->_prev == 0);
932
8.79M
  TIXMLASSERT(node->_next == 0);
933
8.79M
  TIXMLASSERT(node->_parent == 0);
934
8.79M
    DeleteNode( node );
935
8.79M
}
936
937
938
XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
939
8.79M
{
940
8.79M
    TIXMLASSERT( addThis );
941
8.79M
    if ( addThis->_document != _document ) {
942
0
        TIXMLASSERT( false );
943
0
        return 0;
944
0
    }
945
8.79M
    InsertChildPreamble( addThis );
946
947
8.79M
    if ( _lastChild ) {
948
7.52M
        TIXMLASSERT( _firstChild );
949
7.52M
        TIXMLASSERT( _lastChild->_next == 0 );
950
7.52M
        _lastChild->_next = addThis;
951
7.52M
        addThis->_prev = _lastChild;
952
7.52M
        _lastChild = addThis;
953
954
7.52M
        addThis->_next = 0;
955
7.52M
    }
956
1.26M
    else {
957
1.26M
        TIXMLASSERT( _firstChild == 0 );
958
1.26M
        _firstChild = _lastChild = addThis;
959
960
1.26M
        addThis->_prev = 0;
961
1.26M
        addThis->_next = 0;
962
1.26M
    }
963
8.79M
    addThis->_parent = this;
964
8.79M
    return addThis;
965
8.79M
}
966
967
968
XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
969
0
{
970
0
    TIXMLASSERT( addThis );
971
0
    if ( addThis->_document != _document ) {
972
0
        TIXMLASSERT( false );
973
0
        return 0;
974
0
    }
975
0
    InsertChildPreamble( addThis );
976
977
0
    if ( _firstChild ) {
978
0
        TIXMLASSERT( _lastChild );
979
0
        TIXMLASSERT( _firstChild->_prev == 0 );
980
981
0
        _firstChild->_prev = addThis;
982
0
        addThis->_next = _firstChild;
983
0
        _firstChild = addThis;
984
985
0
        addThis->_prev = 0;
986
0
    }
987
0
    else {
988
0
        TIXMLASSERT( _lastChild == 0 );
989
0
        _firstChild = _lastChild = addThis;
990
991
0
        addThis->_prev = 0;
992
0
        addThis->_next = 0;
993
0
    }
994
0
    addThis->_parent = this;
995
0
    return addThis;
996
0
}
997
998
999
XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
1000
0
{
1001
0
    TIXMLASSERT( addThis );
1002
0
    if ( addThis->_document != _document ) {
1003
0
        TIXMLASSERT( false );
1004
0
        return 0;
1005
0
    }
1006
1007
0
    TIXMLASSERT( afterThis );
1008
1009
0
    if ( afterThis->_parent != this ) {
1010
0
        TIXMLASSERT( false );
1011
0
        return 0;
1012
0
    }
1013
0
    if ( afterThis == addThis ) {
1014
        // Current state: BeforeThis -> AddThis -> OneAfterAddThis
1015
        // Now AddThis must disappear from it's location and then
1016
        // reappear between BeforeThis and OneAfterAddThis.
1017
        // So just leave it where it is.
1018
0
        return addThis;
1019
0
    }
1020
1021
0
    if ( afterThis->_next == 0 ) {
1022
        // The last node or the only node.
1023
0
        return InsertEndChild( addThis );
1024
0
    }
1025
0
    InsertChildPreamble( addThis );
1026
0
    addThis->_prev = afterThis;
1027
0
    addThis->_next = afterThis->_next;
1028
0
    afterThis->_next->_prev = addThis;
1029
0
    afterThis->_next = addThis;
1030
0
    addThis->_parent = this;
1031
0
    return addThis;
1032
0
}
1033
1034
1035
1036
1037
const XMLElement* XMLNode::FirstChildElement( const char* name ) const
1038
128k
{
1039
232k
    for( const XMLNode* node = _firstChild; node; node = node->_next ) {
1040
186k
        const XMLElement* element = node->ToElementWithName( name );
1041
186k
        if ( element ) {
1042
82.8k
            return element;
1043
82.8k
        }
1044
186k
    }
1045
45.8k
    return 0;
1046
128k
}
1047
1048
1049
const XMLElement* XMLNode::LastChildElement( const char* name ) const
1050
0
{
1051
0
    for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
1052
0
        const XMLElement* element = node->ToElementWithName( name );
1053
0
        if ( element ) {
1054
0
            return element;
1055
0
        }
1056
0
    }
1057
0
    return 0;
1058
0
}
1059
1060
1061
const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
1062
80.0k
{
1063
106k
    for( const XMLNode* node = _next; node; node = node->_next ) {
1064
60.5k
        const XMLElement* element = node->ToElementWithName( name );
1065
60.5k
        if ( element ) {
1066
33.6k
            return element;
1067
33.6k
        }
1068
60.5k
    }
1069
46.3k
    return 0;
1070
80.0k
}
1071
1072
1073
const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
1074
0
{
1075
0
    for( const XMLNode* node = _prev; node; node = node->_prev ) {
1076
0
        const XMLElement* element = node->ToElementWithName( name );
1077
0
        if ( element ) {
1078
0
            return element;
1079
0
        }
1080
0
    }
1081
0
    return 0;
1082
0
}
1083
1084
1085
char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
1086
1.29M
{
1087
    // This is a recursive method, but thinking about it "at the current level"
1088
    // it is a pretty simple flat list:
1089
    //    <foo/>
1090
    //    <!-- comment -->
1091
    //
1092
    // With a special case:
1093
    //    <foo>
1094
    //    </foo>
1095
    //    <!-- comment -->
1096
    //
1097
    // Where the closing element (/foo) *must* be the next thing after the opening
1098
    // element, and the names must match. BUT the tricky bit is that the closing
1099
    // element will be read by the child.
1100
    //
1101
    // 'endTag' is the end tag for this node, it is returned by a call to a child.
1102
    // 'parentEnd' is the end tag for the parent, which is filled in and returned.
1103
1104
1.29M
  XMLDocument::DepthTracker tracker(_document);
1105
1.29M
  if (_document->Error())
1106
3
    return 0;
1107
1108
1.29M
  bool first = true;
1109
10.0M
  while( p && *p ) {
1110
10.0M
        XMLNode* node = 0;
1111
1112
10.0M
        p = _document->Identify( p, &node, first );
1113
10.0M
        TIXMLASSERT( p );
1114
10.0M
        if ( node == 0 ) {
1115
9.50k
            break;
1116
9.50k
        }
1117
10.0M
        first = false;
1118
1119
10.0M
       const int initialLineNum = node->_parseLineNum;
1120
1121
10.0M
        StrPair endTag;
1122
10.0M
        p = node->ParseDeep( p, &endTag, curLineNumPtr );
1123
10.0M
        if ( !p ) {
1124
18.5k
            _document->DeleteNode( node );
1125
18.5k
            if ( !_document->Error() ) {
1126
130
                _document->SetError( XML_ERROR_PARSING, initialLineNum, 0);
1127
130
            }
1128
18.5k
            break;
1129
18.5k
        }
1130
1131
10.0M
        const XMLDeclaration* const decl = node->ToDeclaration();
1132
10.0M
        if ( decl ) {
1133
            // Declarations are only allowed at document level
1134
            //
1135
            // Multiple declarations are allowed but all declarations
1136
            // must occur before anything else. 
1137
            //
1138
            // Optimized due to a security test case. If the first node is 
1139
            // a declaration, and the last node is a declaration, then only 
1140
            // declarations have so far been added.
1141
1.12k
            bool wellLocated = false;
1142
1143
1.12k
            if (ToDocument()) {
1144
1.12k
                if (FirstChild()) {
1145
1.06k
                    wellLocated =
1146
1.06k
                        FirstChild() &&
1147
1.06k
                        FirstChild()->ToDeclaration() &&
1148
1.06k
                        LastChild() &&
1149
1.06k
                        LastChild()->ToDeclaration();
1150
1.06k
                }
1151
55
                else {
1152
55
                    wellLocated = true;
1153
55
                }
1154
1.12k
            }
1155
1.12k
            if ( !wellLocated ) {
1156
13
                _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, "XMLDeclaration value=%s", decl->Value());
1157
13
                _document->DeleteNode( node );
1158
13
                break;
1159
13
            }
1160
1.12k
        }
1161
1162
10.0M
        XMLElement* ele = node->ToElement();
1163
10.0M
        if ( ele ) {
1164
            // We read the end tag. Return it to the parent.
1165
3.77M
            if ( ele->ClosingType() == XMLElement::CLOSING ) {
1166
1.25M
                if ( parentEndTag ) {
1167
1.25M
                    ele->_value.TransferTo( parentEndTag );
1168
1.25M
                }
1169
1.25M
                node->_memPool->SetTracked();   // created and then immediately deleted.
1170
1.25M
                DeleteNode( node );
1171
1.25M
                return p;
1172
1.25M
            }
1173
1174
            // Handle an end tag returned to this level.
1175
            // And handle a bunch of annoying errors.
1176
2.51M
            bool mismatch = false;
1177
2.51M
            if ( endTag.Empty() ) {
1178
1.25M
                if ( ele->ClosingType() == XMLElement::OPEN ) {
1179
1
                    mismatch = true;
1180
1
                }
1181
1.25M
            }
1182
1.25M
            else {
1183
1.25M
                if ( ele->ClosingType() != XMLElement::OPEN ) {
1184
0
                    mismatch = true;
1185
0
                }
1186
1.25M
                else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
1187
127
                    mismatch = true;
1188
127
                }
1189
1.25M
            }
1190
2.51M
            if ( mismatch ) {
1191
128
                _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, "XMLElement name=%s", ele->Name());
1192
128
                _document->DeleteNode( node );
1193
128
                break;
1194
128
            }
1195
2.51M
        }
1196
8.79M
        InsertEndChild( node );
1197
8.79M
    }
1198
37.8k
    return 0;
1199
1.29M
}
1200
1201
/*static*/ void XMLNode::DeleteNode( XMLNode* node )
1202
10.0M
{
1203
10.0M
    if ( node == 0 ) {
1204
0
        return;
1205
0
    }
1206
10.0M
  TIXMLASSERT(node->_document);
1207
10.0M
  if (!node->ToDocument()) {
1208
10.0M
    node->_document->MarkInUse(node);
1209
10.0M
  }
1210
1211
10.0M
    MemPool* pool = node->_memPool;
1212
10.0M
    node->~XMLNode();
1213
10.0M
    pool->Free( node );
1214
10.0M
}
1215
1216
void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
1217
8.79M
{
1218
8.79M
    TIXMLASSERT( insertThis );
1219
8.79M
    TIXMLASSERT( insertThis->_document == _document );
1220
1221
8.79M
  if (insertThis->_parent) {
1222
0
        insertThis->_parent->Unlink( insertThis );
1223
0
  }
1224
8.79M
  else {
1225
8.79M
    insertThis->_document->MarkInUse(insertThis);
1226
8.79M
        insertThis->_memPool->SetTracked();
1227
8.79M
  }
1228
8.79M
}
1229
1230
const XMLElement* XMLNode::ToElementWithName( const char* name ) const
1231
247k
{
1232
247k
    const XMLElement* element = this->ToElement();
1233
247k
    if ( element == 0 ) {
1234
50.6k
        return 0;
1235
50.6k
    }
1236
196k
    if ( name == 0 ) {
1237
100k
        return element;
1238
100k
    }
1239
96.6k
    if ( XMLUtil::StringEqual( element->Name(), name ) ) {
1240
16.5k
       return element;
1241
16.5k
    }
1242
80.1k
    return 0;
1243
96.6k
}
1244
1245
// --------- XMLText ---------- //
1246
char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
1247
2.98M
{
1248
2.98M
    if ( this->CData() ) {
1249
707
        p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
1250
707
        if ( !p ) {
1251
60
            _document->SetError( XML_ERROR_PARSING_CDATA, _parseLineNum, 0 );
1252
60
        }
1253
707
        return p;
1254
707
    }
1255
2.98M
    else {
1256
2.98M
        int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1257
2.98M
        if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
1258
0
            flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
1259
0
        }
1260
1261
2.98M
        p = _value.ParseText( p, "<", flags, curLineNumPtr );
1262
2.98M
        if ( p && *p ) {
1263
2.98M
            return p-1;
1264
2.98M
        }
1265
165
        if ( !p ) {
1266
161
            _document->SetError( XML_ERROR_PARSING_TEXT, _parseLineNum, 0 );
1267
161
        }
1268
165
    }
1269
165
    return 0;
1270
2.98M
}
1271
1272
1273
XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1274
0
{
1275
0
    if ( !doc ) {
1276
0
        doc = _document;
1277
0
    }
1278
0
    XMLText* text = doc->NewText( Value() );  // fixme: this will always allocate memory. Intern?
1279
0
    text->SetCData( this->CData() );
1280
0
    return text;
1281
0
}
1282
1283
1284
bool XMLText::ShallowEqual( const XMLNode* compare ) const
1285
0
{
1286
0
    TIXMLASSERT( compare );
1287
0
    const XMLText* text = compare->ToText();
1288
0
    return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
1289
0
}
1290
1291
1292
bool XMLText::Accept( XMLVisitor* visitor ) const
1293
1.01M
{
1294
1.01M
    TIXMLASSERT( visitor );
1295
1.01M
    return visitor->Visit( *this );
1296
1.01M
}
1297
1298
1299
// --------- XMLComment ---------- //
1300
1301
1.76k
XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
1302
1.76k
{
1303
1.76k
}
1304
1305
1306
XMLComment::~XMLComment()
1307
{
1308
}
1309
1310
1311
char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
1312
1.76k
{
1313
    // Comment parses as text.
1314
1.76k
    p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
1315
1.76k
    if ( p == 0 ) {
1316
66
        _document->SetError( XML_ERROR_PARSING_COMMENT, _parseLineNum, 0 );
1317
66
    }
1318
1.76k
    return p;
1319
1.76k
}
1320
1321
1322
XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1323
0
{
1324
0
    if ( !doc ) {
1325
0
        doc = _document;
1326
0
    }
1327
0
    XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1328
0
    return comment;
1329
0
}
1330
1331
1332
bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1333
0
{
1334
0
    TIXMLASSERT( compare );
1335
0
    const XMLComment* comment = compare->ToComment();
1336
0
    return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
1337
0
}
1338
1339
1340
bool XMLComment::Accept( XMLVisitor* visitor ) const
1341
833
{
1342
833
    TIXMLASSERT( visitor );
1343
833
    return visitor->Visit( *this );
1344
833
}
1345
1346
1347
// --------- XMLDeclaration ---------- //
1348
1349
1.19k
XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1350
1.19k
{
1351
1.19k
}
1352
1353
1354
XMLDeclaration::~XMLDeclaration()
1355
{
1356
    //printf( "~XMLDeclaration\n" );
1357
}
1358
1359
1360
char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
1361
1.19k
{
1362
    // Declaration parses as text.
1363
1.19k
    p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
1364
1.19k
    if ( p == 0 ) {
1365
61
        _document->SetError( XML_ERROR_PARSING_DECLARATION, _parseLineNum, 0 );
1366
61
    }
1367
1.19k
    return p;
1368
1.19k
}
1369
1370
1371
XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1372
0
{
1373
0
    if ( !doc ) {
1374
0
        doc = _document;
1375
0
    }
1376
0
    XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1377
0
    return dec;
1378
0
}
1379
1380
1381
bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1382
0
{
1383
0
    TIXMLASSERT( compare );
1384
0
    const XMLDeclaration* declaration = compare->ToDeclaration();
1385
0
    return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
1386
0
}
1387
1388
1389
1390
bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1391
551
{
1392
551
    TIXMLASSERT( visitor );
1393
551
    return visitor->Visit( *this );
1394
551
}
1395
1396
// --------- XMLUnknown ---------- //
1397
1398
3.29M
XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1399
3.29M
{
1400
3.29M
}
1401
1402
1403
XMLUnknown::~XMLUnknown()
1404
{
1405
}
1406
1407
1408
char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
1409
3.29M
{
1410
    // Unknown parses as text.
1411
3.29M
    p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
1412
3.29M
    if ( !p ) {
1413
123
        _document->SetError( XML_ERROR_PARSING_UNKNOWN, _parseLineNum, 0 );
1414
123
    }
1415
3.29M
    return p;
1416
3.29M
}
1417
1418
1419
XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1420
0
{
1421
0
    if ( !doc ) {
1422
0
        doc = _document;
1423
0
    }
1424
0
    XMLUnknown* text = doc->NewUnknown( Value() );  // fixme: this will always allocate memory. Intern?
1425
0
    return text;
1426
0
}
1427
1428
1429
bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1430
0
{
1431
0
    TIXMLASSERT( compare );
1432
0
    const XMLUnknown* unknown = compare->ToUnknown();
1433
0
    return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
1434
0
}
1435
1436
1437
bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1438
1.21M
{
1439
1.21M
    TIXMLASSERT( visitor );
1440
1.21M
    return visitor->Visit( *this );
1441
1.21M
}
1442
1443
// --------- XMLAttribute ---------- //
1444
1445
const char* XMLAttribute::Name() const
1446
722k
{
1447
722k
    return _name.GetStr();
1448
722k
}
1449
1450
const char* XMLAttribute::Value() const
1451
176k
{
1452
176k
    return _value.GetStr();
1453
176k
}
1454
1455
char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
1456
340k
{
1457
    // Parse using the name rules: bug fix, was using ParseText before
1458
340k
    p = _name.ParseName( p );
1459
340k
    if ( !p || !*p ) {
1460
20
        return 0;
1461
20
    }
1462
1463
    // Skip white space before =
1464
340k
    p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
1465
340k
    if ( *p != '=' ) {
1466
57
        return 0;
1467
57
    }
1468
1469
340k
    ++p;  // move up to opening quote
1470
340k
    p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
1471
340k
    if ( *p != '\"' && *p != '\'' ) {
1472
34
        return 0;
1473
34
    }
1474
1475
340k
    const char endTag[2] = { *p, 0 };
1476
340k
    ++p;  // move past opening quote
1477
1478
340k
    p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
1479
340k
    return p;
1480
340k
}
1481
1482
1483
void XMLAttribute::SetName( const char* n )
1484
0
{
1485
0
    _name.SetStr( n );
1486
0
}
1487
1488
1489
XMLError XMLAttribute::QueryIntValue( int* value ) const
1490
0
{
1491
0
    if ( XMLUtil::ToInt( Value(), value )) {
1492
0
        return XML_SUCCESS;
1493
0
    }
1494
0
    return XML_WRONG_ATTRIBUTE_TYPE;
1495
0
}
1496
1497
1498
XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
1499
0
{
1500
0
    if ( XMLUtil::ToUnsigned( Value(), value )) {
1501
0
        return XML_SUCCESS;
1502
0
    }
1503
0
    return XML_WRONG_ATTRIBUTE_TYPE;
1504
0
}
1505
1506
1507
XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1508
0
{
1509
0
  if (XMLUtil::ToInt64(Value(), value)) {
1510
0
    return XML_SUCCESS;
1511
0
  }
1512
0
  return XML_WRONG_ATTRIBUTE_TYPE;
1513
0
}
1514
1515
1516
XMLError XMLAttribute::QueryUnsigned64Value(uint64_t* value) const
1517
0
{
1518
0
    if(XMLUtil::ToUnsigned64(Value(), value)) {
1519
0
        return XML_SUCCESS;
1520
0
    }
1521
0
    return XML_WRONG_ATTRIBUTE_TYPE;
1522
0
}
1523
1524
1525
XMLError XMLAttribute::QueryBoolValue( bool* value ) const
1526
0
{
1527
0
    if ( XMLUtil::ToBool( Value(), value )) {
1528
0
        return XML_SUCCESS;
1529
0
    }
1530
0
    return XML_WRONG_ATTRIBUTE_TYPE;
1531
0
}
1532
1533
1534
XMLError XMLAttribute::QueryFloatValue( float* value ) const
1535
0
{
1536
0
    if ( XMLUtil::ToFloat( Value(), value )) {
1537
0
        return XML_SUCCESS;
1538
0
    }
1539
0
    return XML_WRONG_ATTRIBUTE_TYPE;
1540
0
}
1541
1542
1543
XMLError XMLAttribute::QueryDoubleValue( double* value ) const
1544
0
{
1545
0
    if ( XMLUtil::ToDouble( Value(), value )) {
1546
0
        return XML_SUCCESS;
1547
0
    }
1548
0
    return XML_WRONG_ATTRIBUTE_TYPE;
1549
0
}
1550
1551
1552
void XMLAttribute::SetAttribute( const char* v )
1553
0
{
1554
0
    _value.SetStr( v );
1555
0
}
1556
1557
1558
void XMLAttribute::SetAttribute( int v )
1559
0
{
1560
0
    char buf[BUF_SIZE];
1561
0
    XMLUtil::ToStr( v, buf, BUF_SIZE );
1562
0
    _value.SetStr( buf );
1563
0
}
1564
1565
1566
void XMLAttribute::SetAttribute( unsigned v )
1567
0
{
1568
0
    char buf[BUF_SIZE];
1569
0
    XMLUtil::ToStr( v, buf, BUF_SIZE );
1570
0
    _value.SetStr( buf );
1571
0
}
1572
1573
1574
void XMLAttribute::SetAttribute(int64_t v)
1575
0
{
1576
0
  char buf[BUF_SIZE];
1577
0
  XMLUtil::ToStr(v, buf, BUF_SIZE);
1578
0
  _value.SetStr(buf);
1579
0
}
1580
1581
void XMLAttribute::SetAttribute(uint64_t v)
1582
0
{
1583
0
    char buf[BUF_SIZE];
1584
0
    XMLUtil::ToStr(v, buf, BUF_SIZE);
1585
0
    _value.SetStr(buf);
1586
0
}
1587
1588
1589
void XMLAttribute::SetAttribute( bool v )
1590
0
{
1591
0
    char buf[BUF_SIZE];
1592
0
    XMLUtil::ToStr( v, buf, BUF_SIZE );
1593
0
    _value.SetStr( buf );
1594
0
}
1595
1596
void XMLAttribute::SetAttribute( double v )
1597
0
{
1598
0
    char buf[BUF_SIZE];
1599
0
    XMLUtil::ToStr( v, buf, BUF_SIZE );
1600
0
    _value.SetStr( buf );
1601
0
}
1602
1603
void XMLAttribute::SetAttribute( float v )
1604
0
{
1605
0
    char buf[BUF_SIZE];
1606
0
    XMLUtil::ToStr( v, buf, BUF_SIZE );
1607
0
    _value.SetStr( buf );
1608
0
}
1609
1610
1611
// --------- XMLElement ---------- //
1612
3.79M
XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
1613
3.79M
    _closingType( OPEN ),
1614
3.79M
    _rootAttribute( 0 )
1615
3.79M
{
1616
3.79M
}
1617
1618
1619
XMLElement::~XMLElement()
1620
3.79M
{
1621
4.13M
    while( _rootAttribute ) {
1622
340k
        XMLAttribute* next = _rootAttribute->_next;
1623
340k
        DeleteAttribute( _rootAttribute );
1624
340k
        _rootAttribute = next;
1625
340k
    }
1626
3.79M
}
1627
1628
1629
const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1630
504k
{
1631
706k
    for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
1632
270k
        if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1633
67.9k
            return a;
1634
67.9k
        }
1635
270k
    }
1636
436k
    return 0;
1637
504k
}
1638
1639
1640
const char* XMLElement::Attribute( const char* name, const char* value ) const
1641
504k
{
1642
504k
    const XMLAttribute* a = FindAttribute( name );
1643
504k
    if ( !a ) {
1644
436k
        return 0;
1645
436k
    }
1646
67.9k
    if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1647
67.9k
        return a->Value();
1648
67.9k
    }
1649
0
    return 0;
1650
67.9k
}
1651
1652
int XMLElement::IntAttribute(const char* name, int defaultValue) const
1653
0
{
1654
0
  int i = defaultValue;
1655
0
  QueryIntAttribute(name, &i);
1656
0
  return i;
1657
0
}
1658
1659
unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
1660
0
{
1661
0
  unsigned i = defaultValue;
1662
0
  QueryUnsignedAttribute(name, &i);
1663
0
  return i;
1664
0
}
1665
1666
int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
1667
0
{
1668
0
  int64_t i = defaultValue;
1669
0
  QueryInt64Attribute(name, &i);
1670
0
  return i;
1671
0
}
1672
1673
uint64_t XMLElement::Unsigned64Attribute(const char* name, uint64_t defaultValue) const
1674
0
{
1675
0
  uint64_t i = defaultValue;
1676
0
  QueryUnsigned64Attribute(name, &i);
1677
0
  return i;
1678
0
}
1679
1680
bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
1681
0
{
1682
0
  bool b = defaultValue;
1683
0
  QueryBoolAttribute(name, &b);
1684
0
  return b;
1685
0
}
1686
1687
double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
1688
0
{
1689
0
  double d = defaultValue;
1690
0
  QueryDoubleAttribute(name, &d);
1691
0
  return d;
1692
0
}
1693
1694
float XMLElement::FloatAttribute(const char* name, float defaultValue) const
1695
0
{
1696
0
  float f = defaultValue;
1697
0
  QueryFloatAttribute(name, &f);
1698
0
  return f;
1699
0
}
1700
1701
const char* XMLElement::GetText() const
1702
0
{
1703
    /* skip comment node */
1704
0
    const XMLNode* node = FirstChild();
1705
0
    while (node) {
1706
0
        if (node->ToComment()) {
1707
0
            node = node->NextSibling();
1708
0
            continue;
1709
0
        }
1710
0
        break;
1711
0
    }
1712
1713
0
    if ( node && node->ToText() ) {
1714
0
        return node->Value();
1715
0
    }
1716
0
    return 0;
1717
0
}
1718
1719
1720
void  XMLElement::SetText( const char* inText )
1721
0
{
1722
0
  if ( FirstChild() && FirstChild()->ToText() )
1723
0
    FirstChild()->SetValue( inText );
1724
0
  else {
1725
0
    XMLText*  theText = GetDocument()->NewText( inText );
1726
0
    InsertFirstChild( theText );
1727
0
  }
1728
0
}
1729
1730
1731
void XMLElement::SetText( int v )
1732
0
{
1733
0
    char buf[BUF_SIZE];
1734
0
    XMLUtil::ToStr( v, buf, BUF_SIZE );
1735
0
    SetText( buf );
1736
0
}
1737
1738
1739
void XMLElement::SetText( unsigned v )
1740
0
{
1741
0
    char buf[BUF_SIZE];
1742
0
    XMLUtil::ToStr( v, buf, BUF_SIZE );
1743
0
    SetText( buf );
1744
0
}
1745
1746
1747
void XMLElement::SetText(int64_t v)
1748
0
{
1749
0
  char buf[BUF_SIZE];
1750
0
  XMLUtil::ToStr(v, buf, BUF_SIZE);
1751
0
  SetText(buf);
1752
0
}
1753
1754
0
void XMLElement::SetText(uint64_t v) {
1755
0
    char buf[BUF_SIZE];
1756
0
    XMLUtil::ToStr(v, buf, BUF_SIZE);
1757
0
    SetText(buf);
1758
0
}
1759
1760
1761
void XMLElement::SetText( bool v )
1762
0
{
1763
0
    char buf[BUF_SIZE];
1764
0
    XMLUtil::ToStr( v, buf, BUF_SIZE );
1765
0
    SetText( buf );
1766
0
}
1767
1768
1769
void XMLElement::SetText( float v )
1770
0
{
1771
0
    char buf[BUF_SIZE];
1772
0
    XMLUtil::ToStr( v, buf, BUF_SIZE );
1773
0
    SetText( buf );
1774
0
}
1775
1776
1777
void XMLElement::SetText( double v )
1778
0
{
1779
0
    char buf[BUF_SIZE];
1780
0
    XMLUtil::ToStr( v, buf, BUF_SIZE );
1781
0
    SetText( buf );
1782
0
}
1783
1784
1785
XMLError XMLElement::QueryIntText( int* ival ) const
1786
0
{
1787
0
    if ( FirstChild() && FirstChild()->ToText() ) {
1788
0
        const char* t = FirstChild()->Value();
1789
0
        if ( XMLUtil::ToInt( t, ival ) ) {
1790
0
            return XML_SUCCESS;
1791
0
        }
1792
0
        return XML_CAN_NOT_CONVERT_TEXT;
1793
0
    }
1794
0
    return XML_NO_TEXT_NODE;
1795
0
}
1796
1797
1798
XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
1799
0
{
1800
0
    if ( FirstChild() && FirstChild()->ToText() ) {
1801
0
        const char* t = FirstChild()->Value();
1802
0
        if ( XMLUtil::ToUnsigned( t, uval ) ) {
1803
0
            return XML_SUCCESS;
1804
0
        }
1805
0
        return XML_CAN_NOT_CONVERT_TEXT;
1806
0
    }
1807
0
    return XML_NO_TEXT_NODE;
1808
0
}
1809
1810
1811
XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1812
0
{
1813
0
  if (FirstChild() && FirstChild()->ToText()) {
1814
0
    const char* t = FirstChild()->Value();
1815
0
    if (XMLUtil::ToInt64(t, ival)) {
1816
0
      return XML_SUCCESS;
1817
0
    }
1818
0
    return XML_CAN_NOT_CONVERT_TEXT;
1819
0
  }
1820
0
  return XML_NO_TEXT_NODE;
1821
0
}
1822
1823
1824
XMLError XMLElement::QueryUnsigned64Text(uint64_t* uval) const
1825
0
{
1826
0
    if(FirstChild() && FirstChild()->ToText()) {
1827
0
        const char* t = FirstChild()->Value();
1828
0
        if(XMLUtil::ToUnsigned64(t, uval)) {
1829
0
            return XML_SUCCESS;
1830
0
        }
1831
0
        return XML_CAN_NOT_CONVERT_TEXT;
1832
0
    }
1833
0
    return XML_NO_TEXT_NODE;
1834
0
}
1835
1836
1837
XMLError XMLElement::QueryBoolText( bool* bval ) const
1838
0
{
1839
0
    if ( FirstChild() && FirstChild()->ToText() ) {
1840
0
        const char* t = FirstChild()->Value();
1841
0
        if ( XMLUtil::ToBool( t, bval ) ) {
1842
0
            return XML_SUCCESS;
1843
0
        }
1844
0
        return XML_CAN_NOT_CONVERT_TEXT;
1845
0
    }
1846
0
    return XML_NO_TEXT_NODE;
1847
0
}
1848
1849
1850
XMLError XMLElement::QueryDoubleText( double* dval ) const
1851
0
{
1852
0
    if ( FirstChild() && FirstChild()->ToText() ) {
1853
0
        const char* t = FirstChild()->Value();
1854
0
        if ( XMLUtil::ToDouble( t, dval ) ) {
1855
0
            return XML_SUCCESS;
1856
0
        }
1857
0
        return XML_CAN_NOT_CONVERT_TEXT;
1858
0
    }
1859
0
    return XML_NO_TEXT_NODE;
1860
0
}
1861
1862
1863
XMLError XMLElement::QueryFloatText( float* fval ) const
1864
0
{
1865
0
    if ( FirstChild() && FirstChild()->ToText() ) {
1866
0
        const char* t = FirstChild()->Value();
1867
0
        if ( XMLUtil::ToFloat( t, fval ) ) {
1868
0
            return XML_SUCCESS;
1869
0
        }
1870
0
        return XML_CAN_NOT_CONVERT_TEXT;
1871
0
    }
1872
0
    return XML_NO_TEXT_NODE;
1873
0
}
1874
1875
int XMLElement::IntText(int defaultValue) const
1876
0
{
1877
0
  int i = defaultValue;
1878
0
  QueryIntText(&i);
1879
0
  return i;
1880
0
}
1881
1882
unsigned XMLElement::UnsignedText(unsigned defaultValue) const
1883
0
{
1884
0
  unsigned i = defaultValue;
1885
0
  QueryUnsignedText(&i);
1886
0
  return i;
1887
0
}
1888
1889
int64_t XMLElement::Int64Text(int64_t defaultValue) const
1890
0
{
1891
0
  int64_t i = defaultValue;
1892
0
  QueryInt64Text(&i);
1893
0
  return i;
1894
0
}
1895
1896
uint64_t XMLElement::Unsigned64Text(uint64_t defaultValue) const
1897
0
{
1898
0
  uint64_t i = defaultValue;
1899
0
  QueryUnsigned64Text(&i);
1900
0
  return i;
1901
0
}
1902
1903
bool XMLElement::BoolText(bool defaultValue) const
1904
0
{
1905
0
  bool b = defaultValue;
1906
0
  QueryBoolText(&b);
1907
0
  return b;
1908
0
}
1909
1910
double XMLElement::DoubleText(double defaultValue) const
1911
0
{
1912
0
  double d = defaultValue;
1913
0
  QueryDoubleText(&d);
1914
0
  return d;
1915
0
}
1916
1917
float XMLElement::FloatText(float defaultValue) const
1918
0
{
1919
0
  float f = defaultValue;
1920
0
  QueryFloatText(&f);
1921
0
  return f;
1922
0
}
1923
1924
1925
XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1926
0
{
1927
0
    XMLAttribute* last = 0;
1928
0
    XMLAttribute* attrib = 0;
1929
0
    for( attrib = _rootAttribute;
1930
0
            attrib;
1931
0
            last = attrib, attrib = attrib->_next ) {
1932
0
        if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1933
0
            break;
1934
0
        }
1935
0
    }
1936
0
    if ( !attrib ) {
1937
0
        attrib = CreateAttribute();
1938
0
        TIXMLASSERT( attrib );
1939
0
        if ( last ) {
1940
0
            TIXMLASSERT( last->_next == 0 );
1941
0
            last->_next = attrib;
1942
0
        }
1943
0
        else {
1944
0
            TIXMLASSERT( _rootAttribute == 0 );
1945
0
            _rootAttribute = attrib;
1946
0
        }
1947
0
        attrib->SetName( name );
1948
0
    }
1949
0
    return attrib;
1950
0
}
1951
1952
1953
void XMLElement::DeleteAttribute( const char* name )
1954
0
{
1955
0
    XMLAttribute* prev = 0;
1956
0
    for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
1957
0
        if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1958
0
            if ( prev ) {
1959
0
                prev->_next = a->_next;
1960
0
            }
1961
0
            else {
1962
0
                _rootAttribute = a->_next;
1963
0
            }
1964
0
            DeleteAttribute( a );
1965
0
            break;
1966
0
        }
1967
0
        prev = a;
1968
0
    }
1969
0
}
1970
1971
1972
char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
1973
3.79M
{
1974
3.79M
    XMLAttribute* prevAttribute = 0;
1975
1976
    // Read the attributes.
1977
4.13M
    while( p ) {
1978
4.13M
        p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
1979
4.13M
        if ( !(*p) ) {
1980
115
            _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, "XMLElement name=%s", Name() );
1981
115
            return 0;
1982
115
        }
1983
1984
        // attribute.
1985
4.13M
        if (XMLUtil::IsNameStartChar( (unsigned char) *p ) ) {
1986
340k
            XMLAttribute* attrib = CreateAttribute();
1987
340k
            TIXMLASSERT( attrib );
1988
340k
            attrib->_parseLineNum = _document->_parseCurLineNum;
1989
1990
340k
            const int attrLineNum = attrib->_parseLineNum;
1991
1992
340k
            p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
1993
340k
            if ( !p || Attribute( attrib->Name() ) ) {
1994
295
                DeleteAttribute( attrib );
1995
295
                _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, attrLineNum, "XMLElement name=%s", Name() );
1996
295
                return 0;
1997
295
            }
1998
            // There is a minor bug here: if the attribute in the source xml
1999
            // document is duplicated, it will not be detected and the
2000
            // attribute will be doubly added. However, tracking the 'prevAttribute'
2001
            // avoids re-scanning the attribute list. Preferring performance for
2002
            // now, may reconsider in the future.
2003
340k
            if ( prevAttribute ) {
2004
30.3k
                TIXMLASSERT( prevAttribute->_next == 0 );
2005
30.3k
                prevAttribute->_next = attrib;
2006
30.3k
            }
2007
309k
            else {
2008
309k
                TIXMLASSERT( _rootAttribute == 0 );
2009
309k
                _rootAttribute = attrib;
2010
309k
            }
2011
340k
            prevAttribute = attrib;
2012
340k
        }
2013
        // end of the tag
2014
3.79M
        else if ( *p == '>' ) {
2015
2.53M
            ++p;
2016
2.53M
            break;
2017
2.53M
        }
2018
        // end of the tag
2019
1.25M
        else if ( *p == '/' && *(p+1) == '>' ) {
2020
1.25M
            _closingType = CLOSED;
2021
1.25M
            return p+2; // done; sealed element.
2022
1.25M
        }
2023
133
        else {
2024
133
            _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, 0 );
2025
133
            return 0;
2026
133
        }
2027
4.13M
    }
2028
2.53M
    return p;
2029
3.79M
}
2030
2031
void XMLElement::DeleteAttribute( XMLAttribute* attribute )
2032
340k
{
2033
340k
    if ( attribute == 0 ) {
2034
0
        return;
2035
0
    }
2036
340k
    MemPool* pool = attribute->_memPool;
2037
340k
    attribute->~XMLAttribute();
2038
340k
    pool->Free( attribute );
2039
340k
}
2040
2041
XMLAttribute* XMLElement::CreateAttribute()
2042
340k
{
2043
340k
    TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
2044
340k
    XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
2045
340k
    TIXMLASSERT( attrib );
2046
340k
    attrib->_memPool = &_document->_attributePool;
2047
340k
    attrib->_memPool->SetTracked();
2048
340k
    return attrib;
2049
340k
}
2050
2051
2052
XMLElement* XMLElement::InsertNewChildElement(const char* name)
2053
0
{
2054
0
    XMLElement* node = _document->NewElement(name);
2055
0
    return InsertEndChild(node) ? node : 0;
2056
0
}
2057
2058
XMLComment* XMLElement::InsertNewComment(const char* comment)
2059
0
{
2060
0
    XMLComment* node = _document->NewComment(comment);
2061
0
    return InsertEndChild(node) ? node : 0;
2062
0
}
2063
2064
XMLText* XMLElement::InsertNewText(const char* text)
2065
0
{
2066
0
    XMLText* node = _document->NewText(text);
2067
0
    return InsertEndChild(node) ? node : 0;
2068
0
}
2069
2070
XMLDeclaration* XMLElement::InsertNewDeclaration(const char* text)
2071
0
{
2072
0
    XMLDeclaration* node = _document->NewDeclaration(text);
2073
0
    return InsertEndChild(node) ? node : 0;
2074
0
}
2075
2076
XMLUnknown* XMLElement::InsertNewUnknown(const char* text)
2077
0
{
2078
0
    XMLUnknown* node = _document->NewUnknown(text);
2079
0
    return InsertEndChild(node) ? node : 0;
2080
0
}
2081
2082
2083
2084
//
2085
//  <ele></ele>
2086
//  <ele>foo<b>bar</b></ele>
2087
//
2088
char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
2089
3.79M
{
2090
    // Read the element name.
2091
3.79M
    p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
2092
2093
    // The closing element is the </element> form. It is
2094
    // parsed just like a regular element then deleted from
2095
    // the DOM.
2096
3.79M
    if ( *p == '/' ) {
2097
1.25M
        _closingType = CLOSING;
2098
1.25M
        ++p;
2099
1.25M
    }
2100
2101
3.79M
    p = _value.ParseName( p );
2102
3.79M
    if ( _value.Empty() ) {
2103
83
        return 0;
2104
83
    }
2105
2106
3.79M
    p = ParseAttributes( p, curLineNumPtr );
2107
3.79M
    if ( !p || !*p || _closingType != OPEN ) {
2108
2.51M
        return p;
2109
2.51M
    }
2110
2111
1.27M
    p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr );
2112
1.27M
    return p;
2113
3.79M
}
2114
2115
2116
2117
XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
2118
0
{
2119
0
    if ( !doc ) {
2120
0
        doc = _document;
2121
0
    }
2122
0
    XMLElement* element = doc->NewElement( Value() );         // fixme: this will always allocate memory. Intern?
2123
0
    for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
2124
0
        element->SetAttribute( a->Name(), a->Value() );         // fixme: this will always allocate memory. Intern?
2125
0
    }
2126
0
    return element;
2127
0
}
2128
2129
2130
bool XMLElement::ShallowEqual( const XMLNode* compare ) const
2131
0
{
2132
0
    TIXMLASSERT( compare );
2133
0
    const XMLElement* other = compare->ToElement();
2134
0
    if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
2135
2136
0
        const XMLAttribute* a=FirstAttribute();
2137
0
        const XMLAttribute* b=other->FirstAttribute();
2138
2139
0
        while ( a && b ) {
2140
0
            if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
2141
0
                return false;
2142
0
            }
2143
0
            a = a->Next();
2144
0
            b = b->Next();
2145
0
        }
2146
0
        if ( a || b ) {
2147
            // different count
2148
0
            return false;
2149
0
        }
2150
0
        return true;
2151
0
    }
2152
0
    return false;
2153
0
}
2154
2155
2156
bool XMLElement::Accept( XMLVisitor* visitor ) const
2157
802k
{
2158
802k
    TIXMLASSERT( visitor );
2159
802k
    if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
2160
1.43M
        for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
2161
630k
            if ( !node->Accept( visitor ) ) {
2162
0
                break;
2163
0
            }
2164
630k
        }
2165
802k
    }
2166
802k
    return visitor->VisitExit( *this );
2167
802k
}
2168
2169
2170
// --------- XMLDocument ----------- //
2171
2172
// Warning: List must match 'enum XMLError'
2173
const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
2174
    "XML_SUCCESS",
2175
    "XML_NO_ATTRIBUTE",
2176
    "XML_WRONG_ATTRIBUTE_TYPE",
2177
    "XML_ERROR_FILE_NOT_FOUND",
2178
    "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
2179
    "XML_ERROR_FILE_READ_ERROR",
2180
    "XML_ERROR_PARSING_ELEMENT",
2181
    "XML_ERROR_PARSING_ATTRIBUTE",
2182
    "XML_ERROR_PARSING_TEXT",
2183
    "XML_ERROR_PARSING_CDATA",
2184
    "XML_ERROR_PARSING_COMMENT",
2185
    "XML_ERROR_PARSING_DECLARATION",
2186
    "XML_ERROR_PARSING_UNKNOWN",
2187
    "XML_ERROR_EMPTY_DOCUMENT",
2188
    "XML_ERROR_MISMATCHED_ELEMENT",
2189
    "XML_ERROR_PARSING",
2190
    "XML_CAN_NOT_CONVERT_TEXT",
2191
    "XML_NO_TEXT_NODE",
2192
  "XML_ELEMENT_DEPTH_EXCEEDED"
2193
};
2194
2195
2196
XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :
2197
20.5k
    XMLNode( 0 ),
2198
20.5k
    _writeBOM( false ),
2199
20.5k
    _processEntities( processEntities ),
2200
20.5k
    _errorID(XML_SUCCESS),
2201
20.5k
    _whitespaceMode( whitespaceMode ),
2202
20.5k
    _errorStr(),
2203
20.5k
    _errorLineNum( 0 ),
2204
20.5k
    _charBuffer( 0 ),
2205
20.5k
    _parseCurLineNum( 0 ),
2206
20.5k
  _parsingDepth(0),
2207
20.5k
    _unlinked(),
2208
20.5k
    _elementPool(),
2209
20.5k
    _attributePool(),
2210
20.5k
    _textPool(),
2211
20.5k
    _commentPool()
2212
20.5k
{
2213
    // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
2214
20.5k
    _document = this;
2215
20.5k
}
2216
2217
2218
XMLDocument::~XMLDocument()
2219
20.5k
{
2220
20.5k
    Clear();
2221
20.5k
}
2222
2223
2224
void XMLDocument::MarkInUse(const XMLNode* const node)
2225
18.8M
{
2226
18.8M
  TIXMLASSERT(node);
2227
18.8M
  TIXMLASSERT(node->_parent == 0);
2228
2229
761M
  for (int i = 0; i < _unlinked.Size(); ++i) {
2230
752M
    if (node == _unlinked[i]) {
2231
10.0M
      _unlinked.SwapRemove(i);
2232
10.0M
      break;
2233
10.0M
    }
2234
752M
  }
2235
18.8M
}
2236
2237
void XMLDocument::Clear()
2238
41.0k
{
2239
41.0k
    DeleteChildren();
2240
41.0k
  while( _unlinked.Size()) {
2241
0
    DeleteNode(_unlinked[0]); // Will remove from _unlinked as part of delete.
2242
0
  }
2243
2244
#ifdef TINYXML2_DEBUG
2245
    const bool hadError = Error();
2246
#endif
2247
41.0k
    ClearError();
2248
2249
41.0k
    delete [] _charBuffer;
2250
41.0k
    _charBuffer = 0;
2251
41.0k
  _parsingDepth = 0;
2252
2253
#if 0
2254
    _textPool.Trace( "text" );
2255
    _elementPool.Trace( "element" );
2256
    _commentPool.Trace( "comment" );
2257
    _attributePool.Trace( "attribute" );
2258
#endif
2259
2260
#ifdef TINYXML2_DEBUG
2261
    if ( !hadError ) {
2262
        TIXMLASSERT( _elementPool.CurrentAllocs()   == _elementPool.Untracked() );
2263
        TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
2264
        TIXMLASSERT( _textPool.CurrentAllocs()      == _textPool.Untracked() );
2265
        TIXMLASSERT( _commentPool.CurrentAllocs()   == _commentPool.Untracked() );
2266
    }
2267
#endif
2268
41.0k
}
2269
2270
2271
void XMLDocument::DeepCopy(XMLDocument* target) const
2272
0
{
2273
0
  TIXMLASSERT(target);
2274
0
    if (target == this) {
2275
0
        return; // technically success - a no-op.
2276
0
    }
2277
2278
0
  target->Clear();
2279
0
  for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {
2280
0
    target->InsertEndChild(node->DeepClone(target));
2281
0
  }
2282
0
}
2283
2284
XMLElement* XMLDocument::NewElement( const char* name )
2285
0
{
2286
0
    XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );
2287
0
    ele->SetName( name );
2288
0
    return ele;
2289
0
}
2290
2291
2292
XMLComment* XMLDocument::NewComment( const char* str )
2293
0
{
2294
0
    XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
2295
0
    comment->SetValue( str );
2296
0
    return comment;
2297
0
}
2298
2299
2300
XMLText* XMLDocument::NewText( const char* str )
2301
0
{
2302
0
    XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
2303
0
    text->SetValue( str );
2304
0
    return text;
2305
0
}
2306
2307
2308
XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2309
0
{
2310
0
    XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
2311
0
    dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2312
0
    return dec;
2313
0
}
2314
2315
2316
XMLUnknown* XMLDocument::NewUnknown( const char* str )
2317
0
{
2318
0
    XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
2319
0
    unk->SetValue( str );
2320
0
    return unk;
2321
0
}
2322
2323
static FILE* callfopen( const char* filepath, const char* mode )
2324
0
{
2325
0
    TIXMLASSERT( filepath );
2326
0
    TIXMLASSERT( mode );
2327
#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2328
    FILE* fp = 0;
2329
    const errno_t err = fopen_s( &fp, filepath, mode );
2330
    if ( err ) {
2331
        return 0;
2332
    }
2333
#else
2334
0
    FILE* fp = fopen( filepath, mode );
2335
0
#endif
2336
0
    return fp;
2337
0
}
2338
2339
18.6k
void XMLDocument::DeleteNode( XMLNode* node ) {
2340
18.6k
    TIXMLASSERT( node );
2341
18.6k
    TIXMLASSERT(node->_document == this );
2342
18.6k
    if (node->_parent) {
2343
0
        node->_parent->DeleteChild( node );
2344
0
    }
2345
18.6k
    else {
2346
        // Isn't in the tree.
2347
        // Use the parent delete.
2348
        // Also, we need to mark it tracked: we 'know'
2349
        // it was never used.
2350
18.6k
        node->_memPool->SetTracked();
2351
        // Call the static XMLNode version:
2352
18.6k
        XMLNode::DeleteNode(node);
2353
18.6k
    }
2354
18.6k
}
2355
2356
2357
XMLError XMLDocument::LoadFile( const char* filename )
2358
0
{
2359
0
    if ( !filename ) {
2360
0
        TIXMLASSERT( false );
2361
0
        SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" );
2362
0
        return _errorID;
2363
0
    }
2364
2365
0
    Clear();
2366
0
    FILE* fp = callfopen( filename, "rb" );
2367
0
    if ( !fp ) {
2368
0
        SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename );
2369
0
        return _errorID;
2370
0
    }
2371
0
    LoadFile( fp );
2372
0
    fclose( fp );
2373
0
    return _errorID;
2374
0
}
2375
2376
XMLError XMLDocument::LoadFile( FILE* fp )
2377
0
{
2378
0
    Clear();
2379
2380
0
    TIXML_FSEEK( fp, 0, SEEK_SET );
2381
0
    if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
2382
0
        SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2383
0
        return _errorID;
2384
0
    }
2385
2386
0
    TIXML_FSEEK( fp, 0, SEEK_END );
2387
2388
0
    unsigned long long filelength;
2389
0
    {
2390
0
        const long long fileLengthSigned = TIXML_FTELL( fp );
2391
0
        TIXML_FSEEK( fp, 0, SEEK_SET );
2392
0
        if ( fileLengthSigned == -1L ) {
2393
0
            SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2394
0
            return _errorID;
2395
0
        }
2396
0
        TIXMLASSERT( fileLengthSigned >= 0 );
2397
0
        filelength = static_cast<unsigned long long>(fileLengthSigned);
2398
0
    }
2399
2400
0
    const size_t maxSizeT = static_cast<size_t>(-1);
2401
    // We'll do the comparison as an unsigned long long, because that's guaranteed to be at
2402
    // least 8 bytes, even on a 32-bit platform.
2403
0
    if ( filelength >= static_cast<unsigned long long>(maxSizeT) ) {
2404
        // Cannot handle files which won't fit in buffer together with null terminator
2405
0
        SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2406
0
        return _errorID;
2407
0
    }
2408
2409
0
    if ( filelength == 0 ) {
2410
0
        SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2411
0
        return _errorID;
2412
0
    }
2413
2414
0
    const size_t size = static_cast<size_t>(filelength);
2415
0
    TIXMLASSERT( _charBuffer == 0 );
2416
0
    _charBuffer = new char[size+1];
2417
0
    const size_t read = fread( _charBuffer, 1, size, fp );
2418
0
    if ( read != size ) {
2419
0
        SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2420
0
        return _errorID;
2421
0
    }
2422
2423
0
    _charBuffer[size] = 0;
2424
2425
0
    Parse();
2426
0
    return _errorID;
2427
0
}
2428
2429
2430
XMLError XMLDocument::SaveFile( const char* filename, bool compact )
2431
0
{
2432
0
    if ( !filename ) {
2433
0
        TIXMLASSERT( false );
2434
0
        SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" );
2435
0
        return _errorID;
2436
0
    }
2437
2438
0
    FILE* fp = callfopen( filename, "w" );
2439
0
    if ( !fp ) {
2440
0
        SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename );
2441
0
        return _errorID;
2442
0
    }
2443
0
    SaveFile(fp, compact);
2444
0
    fclose( fp );
2445
0
    return _errorID;
2446
0
}
2447
2448
2449
XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
2450
0
{
2451
    // Clear any error from the last save, otherwise it will get reported
2452
    // for *this* call.
2453
0
    ClearError();
2454
0
    XMLPrinter stream( fp, compact );
2455
0
    Print( &stream );
2456
0
    return _errorID;
2457
0
}
2458
2459
2460
XMLError XMLDocument::Parse( const char* xml, size_t nBytes )
2461
20.5k
{
2462
20.5k
    Clear();
2463
2464
20.5k
    if ( nBytes == 0 || !xml || !*xml ) {
2465
17
        SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2466
17
        return _errorID;
2467
17
    }
2468
20.5k
    if ( nBytes == static_cast<size_t>(-1) ) {
2469
0
        nBytes = strlen( xml );
2470
0
    }
2471
20.5k
    TIXMLASSERT( _charBuffer == 0 );
2472
20.5k
    _charBuffer = new char[ nBytes+1 ];
2473
20.5k
    memcpy( _charBuffer, xml, nBytes );
2474
20.5k
    _charBuffer[nBytes] = 0;
2475
2476
20.5k
    Parse();
2477
20.5k
    if ( Error() ) {
2478
        // clean up now essentially dangling memory.
2479
        // and the parse fail can put objects in the
2480
        // pools that are dead and inaccessible.
2481
1.30k
        DeleteChildren();
2482
1.30k
        _elementPool.Clear();
2483
1.30k
        _attributePool.Clear();
2484
1.30k
        _textPool.Clear();
2485
1.30k
        _commentPool.Clear();
2486
1.30k
    }
2487
20.5k
    return _errorID;
2488
20.5k
}
2489
2490
2491
void XMLDocument::Print( XMLPrinter* streamer ) const
2492
9.59k
{
2493
9.59k
    if ( streamer ) {
2494
9.59k
        Accept( streamer );
2495
9.59k
    }
2496
0
    else {
2497
0
        XMLPrinter stdoutStreamer( stdout );
2498
0
        Accept( &stdoutStreamer );
2499
0
    }
2500
9.59k
}
2501
2502
2503
41.0k
void XMLDocument::ClearError() {
2504
41.0k
    _errorID = XML_SUCCESS;
2505
41.0k
    _errorLineNum = 0;
2506
41.0k
    _errorStr.Reset();
2507
41.0k
}
2508
2509
2510
void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... )
2511
1.32k
{
2512
1.32k
    TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
2513
1.32k
    _errorID = error;
2514
1.32k
    _errorLineNum = lineNum;
2515
1.32k
  _errorStr.Reset();
2516
2517
1.32k
    const size_t BUFFER_SIZE = 1000;
2518
1.32k
    char* buffer = new char[BUFFER_SIZE];
2519
2520
1.32k
    TIXMLASSERT(sizeof(error) <= sizeof(int));
2521
1.32k
    TIXML_SNPRINTF(buffer, BUFFER_SIZE, "Error=%s ErrorID=%d (0x%x) Line number=%d", ErrorIDToName(error), int(error), int(error), lineNum);
2522
2523
1.32k
  if (format) {
2524
554
    size_t len = strlen(buffer);
2525
554
    TIXML_SNPRINTF(buffer + len, BUFFER_SIZE - len, ": ");
2526
554
    len = strlen(buffer);
2527
2528
554
    va_list va;
2529
554
    va_start(va, format);
2530
554
    TIXML_VSNPRINTF(buffer + len, BUFFER_SIZE - len, format, va);
2531
554
    va_end(va);
2532
554
  }
2533
1.32k
  _errorStr.SetStr(buffer);
2534
1.32k
  delete[] buffer;
2535
1.32k
}
2536
2537
2538
/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
2539
1.33k
{
2540
1.33k
  TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2541
1.33k
    const char* errorName = _errorNames[errorID];
2542
1.33k
    TIXMLASSERT( errorName && errorName[0] );
2543
1.33k
    return errorName;
2544
1.33k
}
2545
2546
const char* XMLDocument::ErrorStr() const
2547
1.30k
{
2548
1.30k
  return _errorStr.Empty() ? "" : _errorStr.GetStr();
2549
1.30k
}
2550
2551
2552
void XMLDocument::PrintError() const
2553
0
{
2554
0
    printf("%s\n", ErrorStr());
2555
0
}
2556
2557
const char* XMLDocument::ErrorName() const
2558
13
{
2559
13
    return ErrorIDToName(_errorID);
2560
13
}
2561
2562
void XMLDocument::Parse()
2563
20.5k
{
2564
20.5k
    TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2565
20.5k
    TIXMLASSERT( _charBuffer );
2566
20.5k
    _parseCurLineNum = 1;
2567
20.5k
    _parseLineNum = 1;
2568
20.5k
    char* p = _charBuffer;
2569
20.5k
    p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
2570
20.5k
    p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
2571
20.5k
    if ( !*p ) {
2572
16
        SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2573
16
        return;
2574
16
    }
2575
20.5k
    ParseDeep(p, 0, &_parseCurLineNum );
2576
20.5k
}
2577
2578
void XMLDocument::PushDepth()
2579
1.29M
{
2580
1.29M
  _parsingDepth++;
2581
1.29M
  if (_parsingDepth == TINYXML2_MAX_ELEMENT_DEPTH) {
2582
3
    SetError(XML_ELEMENT_DEPTH_EXCEEDED, _parseCurLineNum, "Element nesting is too deep." );
2583
3
  }
2584
1.29M
}
2585
2586
void XMLDocument::PopDepth()
2587
1.29M
{
2588
1.29M
  TIXMLASSERT(_parsingDepth > 0);
2589
1.29M
  --_parsingDepth;
2590
1.29M
}
2591
2592
XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
2593
9.59k
    _elementJustOpened( false ),
2594
9.59k
    _stack(),
2595
9.59k
    _firstElement( true ),
2596
9.59k
    _fp( file ),
2597
9.59k
    _depth( depth ),
2598
9.59k
    _textDepth( -1 ),
2599
9.59k
    _processEntities( true ),
2600
9.59k
    _compactMode( compact ),
2601
9.59k
    _buffer()
2602
9.59k
{
2603
623k
    for( int i=0; i<ENTITY_RANGE; ++i ) {
2604
613k
        _entityFlag[i] = false;
2605
613k
        _restrictedEntityFlag[i] = false;
2606
613k
    }
2607
57.5k
    for( int i=0; i<NUM_ENTITIES; ++i ) {
2608
47.9k
        const char entityValue = entities[i].value;
2609
47.9k
        const unsigned char flagIndex = static_cast<unsigned char>(entityValue);
2610
47.9k
        TIXMLASSERT( flagIndex < ENTITY_RANGE );
2611
47.9k
        _entityFlag[flagIndex] = true;
2612
47.9k
    }
2613
9.59k
    _restrictedEntityFlag[static_cast<unsigned char>('&')] = true;
2614
9.59k
    _restrictedEntityFlag[static_cast<unsigned char>('<')] = true;
2615
9.59k
    _restrictedEntityFlag[static_cast<unsigned char>('>')] = true;  // not required, but consistency is nice
2616
9.59k
    _buffer.Push( 0 );
2617
9.59k
}
2618
2619
2620
void XMLPrinter::Print( const char* format, ... )
2621
0
{
2622
0
    va_list     va;
2623
0
    va_start( va, format );
2624
2625
0
    if ( _fp ) {
2626
0
        vfprintf( _fp, format, va );
2627
0
    }
2628
0
    else {
2629
0
        const int len = TIXML_VSCPRINTF( format, va );
2630
        // Close out and re-start the va-args
2631
0
        va_end( va );
2632
0
        TIXMLASSERT( len >= 0 );
2633
0
        va_start( va, format );
2634
0
        TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
2635
0
        char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
2636
0
    TIXML_VSNPRINTF( p, len+1, format, va );
2637
0
    }
2638
0
    va_end( va );
2639
0
}
2640
2641
2642
void XMLPrinter::Write( const char* data, size_t size )
2643
299M
{
2644
299M
    if ( _fp ) {
2645
0
        fwrite ( data , sizeof(char), size, _fp);
2646
0
    }
2647
299M
    else {
2648
299M
        char* p = _buffer.PushArr( static_cast<int>(size) ) - 1;   // back up over the null terminator.
2649
299M
        memcpy( p, data, size );
2650
299M
        p[size] = 0;
2651
299M
    }
2652
299M
}
2653
2654
2655
void XMLPrinter::Putc( char ch )
2656
5.03M
{
2657
5.03M
    if ( _fp ) {
2658
0
        fputc ( ch, _fp);
2659
0
    }
2660
5.03M
    else {
2661
5.03M
        char* p = _buffer.PushArr( sizeof(char) ) - 1;   // back up over the null terminator.
2662
5.03M
        p[0] = ch;
2663
5.03M
        p[1] = 0;
2664
5.03M
    }
2665
5.03M
}
2666
2667
2668
void XMLPrinter::PrintSpace( int depth )
2669
2.51M
{
2670
294M
    for( int i=0; i<depth; ++i ) {
2671
291M
        Write( "    " );
2672
291M
    }
2673
2.51M
}
2674
2675
2676
void XMLPrinter::PrintString( const char* p, bool restricted )
2677
1.10M
{
2678
    // Look for runs of bytes between entities to print.
2679
1.10M
    const char* q = p;
2680
2681
1.10M
    if ( _processEntities ) {
2682
1.10M
        const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
2683
5.50M
        while ( *q ) {
2684
4.40M
            TIXMLASSERT( p <= q );
2685
            // Remember, char is sometimes signed. (How many times has that bitten me?)
2686
4.40M
            if ( *q > 0 && *q < ENTITY_RANGE ) {
2687
                // Check for entities. If one is found, flush
2688
                // the stream up until the entity, write the
2689
                // entity, and keep looking.
2690
3.68M
                if ( flag[static_cast<unsigned char>(*q)] ) {
2691
290k
                    while ( p < q ) {
2692
112k
                        const size_t delta = q - p;
2693
112k
                        const int toPrint = ( INT_MAX < delta ) ? INT_MAX : static_cast<int>(delta);
2694
112k
                        Write( p, toPrint );
2695
112k
                        p += toPrint;
2696
112k
                    }
2697
178k
                    bool entityPatternPrinted = false;
2698
692k
                    for( int i=0; i<NUM_ENTITIES; ++i ) {
2699
692k
                        if ( entities[i].value == *q ) {
2700
178k
                            Putc( '&' );
2701
178k
                            Write( entities[i].pattern, entities[i].length );
2702
178k
                            Putc( ';' );
2703
178k
                            entityPatternPrinted = true;
2704
178k
                            break;
2705
178k
                        }
2706
692k
                    }
2707
178k
                    if ( !entityPatternPrinted ) {
2708
                        // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2709
0
                        TIXMLASSERT( false );
2710
0
                    }
2711
178k
                    ++p;
2712
178k
                }
2713
3.68M
            }
2714
4.40M
            ++q;
2715
4.40M
            TIXMLASSERT( p <= q );
2716
4.40M
        }
2717
        // Flush the remaining string. This will be the entire
2718
        // string if an entity wasn't found.
2719
1.10M
        if ( p < q ) {
2720
971k
            const size_t delta = q - p;
2721
971k
            const int toPrint = ( INT_MAX < delta ) ? INT_MAX : static_cast<int>(delta);
2722
971k
            Write( p, toPrint );
2723
971k
        }
2724
1.10M
    }
2725
0
    else {
2726
0
        Write( p );
2727
0
    }
2728
1.10M
}
2729
2730
2731
void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
2732
1
{
2733
1
    if ( writeBOM ) {
2734
1
        static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
2735
1
        Write( reinterpret_cast< const char* >( bom ) );
2736
1
    }
2737
1
    if ( writeDec ) {
2738
0
        PushDeclaration( "xml version=\"1.0\"" );
2739
0
    }
2740
1
}
2741
2742
void XMLPrinter::PrepareForNewNode( bool compactMode )
2743
2.01M
{
2744
2.01M
    SealElementIfJustOpened();
2745
2746
2.01M
    if ( compactMode ) {
2747
0
        return;
2748
0
    }
2749
2750
2.01M
    if ( _firstElement ) {
2751
9.59k
        PrintSpace (_depth);
2752
2.00M
    } else if ( _textDepth < 0) {
2753
1.97M
        Putc( '\n' );
2754
1.97M
        PrintSpace( _depth );
2755
1.97M
    }
2756
2757
2.01M
    _firstElement = false;
2758
2.01M
}
2759
2760
void XMLPrinter::OpenElement( const char* name, bool compactMode )
2761
802k
{
2762
802k
    PrepareForNewNode( compactMode );
2763
802k
    _stack.Push( name );
2764
2765
802k
    Write ( "<" );
2766
802k
    Write ( name );
2767
2768
802k
    _elementJustOpened = true;
2769
802k
    ++_depth;
2770
802k
}
2771
2772
2773
void XMLPrinter::PushAttribute( const char* name, const char* value )
2774
88.3k
{
2775
88.3k
    TIXMLASSERT( _elementJustOpened );
2776
88.3k
    Putc ( ' ' );
2777
88.3k
    Write( name );
2778
88.3k
    Write( "=\"" );
2779
88.3k
    PrintString( value, false );
2780
88.3k
    Putc ( '\"' );
2781
88.3k
}
2782
2783
2784
void XMLPrinter::PushAttribute( const char* name, int v )
2785
0
{
2786
0
    char buf[BUF_SIZE];
2787
0
    XMLUtil::ToStr( v, buf, BUF_SIZE );
2788
0
    PushAttribute( name, buf );
2789
0
}
2790
2791
2792
void XMLPrinter::PushAttribute( const char* name, unsigned v )
2793
0
{
2794
0
    char buf[BUF_SIZE];
2795
0
    XMLUtil::ToStr( v, buf, BUF_SIZE );
2796
0
    PushAttribute( name, buf );
2797
0
}
2798
2799
2800
void XMLPrinter::PushAttribute(const char* name, int64_t v)
2801
0
{
2802
0
  char buf[BUF_SIZE];
2803
0
  XMLUtil::ToStr(v, buf, BUF_SIZE);
2804
0
  PushAttribute(name, buf);
2805
0
}
2806
2807
2808
void XMLPrinter::PushAttribute(const char* name, uint64_t v)
2809
0
{
2810
0
  char buf[BUF_SIZE];
2811
0
  XMLUtil::ToStr(v, buf, BUF_SIZE);
2812
0
  PushAttribute(name, buf);
2813
0
}
2814
2815
2816
void XMLPrinter::PushAttribute( const char* name, bool v )
2817
0
{
2818
0
    char buf[BUF_SIZE];
2819
0
    XMLUtil::ToStr( v, buf, BUF_SIZE );
2820
0
    PushAttribute( name, buf );
2821
0
}
2822
2823
2824
void XMLPrinter::PushAttribute( const char* name, double v )
2825
0
{
2826
0
    char buf[BUF_SIZE];
2827
0
    XMLUtil::ToStr( v, buf, BUF_SIZE );
2828
0
    PushAttribute( name, buf );
2829
0
}
2830
2831
2832
void XMLPrinter::CloseElement( bool compactMode )
2833
802k
{
2834
802k
    --_depth;
2835
802k
    const char* name = _stack.Pop();
2836
2837
802k
    if ( _elementJustOpened ) {
2838
239k
        Write( "/>" );
2839
239k
    }
2840
563k
    else {
2841
563k
        if ( _textDepth < 0 && !compactMode) {
2842
527k
            Putc( '\n' );
2843
527k
            PrintSpace( _depth );
2844
527k
        }
2845
563k
        Write ( "</" );
2846
563k
        Write ( name );
2847
563k
        Write ( ">" );
2848
563k
    }
2849
2850
802k
    if ( _textDepth == _depth ) {
2851
34.9k
        _textDepth = -1;
2852
34.9k
    }
2853
802k
    if ( _depth == 0 && !compactMode) {
2854
218k
        Putc( '\n' );
2855
218k
    }
2856
802k
    _elementJustOpened = false;
2857
802k
}
2858
2859
2860
void XMLPrinter::SealElementIfJustOpened()
2861
3.03M
{
2862
3.03M
    if ( !_elementJustOpened ) {
2863
2.46M
        return;
2864
2.46M
    }
2865
563k
    _elementJustOpened = false;
2866
563k
    Putc( '>' );
2867
563k
}
2868
2869
2870
void XMLPrinter::PushText( const char* text, bool cdata )
2871
1.01M
{
2872
1.01M
    _textDepth = _depth-1;
2873
2874
1.01M
    SealElementIfJustOpened();
2875
1.01M
    if ( cdata ) {
2876
313
        Write( "<![CDATA[" );
2877
313
        Write( text );
2878
313
        Write( "]]>" );
2879
313
    }
2880
1.01M
    else {
2881
1.01M
        PrintString( text, true );
2882
1.01M
    }
2883
1.01M
}
2884
2885
2886
void XMLPrinter::PushText( int64_t value )
2887
0
{
2888
0
    char buf[BUF_SIZE];
2889
0
    XMLUtil::ToStr( value, buf, BUF_SIZE );
2890
0
    PushText( buf, false );
2891
0
}
2892
2893
2894
void XMLPrinter::PushText( uint64_t value )
2895
0
{
2896
0
  char buf[BUF_SIZE];
2897
0
  XMLUtil::ToStr(value, buf, BUF_SIZE);
2898
0
  PushText(buf, false);
2899
0
}
2900
2901
2902
void XMLPrinter::PushText( int value )
2903
0
{
2904
0
    char buf[BUF_SIZE];
2905
0
    XMLUtil::ToStr( value, buf, BUF_SIZE );
2906
0
    PushText( buf, false );
2907
0
}
2908
2909
2910
void XMLPrinter::PushText( unsigned value )
2911
0
{
2912
0
    char buf[BUF_SIZE];
2913
0
    XMLUtil::ToStr( value, buf, BUF_SIZE );
2914
0
    PushText( buf, false );
2915
0
}
2916
2917
2918
void XMLPrinter::PushText( bool value )
2919
0
{
2920
0
    char buf[BUF_SIZE];
2921
0
    XMLUtil::ToStr( value, buf, BUF_SIZE );
2922
0
    PushText( buf, false );
2923
0
}
2924
2925
2926
void XMLPrinter::PushText( float value )
2927
0
{
2928
0
    char buf[BUF_SIZE];
2929
0
    XMLUtil::ToStr( value, buf, BUF_SIZE );
2930
0
    PushText( buf, false );
2931
0
}
2932
2933
2934
void XMLPrinter::PushText( double value )
2935
0
{
2936
0
    char buf[BUF_SIZE];
2937
0
    XMLUtil::ToStr( value, buf, BUF_SIZE );
2938
0
    PushText( buf, false );
2939
0
}
2940
2941
2942
void XMLPrinter::PushComment( const char* comment )
2943
833
{
2944
833
    PrepareForNewNode( _compactMode );
2945
2946
833
    Write( "<!--" );
2947
833
    Write( comment );
2948
833
    Write( "-->" );
2949
833
}
2950
2951
2952
void XMLPrinter::PushDeclaration( const char* value )
2953
551
{
2954
551
    PrepareForNewNode( _compactMode );
2955
2956
551
    Write( "<?" );
2957
551
    Write( value );
2958
551
    Write( "?>" );
2959
551
}
2960
2961
2962
void XMLPrinter::PushUnknown( const char* value )
2963
1.21M
{
2964
1.21M
    PrepareForNewNode( _compactMode );
2965
2966
1.21M
    Write( "<!" );
2967
1.21M
    Write( value );
2968
1.21M
    Putc( '>' );
2969
1.21M
}
2970
2971
2972
bool XMLPrinter::VisitEnter( const XMLDocument& doc )
2973
9.59k
{
2974
9.59k
    _processEntities = doc.ProcessEntities();
2975
9.59k
    if ( doc.HasBOM() ) {
2976
1
        PushHeader( true, false );
2977
1
    }
2978
9.59k
    return true;
2979
9.59k
}
2980
2981
2982
bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
2983
802k
{
2984
802k
    const XMLElement* parentElem = 0;
2985
802k
    if ( element.Parent() ) {
2986
802k
        parentElem = element.Parent()->ToElement();
2987
802k
    }
2988
802k
    const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
2989
802k
    OpenElement( element.Name(), compactMode );
2990
890k
    while ( attribute ) {
2991
88.3k
        PushAttribute( attribute->Name(), attribute->Value() );
2992
88.3k
        attribute = attribute->Next();
2993
88.3k
    }
2994
802k
    return true;
2995
802k
}
2996
2997
2998
bool XMLPrinter::VisitExit( const XMLElement& element )
2999
802k
{
3000
802k
    CloseElement( CompactMode(element) );
3001
802k
    return true;
3002
802k
}
3003
3004
3005
bool XMLPrinter::Visit( const XMLText& text )
3006
1.01M
{
3007
1.01M
    PushText( text.Value(), text.CData() );
3008
1.01M
    return true;
3009
1.01M
}
3010
3011
3012
bool XMLPrinter::Visit( const XMLComment& comment )
3013
833
{
3014
833
    PushComment( comment.Value() );
3015
833
    return true;
3016
833
}
3017
3018
bool XMLPrinter::Visit( const XMLDeclaration& declaration )
3019
551
{
3020
551
    PushDeclaration( declaration.Value() );
3021
551
    return true;
3022
551
}
3023
3024
3025
bool XMLPrinter::Visit( const XMLUnknown& unknown )
3026
1.21M
{
3027
1.21M
    PushUnknown( unknown.Value() );
3028
1.21M
    return true;
3029
1.21M
}
3030
3031
}   // namespace tinyxml2