Coverage Report

Created: 2026-02-15 06:03

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