Coverage Report

Created: 2026-08-14 06:06

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