Coverage Report

Created: 2026-01-13 06:44

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
138k
#   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.38k
  #define TIXML_SNPRINTF  snprintf
114
2.30k
  #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.42k
  #define TIXML_FSEEK fseek
135
2.14k
  #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
34.6M
{
175
34.6M
    Reset();
176
34.6M
}
177
178
179
void StrPair::TransferTo( StrPair* other )
180
4.39k
{
181
4.39k
    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.39k
    TIXMLASSERT( other != 0 );
188
4.39k
    TIXMLASSERT( other->_flags == 0 );
189
4.39k
    TIXMLASSERT( other->_start == 0 );
190
4.39k
    TIXMLASSERT( other->_end == 0 );
191
192
4.39k
    other->Reset();
193
194
4.39k
    other->_flags = _flags;
195
4.39k
    other->_start = _start;
196
4.39k
    other->_end = _end;
197
198
4.39k
    _flags = 0;
199
4.39k
    _start = 0;
200
4.39k
    _end = 0;
201
4.39k
}
202
203
204
void StrPair::Reset()
205
53.4M
{
206
53.4M
    if ( _flags & NEEDS_DELETE ) {
207
4.08k
        delete [] _start;
208
4.08k
    }
209
53.4M
    _flags = 0;
210
53.4M
    _start = 0;
211
53.4M
    _end = 0;
212
53.4M
}
213
214
215
void StrPair::SetStr( const char* str, int flags )
216
4.08k
{
217
4.08k
    TIXMLASSERT( str );
218
4.08k
    Reset();
219
4.08k
    size_t len = strlen( str );
220
4.08k
    TIXMLASSERT( _start == 0 );
221
4.08k
    _start = new char[ len+1 ];
222
4.08k
    memcpy( _start, str, len+1 );
223
4.08k
    _end = _start + len;
224
4.08k
    _flags = flags | NEEDS_DELETE;
225
4.08k
}
226
227
228
char* StrPair::ParseText( char* p, const char* endTag, int strFlags, int* curLineNumPtr )
229
14.5M
{
230
14.5M
    TIXMLASSERT( p );
231
14.5M
    TIXMLASSERT( endTag && *endTag );
232
14.5M
  TIXMLASSERT(curLineNumPtr);
233
234
14.5M
    char* start = p;
235
14.5M
    const char  endChar = *endTag;
236
14.5M
    size_t length = strlen( endTag );
237
238
    // Inner loop of text parsing.
239
21.2M
    while ( *p ) {
240
21.2M
        if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
241
14.5M
            Set( start, p, strFlags );
242
14.5M
            return p + length;
243
14.5M
        } else if (*p == '\n') {
244
11.8k
            ++(*curLineNumPtr);
245
11.8k
        }
246
6.74M
        ++p;
247
6.74M
        TIXMLASSERT( p );
248
6.74M
    }
249
1.26k
    return 0;
250
14.5M
}
251
252
253
char* StrPair::ParseName( char* p )
254
4.30M
{
255
4.30M
    if ( !p || !(*p) ) {
256
258
        return 0;
257
258
    }
258
4.30M
    if ( !XMLUtil::IsNameStartChar( static_cast<unsigned char>(*p) ) ) {
259
76
        return 0;
260
76
    }
261
262
4.30M
    char* const start = p;
263
4.30M
    ++p;
264
7.58M
    while ( *p && XMLUtil::IsNameChar( static_cast<unsigned char>(*p) ) ) {
265
3.27M
        ++p;
266
3.27M
    }
267
268
4.30M
    Set( start, p, 0 );
269
4.30M
    return p;
270
4.30M
}
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
12.6M
{
304
12.6M
    TIXMLASSERT( _start );
305
12.6M
    TIXMLASSERT( _end );
306
12.6M
    if ( _flags & NEEDS_FLUSH ) {
307
1.54M
        *_end = 0;
308
1.54M
        _flags ^= NEEDS_FLUSH;
309
310
1.54M
        if ( _flags ) {
311
902
            const char* p = _start; // the read pointer
312
902
            char* q = _start; // the write pointer
313
314
1.09M
            while( p < _end ) {
315
1.09M
                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.69k
                    if ( *(p+1) == LF ) {
320
391
                        p += 2;
321
391
                    }
322
1.29k
                    else {
323
1.29k
                        ++p;
324
1.29k
                    }
325
1.69k
                    *q = LF;
326
1.69k
                    ++q;
327
1.69k
                }
328
1.09M
                else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
329
4.32k
                    if ( *(p+1) == CR ) {
330
687
                        p += 2;
331
687
                    }
332
3.63k
                    else {
333
3.63k
                        ++p;
334
3.63k
                    }
335
4.32k
                    *q = LF;
336
4.32k
                    ++q;
337
4.32k
                }
338
1.08M
                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
206k
                    if ( *(p+1) == '#' ) {
345
131k
                        const int buflen = 10;
346
131k
                        char buf[buflen] = { 0 };
347
131k
                        int len = 0;
348
131k
                        const char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
349
131k
                        if ( adjusted == 0 ) {
350
57.2k
                            *q = *p;
351
57.2k
                            ++p;
352
57.2k
                            ++q;
353
57.2k
                        }
354
74.6k
                        else {
355
74.6k
                            TIXMLASSERT( 0 <= len && len <= buflen );
356
74.6k
                            TIXMLASSERT( q + len <= adjusted );
357
74.6k
                            p = adjusted;
358
74.6k
                            memcpy( q, buf, len );
359
74.6k
                            q += len;
360
74.6k
                        }
361
131k
                    }
362
75.0k
                    else {
363
75.0k
                        bool entityFound = false;
364
446k
                        for( int i = 0; i < NUM_ENTITIES; ++i ) {
365
373k
                            const Entity& entity = entities[i];
366
373k
                            if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
367
2.66k
                                    && *( p + entity.length + 1 ) == ';' ) {
368
                                // Found an entity - convert.
369
1.72k
                                *q = entity.value;
370
1.72k
                                ++q;
371
1.72k
                                p += entity.length + 2;
372
1.72k
                                entityFound = true;
373
1.72k
                                break;
374
1.72k
                            }
375
373k
                        }
376
75.0k
                        if ( !entityFound ) {
377
                            // fixme: treat as error?
378
73.3k
                            ++p;
379
73.3k
                            ++q;
380
73.3k
                        }
381
75.0k
                    }
382
206k
                }
383
881k
                else {
384
881k
                    *q = *p;
385
881k
                    ++p;
386
881k
                    ++q;
387
881k
                }
388
1.09M
            }
389
902
            *q = 0;
390
902
        }
391
        // The loop below has plenty going on, and this
392
        // is a less useful mode. Break it out.
393
1.54M
        if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
394
0
            CollapseWhitespace();
395
0
        }
396
1.54M
        _flags = (_flags & NEEDS_DELETE);
397
1.54M
    }
398
12.6M
    TIXMLASSERT( _start );
399
12.6M
    return _start;
400
12.6M
}
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.36k
{
422
4.36k
    TIXMLASSERT( p );
423
4.36k
    TIXMLASSERT( bom );
424
4.36k
    *bom = false;
425
4.36k
    const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
426
    // Check for BOM:
427
4.36k
    if (    *(pu+0) == TIXML_UTF_LEAD_0
428
63
            && *(pu+1) == TIXML_UTF_LEAD_1
429
35
            && *(pu+2) == TIXML_UTF_LEAD_2 ) {
430
6
        *bom = true;
431
6
        p += 3;
432
6
    }
433
4.36k
    TIXMLASSERT( p );
434
4.36k
    return p;
435
4.36k
}
436
437
438
void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
439
74.6k
{
440
74.6k
    const unsigned long BYTE_MASK = 0xBF;
441
74.6k
    const unsigned long BYTE_MARK = 0x80;
442
74.6k
    const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
443
444
74.6k
    if (input < 0x80) {
445
5.29k
        *length = 1;
446
5.29k
    }
447
69.3k
    else if ( input < 0x800 ) {
448
738
        *length = 2;
449
738
    }
450
68.6k
    else if ( input < 0x10000 ) {
451
67.7k
        *length = 3;
452
67.7k
    }
453
811
    else if ( input < 0x200000 ) {
454
811
        *length = 4;
455
811
    }
456
0
    else {
457
0
        *length = 0;    // This code won't convert this correctly anyway.
458
0
        return;
459
0
    }
460
461
74.6k
    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
74.6k
    switch (*length) {
466
811
        case 4:
467
811
            --output;
468
811
            *output = static_cast<char>((input | BYTE_MARK) & BYTE_MASK);
469
811
            input >>= 6;
470
811
            TIXML_FALLTHROUGH;
471
68.6k
        case 3:
472
68.6k
            --output;
473
68.6k
            *output = static_cast<char>((input | BYTE_MARK) & BYTE_MASK);
474
68.6k
            input >>= 6;
475
68.6k
            TIXML_FALLTHROUGH;
476
69.3k
        case 2:
477
69.3k
            --output;
478
69.3k
            *output = static_cast<char>((input | BYTE_MARK) & BYTE_MASK);
479
69.3k
            input >>= 6;
480
69.3k
            TIXML_FALLTHROUGH;
481
74.6k
        case 1:
482
74.6k
            --output;
483
74.6k
            *output = static_cast<char>(input | FIRST_BYTE_MARK[*length]);
484
74.6k
            break;
485
0
        default:
486
0
            TIXMLASSERT( false );
487
74.6k
    }
488
74.6k
}
489
490
491
const char* XMLUtil::GetCharacterRef(const char* p, char* value, int* length)
492
131k
{
493
    // Assume an entity, and pull it out.
494
131k
    *length = 0;
495
496
131k
    static const uint32_t MAX_CODE_POINT = 0x10FFFF;
497
498
131k
    if (*(p + 1) == '#' && *(p + 2)) {
499
131k
        uint32_t ucs = 0;
500
131k
        ptrdiff_t delta = 0;
501
131k
        uint32_t mult = 1;
502
131k
        static const char SEMICOLON = ';';
503
504
131k
        bool hex = false;
505
131k
        uint32_t radix = 10;
506
131k
        const char* q = 0;
507
131k
        char terminator = '#';
508
509
131k
        if (*(p + 2) == 'x') {
510
            // Hexadecimal.
511
18.6k
            hex = true;
512
18.6k
            radix = 16;
513
18.6k
            terminator = 'x';
514
515
18.6k
            q = p + 3;
516
18.6k
        }
517
113k
        else {
518
            // Decimal.
519
113k
            q = p + 2;
520
113k
        }
521
131k
        if (!(*q)) {
522
16
            return 0;
523
16
        }
524
525
131k
        q = strchr(q, SEMICOLON);
526
131k
        if (!q) {
527
1.02k
            return 0;
528
1.02k
        }
529
130k
        TIXMLASSERT(*q == SEMICOLON);
530
531
130k
        delta = q - p;
532
130k
        --q;
533
534
560k
        while (*q != terminator) {
535
484k
            uint32_t digit = 0;
536
537
484k
            if (*q >= '0' && *q <= '9') {
538
393k
                digit = *q - '0';
539
393k
            }
540
90.9k
            else if (hex && (*q >= 'a' && *q <= 'f')) {
541
2.54k
                digit = *q - 'a' + 10;
542
2.54k
            }
543
88.3k
            else if (hex && (*q >= 'A' && *q <= 'F')) {
544
33.4k
                digit = *q - 'A' + 10;
545
33.4k
            }
546
54.9k
            else {
547
54.9k
                return 0;
548
54.9k
            }
549
429k
            TIXMLASSERT(digit < radix);
550
551
429k
            const unsigned int digitScaled = mult * digit;
552
429k
            ucs += digitScaled;
553
429k
            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
429k
            if (mult > MAX_CODE_POINT) {
559
50.5k
                mult = MAX_CODE_POINT;
560
50.5k
            }
561
429k
            --q;
562
429k
        }
563
        // Out of range:
564
75.8k
        if (ucs > MAX_CODE_POINT) {
565
1.21k
            return 0;
566
1.21k
        }
567
        // convert the UCS to UTF-8
568
74.6k
        ConvertUTF32ToUTF8(ucs, value, length);
569
74.6k
    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
74.6k
        return p + delta + 1;
575
74.6k
    }
576
28
    return p + 1;
577
131k
}
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
15.7M
{
725
15.7M
    TIXMLASSERT( node );
726
15.7M
    TIXMLASSERT( p );
727
15.7M
    char* const start = p;
728
15.7M
    int const startLine = _parseCurLineNum;
729
15.7M
    p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
730
15.7M
    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
15.7M
    static const char* xmlHeader    = { "<?" };
738
15.7M
    static const char* commentHeader  = { "<!--" };
739
15.7M
    static const char* cdataHeader    = { "<![CDATA[" };
740
15.7M
    static const char* dtdHeader    = { "<!" };
741
15.7M
    static const char* elementHeader  = { "<" };  // and a header for everything else; check last.
742
743
15.7M
    static const int xmlHeaderLen   = 2;
744
15.7M
    static const int commentHeaderLen = 4;
745
15.7M
    static const int cdataHeaderLen   = 9;
746
15.7M
    static const int dtdHeaderLen   = 2;
747
15.7M
    static const int elementHeaderLen = 1;
748
749
15.7M
    TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) );   // use same memory pool
750
15.7M
    TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
751
15.7M
    XMLNode* returnNode = 0;
752
15.7M
    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
15.7M
    else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
758
1.03k
        returnNode = CreateUnlinkedNode<XMLComment>( _commentPool );
759
1.03k
        returnNode->_parseLineNum = _parseCurLineNum;
760
1.03k
        p += commentHeaderLen;
761
1.03k
    }
762
15.7M
    else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
763
959
        XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
764
959
        returnNode = text;
765
959
        returnNode->_parseLineNum = _parseCurLineNum;
766
959
        p += cdataHeaderLen;
767
959
        text->SetCData( true );
768
959
    }
769
15.7M
    else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
770
9.18M
        returnNode = CreateUnlinkedNode<XMLUnknown>( _commentPool );
771
9.18M
        returnNode->_parseLineNum = _parseCurLineNum;
772
9.18M
        p += dtdHeaderLen;
773
9.18M
    }
774
6.57M
    else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
775
776
        // Preserve whitespace pedantically before closing tag, when it's immediately after opening tag
777
2.76M
        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
2.76M
        else {
784
2.76M
            returnNode = CreateUnlinkedNode<XMLElement>(_elementPool);
785
2.76M
            returnNode->_parseLineNum = _parseCurLineNum;
786
2.76M
            p += elementHeaderLen;
787
2.76M
        }
788
2.76M
    }
789
3.80M
    else {
790
3.80M
        returnNode = CreateUnlinkedNode<XMLText>( _textPool );
791
3.80M
        returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character
792
3.80M
        p = start;  // Back it up, all the text counts.
793
3.80M
        _parseCurLineNum = startLine;
794
3.80M
    }
795
796
15.7M
    TIXMLASSERT( returnNode );
797
15.7M
    TIXMLASSERT( p );
798
15.7M
    *node = returnNode;
799
15.7M
    return p;
800
15.7M
}
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
15.7M
    _document( doc ),
821
15.7M
    _parent( 0 ),
822
15.7M
    _value(),
823
15.7M
    _parseLineNum( 0 ),
824
15.7M
    _firstChild( 0 ), _lastChild( 0 ),
825
15.7M
    _prev( 0 ), _next( 0 ),
826
15.7M
  _userData( 0 ),
827
15.7M
    _memPool( 0 )
828
15.7M
{
829
15.7M
}
830
831
832
XMLNode::~XMLNode()
833
15.7M
{
834
15.7M
    DeleteChildren();
835
15.7M
    if ( _parent ) {
836
0
        _parent->Unlink( this );
837
0
    }
838
15.7M
}
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
6.69k
{
870
    // Edge case: XMLDocuments don't have a Value. Return null.
871
6.69k
    if ( this->ToDocument() )
872
0
        return 0;
873
6.69k
    return _value.GetStr();
874
6.69k
}
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
15.7M
{
901
31.4M
    while( _firstChild ) {
902
15.6M
        TIXMLASSERT( _lastChild );
903
15.6M
        DeleteChild( _firstChild );
904
15.6M
    }
905
15.7M
    _firstChild = _lastChild = 0;
906
15.7M
}
907
908
909
void XMLNode::Unlink( XMLNode* child )
910
15.6M
{
911
15.6M
    TIXMLASSERT( child );
912
15.6M
    TIXMLASSERT( child->_document == _document );
913
15.6M
    TIXMLASSERT( child->_parent == this );
914
15.6M
    if ( child == _firstChild ) {
915
15.6M
        _firstChild = _firstChild->_next;
916
15.6M
    }
917
15.6M
    if ( child == _lastChild ) {
918
16.3k
        _lastChild = _lastChild->_prev;
919
16.3k
    }
920
921
15.6M
    if ( child->_prev ) {
922
0
        child->_prev->_next = child->_next;
923
0
    }
924
15.6M
    if ( child->_next ) {
925
15.6M
        child->_next->_prev = child->_prev;
926
15.6M
    }
927
15.6M
  child->_next = 0;
928
15.6M
  child->_prev = 0;
929
15.6M
  child->_parent = 0;
930
15.6M
}
931
932
933
void XMLNode::DeleteChild( XMLNode* node )
934
15.6M
{
935
15.6M
    TIXMLASSERT( node );
936
15.6M
    TIXMLASSERT( node->_document == _document );
937
15.6M
    TIXMLASSERT( node->_parent == this );
938
15.6M
    Unlink( node );
939
15.6M
  TIXMLASSERT(node->_prev == 0);
940
15.6M
  TIXMLASSERT(node->_next == 0);
941
15.6M
  TIXMLASSERT(node->_parent == 0);
942
15.6M
    DeleteNode( node );
943
15.6M
}
944
945
946
XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
947
15.6M
{
948
15.6M
    TIXMLASSERT( addThis );
949
15.6M
    if ( addThis->_document != _document ) {
950
0
        TIXMLASSERT( false );
951
0
        return 0;
952
0
    }
953
15.6M
    InsertChildPreamble( addThis );
954
955
15.6M
    if ( _lastChild ) {
956
15.6M
        TIXMLASSERT( _firstChild );
957
15.6M
        TIXMLASSERT( _lastChild->_next == 0 );
958
15.6M
        _lastChild->_next = addThis;
959
15.6M
        addThis->_prev = _lastChild;
960
15.6M
        _lastChild = addThis;
961
962
15.6M
        addThis->_next = 0;
963
15.6M
    }
964
16.3k
    else {
965
16.3k
        TIXMLASSERT( _firstChild == 0 );
966
16.3k
        _firstChild = _lastChild = addThis;
967
968
16.3k
        addThis->_prev = 0;
969
16.3k
        addThis->_next = 0;
970
16.3k
    }
971
15.6M
    addThis->_parent = this;
972
15.6M
    return addThis;
973
15.6M
}
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
103k
{
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
103k
  XMLDocument::DepthTracker tracker(_document);
1113
103k
  if (_document->Error())
1114
2
    return 0;
1115
1116
103k
  bool first = true;
1117
15.7M
  while( p && *p ) {
1118
15.7M
        XMLNode* node = 0;
1119
1120
15.7M
        p = _document->Identify( p, &node, first );
1121
15.7M
        TIXMLASSERT( p );
1122
15.7M
        if ( node == 0 ) {
1123
49
            break;
1124
49
        }
1125
15.7M
        first = false;
1126
1127
15.7M
       const int initialLineNum = node->_parseLineNum;
1128
1129
15.7M
        StrPair endTag;
1130
15.7M
        p = node->ParseDeep( p, &endTag, curLineNumPtr );
1131
15.7M
        if ( !p ) {
1132
97.9k
            _document->DeleteNode( node );
1133
97.9k
            if ( !_document->Error() ) {
1134
472
                _document->SetError( XML_ERROR_PARSING, initialLineNum, 0);
1135
472
            }
1136
97.9k
            break;
1137
97.9k
        }
1138
1139
15.6M
        const XMLDeclaration* const decl = node->ToDeclaration();
1140
15.6M
        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
51
                else {
1160
51
                    wellLocated = true;
1161
51
                }
1162
1.41k
            }
1163
1.44k
            if ( !wellLocated ) {
1164
171
                _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, "XMLDeclaration value=%s", decl->Value());
1165
171
                _document->DeleteNode( node );
1166
171
                break;
1167
171
            }
1168
1.44k
        }
1169
1170
15.6M
        XMLElement* ele = node->ToElement();
1171
15.6M
        if ( ele ) {
1172
            // We read the end tag. Return it to the parent.
1173
2.67M
            if ( ele->ClosingType() == XMLElement::CLOSING ) {
1174
4.41k
                if ( parentEndTag ) {
1175
4.39k
                    ele->_value.TransferTo( parentEndTag );
1176
4.39k
                }
1177
4.41k
                node->_memPool->SetTracked();   // created and then immediately deleted.
1178
4.41k
                DeleteNode( node );
1179
4.41k
                return p;
1180
4.41k
            }
1181
1182
            // Handle an end tag returned to this level.
1183
            // And handle a bunch of annoying errors.
1184
2.66M
            bool mismatch = false;
1185
2.66M
            if ( endTag.Empty() ) {
1186
2.66M
                if ( ele->ClosingType() == XMLElement::OPEN ) {
1187
46
                    mismatch = true;
1188
46
                }
1189
2.66M
            }
1190
4.39k
            else {
1191
4.39k
                if ( ele->ClosingType() != XMLElement::OPEN ) {
1192
0
                    mismatch = true;
1193
0
                }
1194
4.39k
                else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
1195
322
                    mismatch = true;
1196
322
                }
1197
4.39k
            }
1198
2.66M
            if ( mismatch ) {
1199
368
                _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, "XMLElement name=%s", ele->Name());
1200
368
                _document->DeleteNode( node );
1201
368
                break;
1202
368
            }
1203
2.66M
        }
1204
15.6M
        InsertEndChild( node );
1205
15.6M
    }
1206
98.8k
    return 0;
1207
103k
}
1208
1209
/*static*/ void XMLNode::DeleteNode( XMLNode* node )
1210
15.7M
{
1211
15.7M
    if ( node == 0 ) {
1212
0
        return;
1213
0
    }
1214
15.7M
  TIXMLASSERT(node->_document);
1215
15.7M
  if (!node->ToDocument()) {
1216
15.7M
    node->_document->MarkInUse(node);
1217
15.7M
  }
1218
1219
15.7M
    MemPool* pool = node->_memPool;
1220
15.7M
    node->~XMLNode();
1221
15.7M
    pool->Free( node );
1222
15.7M
}
1223
1224
void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
1225
15.6M
{
1226
15.6M
    TIXMLASSERT( insertThis );
1227
15.6M
    TIXMLASSERT( insertThis->_document == _document );
1228
1229
15.6M
  if (insertThis->_parent) {
1230
0
        insertThis->_parent->Unlink( insertThis );
1231
0
  }
1232
15.6M
  else {
1233
15.6M
    insertThis->_document->MarkInUse(insertThis);
1234
15.6M
        insertThis->_memPool->SetTracked();
1235
15.6M
  }
1236
15.6M
}
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.80M
{
1256
3.80M
    if ( this->CData() ) {
1257
959
        p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
1258
959
        if ( !p ) {
1259
165
            _document->SetError( XML_ERROR_PARSING_CDATA, _parseLineNum, 0 );
1260
165
        }
1261
959
        return p;
1262
959
    }
1263
3.80M
    else {
1264
3.80M
        int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1265
3.80M
        if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
1266
0
            flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
1267
0
        }
1268
1269
3.80M
        p = _value.ParseText( p, "<", flags, curLineNumPtr );
1270
3.80M
        if ( p && *p ) {
1271
3.80M
            return p-1;
1272
3.80M
        }
1273
355
        if ( !p ) {
1274
329
            _document->SetError( XML_ERROR_PARSING_TEXT, _parseLineNum, 0 );
1275
329
        }
1276
355
    }
1277
355
    return 0;
1278
3.80M
}
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.03k
XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
1310
1.03k
{
1311
1.03k
}
1312
1313
1314
XMLComment::~XMLComment()
1315
{
1316
}
1317
1318
1319
char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
1320
1.03k
{
1321
    // Comment parses as text.
1322
1.03k
    p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
1323
1.03k
    if ( p == 0 ) {
1324
168
        _document->SetError( XML_ERROR_PARSING_COMMENT, _parseLineNum, 0 );
1325
168
    }
1326
1.03k
    return p;
1327
1.03k
}
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
156
        _document->SetError( XML_ERROR_PARSING_DECLARATION, _parseLineNum, 0 );
1374
156
    }
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.18M
XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1407
9.18M
{
1408
9.18M
}
1409
1410
1411
XMLUnknown::~XMLUnknown()
1412
{
1413
}
1414
1415
1416
char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
1417
9.18M
{
1418
    // Unknown parses as text.
1419
9.18M
    p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
1420
9.18M
    if ( !p ) {
1421
351
        _document->SetError( XML_ERROR_PARSING_UNKNOWN, _parseLineNum, 0 );
1422
351
    }
1423
9.18M
    return p;
1424
9.18M
}
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
12.6M
{
1455
12.6M
    return _name.GetStr();
1456
12.6M
}
1457
1458
const char* XMLAttribute::Value() const
1459
731
{
1460
731
    return _value.GetStr();
1461
731
}
1462
1463
char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
1464
1.53M
{
1465
    // Parse using the name rules: bug fix, was using ParseText before
1466
1.53M
    p = _name.ParseName( p );
1467
1.53M
    if ( !p || !*p ) {
1468
183
        return 0;
1469
183
    }
1470
1471
    // Skip white space before =
1472
1.53M
    p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
1473
1.53M
    if ( *p != '=' ) {
1474
71
        return 0;
1475
71
    }
1476
1477
1.53M
    ++p;  // move up to opening quote
1478
1.53M
    p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
1479
1.53M
    if ( *p != '\"' && *p != '\'' ) {
1480
100
        return 0;
1481
100
    }
1482
1483
1.53M
    const char endTag[2] = { *p, 0 };
1484
1.53M
    ++p;  // move past opening quote
1485
1486
1.53M
    p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
1487
1.53M
    return p;
1488
1.53M
}
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
2.76M
XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
1621
2.76M
    _closingType( OPEN ),
1622
2.76M
    _rootAttribute( 0 )
1623
2.76M
{
1624
2.76M
}
1625
1626
1627
XMLElement::~XMLElement()
1628
2.76M
{
1629
4.30M
    while( _rootAttribute ) {
1630
1.53M
        XMLAttribute* next = _rootAttribute->_next;
1631
1.53M
        DeleteAttribute( _rootAttribute );
1632
1.53M
        _rootAttribute = next;
1633
1.53M
    }
1634
2.76M
}
1635
1636
1637
const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1638
1.53M
{
1639
12.6M
    for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
1640
11.1M
        if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1641
731
            return a;
1642
731
        }
1643
11.1M
    }
1644
1.53M
    return 0;
1645
1.53M
}
1646
1647
1648
const char* XMLElement::Attribute( const char* name, const char* value ) const
1649
1.53M
{
1650
1.53M
    const XMLAttribute* a = FindAttribute( name );
1651
1.53M
    if ( !a ) {
1652
1.53M
        return 0;
1653
1.53M
    }
1654
731
    if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1655
731
        return a->Value();
1656
731
    }
1657
0
    return 0;
1658
731
}
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
2.76M
{
1982
2.76M
    XMLAttribute* prevAttribute = 0;
1983
1984
    // Read the attributes.
1985
4.30M
    while( p ) {
1986
4.30M
        p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
1987
4.30M
        if ( !(*p) ) {
1988
579
            _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, "XMLElement name=%s", Name() );
1989
579
            return 0;
1990
579
        }
1991
1992
        // attribute.
1993
4.30M
        if (XMLUtil::IsNameStartChar( static_cast<unsigned char>(*p) ) ) {
1994
1.53M
            XMLAttribute* attrib = CreateAttribute();
1995
1.53M
            TIXMLASSERT( attrib );
1996
1.53M
            attrib->_parseLineNum = _document->_parseCurLineNum;
1997
1998
1.53M
            const int attrLineNum = attrib->_parseLineNum;
1999
2000
1.53M
            p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
2001
1.53M
            if ( !p || Attribute( attrib->Name() ) ) {
2002
1.18k
                DeleteAttribute( attrib );
2003
1.18k
                _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, attrLineNum, "XMLElement name=%s", Name() );
2004
1.18k
                return 0;
2005
1.18k
            }
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.53M
            if ( prevAttribute ) {
2012
1.42M
                TIXMLASSERT( prevAttribute->_next == 0 );
2013
1.42M
                prevAttribute->_next = attrib;
2014
1.42M
            }
2015
108k
            else {
2016
108k
                TIXMLASSERT( _rootAttribute == 0 );
2017
108k
                _rootAttribute = attrib;
2018
108k
            }
2019
1.53M
            prevAttribute = attrib;
2020
1.53M
        }
2021
        // end of the tag
2022
2.76M
        else if ( *p == '>' ) {
2023
103k
            ++p;
2024
103k
            break;
2025
103k
        }
2026
        // end of the tag
2027
2.66M
        else if ( *p == '/' && *(p+1) == '>' ) {
2028
2.66M
            _closingType = CLOSED;
2029
2.66M
            return p+2; // done; sealed element.
2030
2.66M
        }
2031
90
        else {
2032
90
            _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, 0 );
2033
90
            return 0;
2034
90
        }
2035
4.30M
    }
2036
103k
    return p;
2037
2.76M
}
2038
2039
void XMLElement::DeleteAttribute( XMLAttribute* attribute )
2040
1.53M
{
2041
1.53M
    if ( attribute == 0 ) {
2042
0
        return;
2043
0
    }
2044
1.53M
    MemPool* pool = attribute->_memPool;
2045
1.53M
    attribute->~XMLAttribute();
2046
1.53M
    pool->Free( attribute );
2047
1.53M
}
2048
2049
XMLAttribute* XMLElement::CreateAttribute()
2050
1.53M
{
2051
1.53M
    TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
2052
1.53M
    XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
2053
1.53M
    TIXMLASSERT( attrib );
2054
1.53M
    attrib->_memPool = &_document->_attributePool;
2055
1.53M
    attrib->_memPool->SetTracked();
2056
1.53M
    return attrib;
2057
1.53M
}
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
2.76M
{
2098
    // Read the element name.
2099
2.76M
    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
2.76M
    if ( *p == '/' ) {
2105
4.82k
        _closingType = CLOSING;
2106
4.82k
        ++p;
2107
4.82k
    }
2108
2109
2.76M
    p = _value.ParseName( p );
2110
2.76M
    if ( _value.Empty() ) {
2111
334
        return 0;
2112
334
    }
2113
2114
2.76M
    p = ParseAttributes( p, curLineNumPtr );
2115
2.76M
    if ( !p || !*p || _closingType != OPEN ) {
2116
2.67M
        return p;
2117
2.67M
    }
2118
2119
98.9k
    p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr );
2120
98.9k
    return p;
2121
2.76M
}
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.36k
    XMLNode( 0 ),
2206
4.36k
    _writeBOM( false ),
2207
4.36k
    _processEntities( processEntities ),
2208
4.36k
    _errorID(XML_SUCCESS),
2209
4.36k
    _whitespaceMode( whitespaceMode ),
2210
4.36k
    _errorStr(),
2211
4.36k
    _errorLineNum( 0 ),
2212
4.36k
    _charBuffer( 0 ),
2213
4.36k
    _parseCurLineNum( 0 ),
2214
4.36k
  _parsingDepth(0),
2215
4.36k
    _unlinked(),
2216
4.36k
    _elementPool(),
2217
4.36k
    _attributePool(),
2218
4.36k
    _textPool(),
2219
4.36k
    _commentPool()
2220
4.36k
{
2221
    // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
2222
4.36k
    _document = this;
2223
4.36k
}
2224
2225
2226
XMLDocument::~XMLDocument()
2227
4.36k
{
2228
4.36k
    Clear();
2229
4.36k
}
2230
2231
2232
void XMLDocument::MarkInUse(const XMLNode* const node)
2233
31.4M
{
2234
31.4M
  TIXMLASSERT(node);
2235
31.4M
  TIXMLASSERT(node->_parent == 0);
2236
2237
628M
  for (size_t i = 0; i < _unlinked.Size(); ++i) {
2238
613M
    if (node == _unlinked[i]) {
2239
15.7M
      _unlinked.SwapRemove(i);
2240
15.7M
      break;
2241
15.7M
    }
2242
613M
  }
2243
31.4M
}
2244
2245
void XMLDocument::Clear()
2246
10.8k
{
2247
10.8k
    DeleteChildren();
2248
10.8k
  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
10.8k
    ClearError();
2256
2257
10.8k
    delete [] _charBuffer;
2258
10.8k
    _charBuffer = 0;
2259
10.8k
  _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
10.8k
}
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.14k
{
2333
2.14k
    TIXMLASSERT( filepath );
2334
2.14k
    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.14k
    FILE* fp = fopen( filepath, mode );
2343
2.14k
#endif
2344
2.14k
    return fp;
2345
2.14k
}
2346
2347
98.4k
void XMLDocument::DeleteNode( XMLNode* node ) {
2348
98.4k
    TIXMLASSERT( node );
2349
98.4k
    TIXMLASSERT(node->_document == this );
2350
98.4k
    if (node->_parent) {
2351
0
        node->_parent->DeleteChild( node );
2352
0
    }
2353
98.4k
    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
98.4k
        node->_memPool->SetTracked();
2359
        // Call the static XMLNode version:
2360
98.4k
        XMLNode::DeleteNode(node);
2361
98.4k
    }
2362
98.4k
}
2363
2364
2365
XMLError XMLDocument::LoadFile( const char* filename )
2366
2.14k
{
2367
2.14k
    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.14k
    Clear();
2374
2.14k
    FILE* fp = callfopen( filename, "rb" );
2375
2.14k
    if ( !fp ) {
2376
0
        SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename );
2377
0
        return _errorID;
2378
0
    }
2379
2.14k
    LoadFile( fp );
2380
2.14k
    fclose( fp );
2381
2.14k
    return _errorID;
2382
2.14k
}
2383
2384
XMLError XMLDocument::LoadFile( FILE* fp )
2385
2.14k
{
2386
2.14k
    Clear();
2387
2388
2.14k
    TIXML_FSEEK( fp, 0, SEEK_SET );
2389
2.14k
    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.14k
    TIXML_FSEEK( fp, 0, SEEK_END );
2395
2396
2.14k
    unsigned long long filelength;
2397
2.14k
    {
2398
2.14k
        const long long fileLengthSigned = TIXML_FTELL( fp );
2399
2.14k
        TIXML_FSEEK( fp, 0, SEEK_SET );
2400
2.14k
        if ( fileLengthSigned == -1L ) {
2401
0
            SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2402
0
            return _errorID;
2403
0
        }
2404
2.14k
        TIXMLASSERT( fileLengthSigned >= 0 );
2405
2.14k
        filelength = static_cast<unsigned long long>(fileLengthSigned);
2406
2.14k
    }
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.14k
    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.14k
    if ( filelength == 0 ) {
2418
0
        SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2419
0
        return _errorID;
2420
0
    }
2421
2422
2.14k
    const size_t size = static_cast<size_t>(filelength);
2423
2.14k
    TIXMLASSERT( _charBuffer == 0 );
2424
2.14k
    _charBuffer = new char[size+1];
2425
2.14k
    const size_t read = fread( _charBuffer, 1, size, fp );
2426
2.14k
    if ( read != size ) {
2427
0
        SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2428
0
        return _errorID;
2429
0
    }
2430
2431
2.14k
    _charBuffer[size] = 0;
2432
2433
2.14k
    Parse();
2434
2.14k
    return _errorID;
2435
2.14k
}
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.22k
{
2470
2.22k
    Clear();
2471
2472
2.22k
    if ( nBytes == 0 || !xml || !*xml ) {
2473
2
        SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2474
2
        return _errorID;
2475
2
    }
2476
2.22k
    if ( nBytes == static_cast<size_t>(-1) ) {
2477
2.22k
        nBytes = strlen( xml );
2478
2.22k
    }
2479
2.22k
    TIXMLASSERT( _charBuffer == 0 );
2480
2.22k
    _charBuffer = new char[ nBytes+1 ];
2481
2.22k
    memcpy( _charBuffer, xml, nBytes );
2482
2.22k
    _charBuffer[nBytes] = 0;
2483
2484
2.22k
    Parse();
2485
2.22k
    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.02k
        DeleteChildren();
2490
2.02k
        _elementPool.Clear();
2491
2.02k
        _attributePool.Clear();
2492
2.02k
        _textPool.Clear();
2493
2.02k
        _commentPool.Clear();
2494
2.02k
    }
2495
2.22k
    return _errorID;
2496
2.22k
}
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
10.8k
void XMLDocument::ClearError() {
2512
10.8k
    _errorID = XML_SUCCESS;
2513
10.8k
    _errorLineNum = 0;
2514
10.8k
    _errorStr.Reset();
2515
10.8k
}
2516
2517
2518
void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... )
2519
4.08k
{
2520
4.08k
    TIXMLASSERT(error >= 0 && error < XML_ERROR_COUNT);
2521
4.08k
    _errorID = error;
2522
4.08k
    _errorLineNum = lineNum;
2523
4.08k
  _errorStr.Reset();
2524
2525
4.08k
    const size_t BUFFER_SIZE = 1000;
2526
4.08k
    char* buffer = new char[BUFFER_SIZE];
2527
2528
4.08k
    TIXMLASSERT(sizeof(error) <= sizeof(int));
2529
4.08k
    TIXML_SNPRINTF(buffer, BUFFER_SIZE, "Error=%s ErrorID=%d (0x%x) Line number=%d",
2530
4.08k
        ErrorIDToName(error), static_cast<int>(error), static_cast<unsigned int>(error), lineNum);
2531
2532
4.08k
  if (format) {
2533
2.30k
    size_t len = strlen(buffer);
2534
2.30k
    TIXML_SNPRINTF(buffer + len, BUFFER_SIZE - len, ": ");
2535
2.30k
    len = strlen(buffer);
2536
2537
2.30k
    va_list va;
2538
2.30k
    va_start(va, format);
2539
2.30k
    TIXML_VSNPRINTF(buffer + len, BUFFER_SIZE - len, format, va);
2540
2.30k
    va_end(va);
2541
2.30k
  }
2542
4.08k
  _errorStr.SetStr(buffer);
2543
4.08k
  delete[] buffer;
2544
4.08k
}
2545
2546
2547
/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
2548
4.08k
{
2549
4.08k
  TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2550
4.08k
    const char* errorName = _errorNames[errorID];
2551
4.08k
    TIXMLASSERT( errorName && errorName[0] );
2552
4.08k
    return errorName;
2553
4.08k
}
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.36k
{
2573
4.36k
    TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2574
4.36k
    TIXMLASSERT( _charBuffer );
2575
4.36k
    _parseCurLineNum = 1;
2576
4.36k
    _parseLineNum = 1;
2577
4.36k
    char* p = _charBuffer;
2578
4.36k
    p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
2579
4.36k
    p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
2580
4.36k
    if ( !*p ) {
2581
48
        SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2582
48
        return;
2583
48
    }
2584
4.31k
    ParseDeep(p, 0, &_parseCurLineNum );
2585
4.31k
}
2586
2587
void XMLDocument::PushDepth()
2588
103k
{
2589
103k
  _parsingDepth++;
2590
103k
  if (_parsingDepth == TINYXML2_MAX_ELEMENT_DEPTH) {
2591
2
    SetError(XML_ELEMENT_DEPTH_EXCEEDED, _parseCurLineNum, "Element nesting is too deep." );
2592
2
  }
2593
103k
}
2594
2595
void XMLDocument::PopDepth()
2596
103k
{
2597
103k
  TIXMLASSERT(_parsingDepth > 0);
2598
103k
  --_parsingDepth;
2599
103k
}
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