Coverage Report

Created: 2025-12-08 06:56

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