Coverage Report

Created: 2026-06-10 06:38

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
22.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.33k
  #define TIXML_SNPRINTF  snprintf
83
1.20k
  #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
22.2M
{
147
22.2M
    Reset();
148
22.2M
}
149
150
151
void StrPair::TransferTo( StrPair* other )
152
2.05k
{
153
2.05k
    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.05k
    TIXMLASSERT( other != 0 );
160
2.05k
    TIXMLASSERT( other->_flags == 0 );
161
2.05k
    TIXMLASSERT( other->_start == 0 );
162
2.05k
    TIXMLASSERT( other->_end == 0 );
163
164
2.05k
    other->Reset();
165
166
2.05k
    other->_flags = _flags;
167
2.05k
    other->_start = _start;
168
2.05k
    other->_end = _end;
169
170
2.05k
    _flags = 0;
171
2.05k
    _start = 0;
172
2.05k
    _end = 0;
173
2.05k
}
174
175
176
void StrPair::Reset()
177
34.9M
{
178
34.9M
    if ( _flags & NEEDS_DELETE ) {
179
2.12k
        delete [] _start;
180
2.12k
    }
181
34.9M
    _flags = 0;
182
34.9M
    _start = 0;
183
34.9M
    _end = 0;
184
34.9M
}
185
186
187
void StrPair::SetStr( const char* str, int flags )
188
2.12k
{
189
2.12k
    TIXMLASSERT( str );
190
2.12k
    Reset();
191
2.12k
    size_t len = strlen( str );
192
2.12k
    TIXMLASSERT( _start == 0 );
193
2.12k
    _start = new char[ len+1 ];
194
2.12k
    memcpy( _start, str, len+1 );
195
2.12k
    _end = _start + len;
196
2.12k
    _flags = flags | NEEDS_DELETE;
197
2.12k
}
198
199
200
char* StrPair::ParseText( char* p, const char* endTag, int strFlags, int* curLineNumPtr )
201
9.63M
{
202
9.63M
    TIXMLASSERT( p );
203
9.63M
    TIXMLASSERT( endTag && *endTag );
204
9.63M
  TIXMLASSERT(curLineNumPtr);
205
206
9.63M
    char* start = p;
207
9.63M
    const char  endChar = *endTag;
208
9.63M
    size_t length = strlen( endTag );
209
210
    // Inner loop of text parsing.
211
12.9M
    while ( *p ) {
212
12.9M
        if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
213
9.63M
            Set( start, p, strFlags );
214
9.63M
            return p + length;
215
9.63M
        } else if (*p == '\n') {
216
13.3k
            ++(*curLineNumPtr);
217
13.3k
        }
218
3.28M
        ++p;
219
3.28M
        TIXMLASSERT( p );
220
3.28M
    }
221
633
    return 0;
222
9.63M
}
223
224
225
char* StrPair::ParseName( char* p )
226
3.01M
{
227
3.01M
    if ( !p || !(*p) ) {
228
128
        return 0;
229
128
    }
230
3.01M
    if ( !XMLUtil::IsNameStartChar( static_cast<unsigned char>(*p) ) ) {
231
49
        return 0;
232
49
    }
233
234
3.01M
    char* const start = p;
235
3.01M
    ++p;
236
4.13M
    while ( *p && XMLUtil::IsNameChar( static_cast<unsigned char>(*p) ) ) {
237
1.11M
        ++p;
238
1.11M
    }
239
240
3.01M
    Set( start, p, 0 );
241
3.01M
    return p;
242
3.01M
}
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
12.8M
{
276
12.8M
    TIXMLASSERT( _start );
277
12.8M
    TIXMLASSERT( _end );
278
12.8M
    if ( _flags & NEEDS_FLUSH ) {
279
1.52M
        *_end = 0;
280
1.52M
        _flags ^= NEEDS_FLUSH;
281
282
1.52M
        if ( _flags ) {
283
509
            const char* p = _start; // the read pointer
284
509
            char* q = _start; // the write pointer
285
286
708k
            while( p < _end ) {
287
707k
                if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
288
                    // CR-LF pair becomes LF
289
                    // CR alone becomes LF
290
                    // LF-CR becomes LF
291
403
                    if ( *(p+1) == LF ) {
292
200
                        p += 2;
293
200
                    }
294
203
                    else {
295
203
                        ++p;
296
203
                    }
297
403
                    *q = LF;
298
403
                    ++q;
299
403
                }
300
707k
                else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
301
8.59k
                    if ( *(p+1) == CR ) {
302
906
                        p += 2;
303
906
                    }
304
7.69k
                    else {
305
7.69k
                        ++p;
306
7.69k
                    }
307
8.59k
                    *q = LF;
308
8.59k
                    ++q;
309
8.59k
                }
310
698k
                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
74.5k
                    if ( *(p+1) == '#' ) {
317
56.5k
                        const int buflen = 10;
318
56.5k
                        char buf[buflen] = { 0 };
319
56.5k
                        int len = 0;
320
56.5k
                        const char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
321
56.5k
                        if ( adjusted == 0 ) {
322
42.7k
                            *q = *p;
323
42.7k
                            ++p;
324
42.7k
                            ++q;
325
42.7k
                        }
326
13.8k
                        else {
327
13.8k
                            TIXMLASSERT( 0 <= len && len <= buflen );
328
13.8k
                            TIXMLASSERT( q + len <= adjusted );
329
13.8k
                            p = adjusted;
330
13.8k
                            memcpy( q, buf, len );
331
13.8k
                            q += len;
332
13.8k
                        }
333
56.5k
                    }
334
17.9k
                    else {
335
17.9k
                        bool entityFound = false;
336
104k
                        for( int i = 0; i < NUM_ENTITIES; ++i ) {
337
88.2k
                            const Entity& entity = entities[i];
338
88.2k
                            if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
339
3.04k
                                    && *( p + entity.length + 1 ) == ';' ) {
340
                                // Found an entity - convert.
341
1.76k
                                *q = entity.value;
342
1.76k
                                ++q;
343
1.76k
                                p += entity.length + 2;
344
1.76k
                                entityFound = true;
345
1.76k
                                break;
346
1.76k
                            }
347
88.2k
                        }
348
17.9k
                        if ( !entityFound ) {
349
                            // fixme: treat as error?
350
16.2k
                            ++p;
351
16.2k
                            ++q;
352
16.2k
                        }
353
17.9k
                    }
354
74.5k
                }
355
624k
                else {
356
624k
                    *q = *p;
357
624k
                    ++p;
358
624k
                    ++q;
359
624k
                }
360
707k
            }
361
509
            *q = 0;
362
509
        }
363
        // The loop below has plenty going on, and this
364
        // is a less useful mode. Break it out.
365
1.52M
        if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
366
0
            CollapseWhitespace();
367
0
        }
368
1.52M
        _flags = (_flags & NEEDS_DELETE);
369
1.52M
    }
370
12.8M
    TIXMLASSERT( _start );
371
12.8M
    return _start;
372
12.8M
}
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.31k
{
394
2.31k
    TIXMLASSERT( p );
395
2.31k
    TIXMLASSERT( bom );
396
2.31k
    *bom = false;
397
2.31k
    const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
398
    // Check for BOM:
399
2.31k
    if (    *(pu+0) == TIXML_UTF_LEAD_0
400
31
            && *(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.31k
    TIXMLASSERT( p );
406
2.31k
    return p;
407
2.31k
}
408
409
410
void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
411
13.7k
{
412
13.7k
    const unsigned long BYTE_MASK = 0xBF;
413
13.7k
    const unsigned long BYTE_MARK = 0x80;
414
13.7k
    const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
415
416
13.7k
    if (input < 0x80) {
417
2.42k
        *length = 1;
418
2.42k
    }
419
11.3k
    else if ( input < 0x800 ) {
420
877
        *length = 2;
421
877
    }
422
10.4k
    else if ( input < 0x10000 ) {
423
10.1k
        *length = 3;
424
10.1k
    }
425
328
    else if ( input < 0x200000 ) {
426
328
        *length = 4;
427
328
    }
428
0
    else {
429
0
        *length = 0;    // This code won't convert this correctly anyway.
430
0
        return;
431
0
    }
432
433
13.7k
    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
13.7k
    switch (*length) {
438
328
        case 4:
439
328
            --output;
440
328
            *output = static_cast<char>((input | BYTE_MARK) & BYTE_MASK);
441
328
            input >>= 6;
442
328
            TIXML_FALLTHROUGH;
443
10.4k
        case 3:
444
10.4k
            --output;
445
10.4k
            *output = static_cast<char>((input | BYTE_MARK) & BYTE_MASK);
446
10.4k
            input >>= 6;
447
10.4k
            TIXML_FALLTHROUGH;
448
11.3k
        case 2:
449
11.3k
            --output;
450
11.3k
            *output = static_cast<char>((input | BYTE_MARK) & BYTE_MASK);
451
11.3k
            input >>= 6;
452
11.3k
            TIXML_FALLTHROUGH;
453
13.7k
        case 1:
454
13.7k
            --output;
455
13.7k
            *output = static_cast<char>(input | FIRST_BYTE_MARK[*length]);
456
13.7k
            break;
457
0
        default:
458
0
            TIXMLASSERT( false );
459
13.7k
    }
460
13.7k
}
461
462
463
const char* XMLUtil::GetCharacterRef(const char* p, char* value, int* length)
464
56.5k
{
465
    // Assume an entity, and pull it out.
466
56.5k
    *length = 0;
467
468
56.5k
    static const uint32_t MAX_CODE_POINT = 0x10FFFF;
469
470
56.5k
    if (*(p + 1) == '#' && *(p + 2)) {
471
56.5k
        uint32_t ucs = 0;
472
56.5k
        ptrdiff_t delta = 0;
473
56.5k
        uint32_t mult = 1;
474
56.5k
        static const char SEMICOLON = ';';
475
476
56.5k
        bool hex = false;
477
56.5k
        uint32_t radix = 10;
478
56.5k
        const char* q = 0;
479
56.5k
        char terminator = '#';
480
481
56.5k
        if (*(p + 2) == 'x') {
482
            // Hexadecimal.
483
11.0k
            hex = true;
484
11.0k
            radix = 16;
485
11.0k
            terminator = 'x';
486
487
11.0k
            q = p + 3;
488
11.0k
        }
489
45.5k
        else {
490
            // Decimal.
491
45.5k
            q = p + 2;
492
45.5k
        }
493
56.5k
        if (!(*q)) {
494
8
            return 0;
495
8
        }
496
497
56.5k
        q = strchr(q, SEMICOLON);
498
56.5k
        if (!q) {
499
453
            return 0;
500
453
        }
501
56.1k
        TIXMLASSERT(*q == SEMICOLON);
502
503
56.1k
        delta = q - p;
504
56.1k
        --q;
505
506
175k
        while (*q != terminator) {
507
161k
            uint32_t digit = 0;
508
509
161k
            if (*q >= '0' && *q <= '9') {
510
102k
                digit = *q - '0';
511
102k
            }
512
58.7k
            else if (hex && (*q >= 'a' && *q <= 'f')) {
513
1.05k
                digit = *q - 'a' + 10;
514
1.05k
            }
515
57.6k
            else if (hex && (*q >= 'A' && *q <= 'F')) {
516
17.7k
                digit = *q - 'A' + 10;
517
17.7k
            }
518
39.9k
            else {
519
39.9k
                return 0;
520
39.9k
            }
521
121k
            TIXMLASSERT(digit < radix);
522
523
121k
            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
121k
            if (digitScaled > MAX_CODE_POINT || ucs > MAX_CODE_POINT - digitScaled) {
529
2.36k
                return 0;
530
2.36k
            }
531
118k
            ucs += digitScaled;
532
118k
            mult *= radix;
533
118k
            if (mult > MAX_CODE_POINT) {
534
28.2k
                mult = MAX_CODE_POINT;
535
28.2k
            }
536
118k
            --q;
537
118k
        }
538
        // Out of range:
539
13.7k
        if (ucs > MAX_CODE_POINT) {
540
0
            return 0;
541
0
        }
542
        // convert the UCS to UTF-8
543
13.7k
        ConvertUTF32ToUTF8(ucs, value, length);
544
13.7k
        if (*length == 0) {
545
            // If *length is 0, ConvertUTF32ToUTF8 rejected the code point.
546
            // Fail safely.
547
0
            return 0;
548
0
        }
549
13.7k
        return p + delta + 1;
550
13.7k
    }
551
13
    return p + 1;
552
56.5k
}
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
9.62M
{
700
9.62M
    TIXMLASSERT( node );
701
9.62M
    TIXMLASSERT( p );
702
9.62M
    char* const start = p;
703
9.62M
    int const startLine = _parseCurLineNum;
704
9.62M
    p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
705
9.62M
    if( !*p ) {
706
27
        *node = 0;
707
27
        TIXMLASSERT( p );
708
27
        return p;
709
27
    }
710
711
    // These strings define the matching patterns:
712
9.62M
    static const char* xmlHeader    = { "<?" };
713
9.62M
    static const char* commentHeader  = { "<!--" };
714
9.62M
    static const char* cdataHeader    = { "<![CDATA[" };
715
9.62M
    static const char* dtdHeader    = { "<!" };
716
9.62M
    static const char* elementHeader  = { "<" };  // and a header for everything else; check last.
717
718
9.62M
    static const int xmlHeaderLen   = 2;
719
9.62M
    static const int commentHeaderLen = 4;
720
9.62M
    static const int cdataHeaderLen   = 9;
721
9.62M
    static const int dtdHeaderLen   = 2;
722
9.62M
    static const int elementHeaderLen = 1;
723
724
9.62M
    TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) );   // use same memory pool
725
9.62M
    TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
726
9.62M
    XMLNode* returnNode = 0;
727
9.62M
    if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
728
808
        returnNode = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
729
808
        returnNode->_parseLineNum = _parseCurLineNum;
730
808
        p += xmlHeaderLen;
731
808
    }
732
9.62M
    else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
733
784
        returnNode = CreateUnlinkedNode<XMLComment>( _commentPool );
734
784
        returnNode->_parseLineNum = _parseCurLineNum;
735
784
        p += commentHeaderLen;
736
784
    }
737
9.61M
    else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
738
444
        XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
739
444
        returnNode = text;
740
444
        returnNode->_parseLineNum = _parseCurLineNum;
741
444
        p += cdataHeaderLen;
742
444
        text->SetCData( true );
743
444
    }
744
9.61M
    else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
745
5.82M
        returnNode = CreateUnlinkedNode<XMLUnknown>( _commentPool );
746
5.82M
        returnNode->_parseLineNum = _parseCurLineNum;
747
5.82M
        p += dtdHeaderLen;
748
5.82M
    }
749
3.79M
    else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
750
751
        // Preserve whitespace pedantically before closing tag, when it's immediately after opening tag
752
1.49M
        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.49M
        else {
759
1.49M
            returnNode = CreateUnlinkedNode<XMLElement>(_elementPool);
760
1.49M
            returnNode->_parseLineNum = _parseCurLineNum;
761
1.49M
            p += elementHeaderLen;
762
1.49M
        }
763
1.49M
    }
764
2.29M
    else {
765
2.29M
        returnNode = CreateUnlinkedNode<XMLText>( _textPool );
766
2.29M
        returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character
767
2.29M
        p = start;  // Back it up, all the text counts.
768
2.29M
        _parseCurLineNum = startLine;
769
2.29M
    }
770
771
9.62M
    TIXMLASSERT( returnNode );
772
9.62M
    TIXMLASSERT( p );
773
9.62M
    *node = returnNode;
774
9.62M
    return p;
775
9.62M
}
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
9.62M
    _document( doc ),
796
9.62M
    _parent( 0 ),
797
9.62M
    _value(),
798
9.62M
    _parseLineNum( 0 ),
799
9.62M
    _firstChild( 0 ), _lastChild( 0 ),
800
9.62M
    _prev( 0 ), _next( 0 ),
801
9.62M
  _userData( 0 ),
802
9.62M
    _memPool( 0 )
803
9.62M
{
804
9.62M
}
805
806
807
XMLNode::~XMLNode()
808
9.62M
{
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
9.62M
    XMLNode *currentChild = _firstChild;
813
14.1M
    while (currentChild != NULL) {
814
4.52M
        XMLNode *next = currentChild->_next;
815
4.52M
        currentChild->_parent = 0;
816
4.52M
        DeleteNode(currentChild);
817
4.52M
        currentChild = next;
818
4.52M
    }
819
820
9.62M
    if ( _parent ) {
821
0
        _parent->Unlink( this );
822
0
    }
823
9.62M
}
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.26k
{
855
    // Edge case: XMLDocuments don't have a Value. Return null.
856
3.26k
    if ( this->ToDocument() )
857
0
        return 0;
858
3.26k
    return _value.GetStr();
859
3.26k
}
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.75k
{
886
5.05M
    while( _firstChild ) {
887
5.04M
        TIXMLASSERT( _lastChild );
888
5.04M
        DeleteChild( _firstChild );
889
5.04M
    }
890
6.75k
    _firstChild = _lastChild = 0;
891
6.75k
}
892
893
894
void XMLNode::Unlink( XMLNode* child )
895
5.04M
{
896
5.04M
    TIXMLASSERT( child );
897
5.04M
    TIXMLASSERT( child->_document == _document );
898
5.04M
    TIXMLASSERT( child->_parent == this );
899
5.04M
    if ( child == _firstChild ) {
900
5.04M
        _firstChild = _firstChild->_next;
901
5.04M
    }
902
5.04M
    if ( child == _lastChild ) {
903
537
        _lastChild = _lastChild->_prev;
904
537
    }
905
906
5.04M
    if ( child->_prev ) {
907
0
        child->_prev->_next = child->_next;
908
0
    }
909
5.04M
    if ( child->_next ) {
910
5.04M
        child->_next->_prev = child->_prev;
911
5.04M
    }
912
5.04M
  child->_next = 0;
913
5.04M
  child->_prev = 0;
914
5.04M
  child->_parent = 0;
915
5.04M
}
916
917
918
void XMLNode::DeleteChild( XMLNode* node )
919
5.04M
{
920
5.04M
    TIXMLASSERT( node );
921
5.04M
    TIXMLASSERT( node->_document == _document );
922
5.04M
    TIXMLASSERT( node->_parent == this );
923
5.04M
    Unlink( node );
924
5.04M
  TIXMLASSERT(node->_prev == 0);
925
5.04M
  TIXMLASSERT(node->_next == 0);
926
5.04M
  TIXMLASSERT(node->_parent == 0);
927
5.04M
    DeleteNode( node );
928
5.04M
}
929
930
931
XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
932
9.57M
{
933
9.57M
    TIXMLASSERT( addThis );
934
9.57M
    if ( addThis->_document != _document ) {
935
0
        TIXMLASSERT( false );
936
0
        return 0;
937
0
    }
938
9.57M
    InsertChildPreamble( addThis );
939
940
9.57M
    if ( _lastChild ) {
941
9.56M
        TIXMLASSERT( _firstChild );
942
9.56M
        TIXMLASSERT( _lastChild->_next == 0 );
943
9.56M
        _lastChild->_next = addThis;
944
9.56M
        addThis->_prev = _lastChild;
945
9.56M
        _lastChild = addThis;
946
947
9.56M
        addThis->_next = 0;
948
9.56M
    }
949
5.96k
    else {
950
5.96k
        TIXMLASSERT( _firstChild == 0 );
951
5.96k
        _firstChild = _lastChild = addThis;
952
953
5.96k
        addThis->_prev = 0;
954
5.96k
        addThis->_next = 0;
955
5.96k
    }
956
9.57M
    addThis->_parent = this;
957
9.57M
    return addThis;
958
9.57M
}
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
46.8k
{
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
46.8k
  XMLDocument::DepthTracker tracker(_document);
1098
46.8k
  if (_document->Error())
1099
2
    return 0;
1100
1101
46.8k
  bool first = true;
1102
9.62M
  while( p && *p ) {
1103
9.62M
        XMLNode* node = 0;
1104
1105
9.62M
        p = _document->Identify( p, &node, first );
1106
9.62M
        TIXMLASSERT( p );
1107
9.62M
        if ( node == 0 ) {
1108
27
            break;
1109
27
        }
1110
9.62M
        first = false;
1111
1112
9.62M
       const int initialLineNum = node->_parseLineNum;
1113
1114
9.62M
        StrPair endTag;
1115
9.62M
        p = node->ParseDeep( p, &endTag, curLineNumPtr );
1116
9.62M
        if ( !p ) {
1117
44.2k
            _document->DeleteNode( node );
1118
44.2k
            if ( !_document->Error() ) {
1119
265
                _document->SetError( XML_ERROR_PARSING, initialLineNum, 0);
1120
265
            }
1121
44.2k
            break;
1122
44.2k
        }
1123
1124
9.57M
        const XMLDeclaration* const decl = node->ToDeclaration();
1125
9.57M
        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
729
            bool wellLocated = false;
1135
1136
729
            if (ToDocument()) {
1137
727
                if (FirstChild()) {
1138
701
                    wellLocated =
1139
701
                        FirstChild() &&
1140
701
                        FirstChild()->ToDeclaration() &&
1141
629
                        LastChild() &&
1142
629
                        LastChild()->ToDeclaration();
1143
701
                }
1144
26
                else {
1145
26
                    wellLocated = true;
1146
26
                }
1147
727
            }
1148
729
            if ( !wellLocated ) {
1149
75
                _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, "XMLDeclaration value=%s", decl->Value());
1150
75
                _document->DeleteNode( node );
1151
75
                break;
1152
75
            }
1153
729
        }
1154
1155
9.57M
        XMLElement* ele = node->ToElement();
1156
9.57M
        if ( ele ) {
1157
            // We read the end tag. Return it to the parent.
1158
1.45M
            if ( ele->ClosingType() == XMLElement::CLOSING ) {
1159
2.06k
                if ( parentEndTag ) {
1160
2.05k
                    ele->_value.TransferTo( parentEndTag );
1161
2.05k
                }
1162
2.06k
                node->_memPool->SetTracked();   // created and then immediately deleted.
1163
2.06k
                DeleteNode( node );
1164
2.06k
                return p;
1165
2.06k
            }
1166
1167
            // Handle an end tag returned to this level.
1168
            // And handle a bunch of annoying errors.
1169
1.45M
            bool mismatch = false;
1170
1.45M
            if ( endTag.Empty() ) {
1171
1.45M
                if ( ele->ClosingType() == XMLElement::OPEN ) {
1172
13
                    mismatch = true;
1173
13
                }
1174
1.45M
            }
1175
2.05k
            else {
1176
2.05k
                if ( ele->ClosingType() != XMLElement::OPEN ) {
1177
0
                    mismatch = true;
1178
0
                }
1179
2.05k
                else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
1180
162
                    mismatch = true;
1181
162
                }
1182
2.05k
            }
1183
1.45M
            if ( mismatch ) {
1184
175
                _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, "XMLElement name=%s", ele->Name());
1185
175
                _document->DeleteNode( node );
1186
175
                break;
1187
175
            }
1188
1.45M
        }
1189
9.57M
        InsertEndChild( node );
1190
9.57M
    }
1191
44.7k
    return 0;
1192
46.8k
}
1193
1194
/*static*/ void XMLNode::DeleteNode( XMLNode* node )
1195
9.62M
{
1196
9.62M
    if ( node == 0 ) {
1197
0
        return;
1198
0
    }
1199
9.62M
  TIXMLASSERT(node->_document);
1200
9.62M
  if (!node->ToDocument()) {
1201
9.62M
    node->_document->MarkInUse(node);
1202
9.62M
  }
1203
1204
9.62M
    MemPool* pool = node->_memPool;
1205
9.62M
    node->~XMLNode();
1206
9.62M
    pool->Free( node );
1207
9.62M
}
1208
1209
void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
1210
9.57M
{
1211
9.57M
    TIXMLASSERT( insertThis );
1212
9.57M
    TIXMLASSERT( insertThis->_document == _document );
1213
1214
9.57M
  if (insertThis->_parent) {
1215
0
        insertThis->_parent->Unlink( insertThis );
1216
0
  }
1217
9.57M
  else {
1218
9.57M
    insertThis->_document->MarkInUse(insertThis);
1219
9.57M
        insertThis->_memPool->SetTracked();
1220
9.57M
  }
1221
9.57M
}
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.29M
{
1241
2.29M
    if ( this->CData() ) {
1242
444
        p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
1243
444
        if ( !p ) {
1244
79
            _document->SetError( XML_ERROR_PARSING_CDATA, _parseLineNum, 0 );
1245
79
        }
1246
444
        return p;
1247
444
    }
1248
2.29M
    else {
1249
2.29M
        int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1250
2.29M
        if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
1251
0
            flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
1252
0
        }
1253
1254
2.29M
        p = _value.ParseText( p, "<", flags, curLineNumPtr );
1255
2.29M
        if ( p && *p ) {
1256
2.29M
            return p-1;
1257
2.29M
        }
1258
189
        if ( !p ) {
1259
169
            _document->SetError( XML_ERROR_PARSING_TEXT, _parseLineNum, 0 );
1260
169
        }
1261
189
    }
1262
189
    return 0;
1263
2.29M
}
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
784
XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
1295
784
{
1296
784
}
1297
1298
1299
XMLComment::~XMLComment()
1300
{
1301
}
1302
1303
1304
char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
1305
784
{
1306
    // Comment parses as text.
1307
784
    p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
1308
784
    if ( p == 0 ) {
1309
88
        _document->SetError( XML_ERROR_PARSING_COMMENT, _parseLineNum, 0 );
1310
88
    }
1311
784
    return p;
1312
784
}
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
808
XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1343
808
{
1344
808
}
1345
1346
1347
XMLDeclaration::~XMLDeclaration()
1348
{
1349
    //printf( "~XMLDeclaration\n" );
1350
}
1351
1352
1353
char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
1354
808
{
1355
    // Declaration parses as text.
1356
808
    p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
1357
808
    if ( p == 0 ) {
1358
79
        _document->SetError( XML_ERROR_PARSING_DECLARATION, _parseLineNum, 0 );
1359
79
    }
1360
808
    return p;
1361
808
}
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
5.82M
XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1392
5.82M
{
1393
5.82M
}
1394
1395
1396
XMLUnknown::~XMLUnknown()
1397
{
1398
}
1399
1400
1401
char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
1402
5.82M
{
1403
    // Unknown parses as text.
1404
5.82M
    p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
1405
5.82M
    if ( !p ) {
1406
171
        _document->SetError( XML_ERROR_PARSING_UNKNOWN, _parseLineNum, 0 );
1407
171
    }
1408
5.82M
    return p;
1409
5.82M
}
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
12.8M
{
1440
12.8M
    return _name.GetStr();
1441
12.8M
}
1442
1443
const char* XMLAttribute::Value() const
1444
434
{
1445
434
    return _value.GetStr();
1446
434
}
1447
1448
char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
1449
1.51M
{
1450
    // Parse using the name rules: bug fix, was using ParseText before
1451
1.51M
    p = _name.ParseName( p );
1452
1.51M
    if ( !p || !*p ) {
1453
91
        return 0;
1454
91
    }
1455
1456
    // Skip white space before =
1457
1.51M
    p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
1458
1.51M
    if ( *p != '=' ) {
1459
40
        return 0;
1460
40
    }
1461
1462
1.51M
    ++p;  // move up to opening quote
1463
1.51M
    p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
1464
1.51M
    if ( *p != '\"' && *p != '\'' ) {
1465
58
        return 0;
1466
58
    }
1467
1468
1.51M
    const char endTag[2] = { *p, 0 };
1469
1.51M
    ++p;  // move past opening quote
1470
1471
1.51M
    p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
1472
1.51M
    return p;
1473
1.51M
}
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.49M
XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
1606
1.49M
    _closingType( OPEN ),
1607
1.49M
    _rootAttribute( 0 )
1608
1.49M
{
1609
1.49M
}
1610
1611
1612
XMLElement::~XMLElement()
1613
1.49M
{
1614
3.01M
    while( _rootAttribute ) {
1615
1.51M
        XMLAttribute* next = _rootAttribute->_next;
1616
1.51M
        DeleteAttribute( _rootAttribute );
1617
1.51M
        _rootAttribute = next;
1618
1.51M
    }
1619
1.49M
}
1620
1621
1622
const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1623
1.51M
{
1624
12.8M
    for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
1625
11.3M
        if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1626
434
            return a;
1627
434
        }
1628
11.3M
    }
1629
1.51M
    return 0;
1630
1.51M
}
1631
1632
1633
const char* XMLElement::Attribute( const char* name, const char* value ) const
1634
1.51M
{
1635
1.51M
    const XMLAttribute* a = FindAttribute( name );
1636
1.51M
    if ( !a ) {
1637
1.51M
        return 0;
1638
1.51M
    }
1639
434
    if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1640
434
        return a->Value();
1641
434
    }
1642
0
    return 0;
1643
434
}
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.49M
{
1967
1.49M
    XMLAttribute* prevAttribute = 0;
1968
1969
    // Read the attributes.
1970
3.01M
    while( p ) {
1971
3.01M
        p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
1972
3.01M
        if ( !(*p) ) {
1973
284
            _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, "XMLElement name=%s", Name() );
1974
284
            return 0;
1975
284
        }
1976
1977
        // attribute.
1978
3.01M
        if (XMLUtil::IsNameStartChar( static_cast<unsigned char>(*p) ) ) {
1979
1.51M
            XMLAttribute* attrib = CreateAttribute();
1980
1.51M
            TIXMLASSERT( attrib );
1981
1.51M
            attrib->_parseLineNum = _document->_parseCurLineNum;
1982
1983
1.51M
            const int attrLineNum = attrib->_parseLineNum;
1984
1985
1.51M
            p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
1986
1.51M
            if ( !p || Attribute( attrib->Name() ) ) {
1987
670
                DeleteAttribute( attrib );
1988
670
                _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, attrLineNum, "XMLElement name=%s", Name() );
1989
670
                return 0;
1990
670
            }
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.51M
            if ( prevAttribute ) {
1997
1.41M
                TIXMLASSERT( prevAttribute->_next == 0 );
1998
1.41M
                prevAttribute->_next = attrib;
1999
1.41M
            }
2000
97.8k
            else {
2001
97.8k
                TIXMLASSERT( _rootAttribute == 0 );
2002
97.8k
                _rootAttribute = attrib;
2003
97.8k
            }
2004
1.51M
            prevAttribute = attrib;
2005
1.51M
        }
2006
        // end of the tag
2007
1.49M
        else if ( *p == '>' ) {
2008
46.6k
            ++p;
2009
46.6k
            break;
2010
46.6k
        }
2011
        // end of the tag
2012
1.45M
        else if ( *p == '/' && *(p+1) == '>' ) {
2013
1.45M
            _closingType = CLOSED;
2014
1.45M
            return p+2; // done; sealed element.
2015
1.45M
        }
2016
44
        else {
2017
44
            _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, 0 );
2018
44
            return 0;
2019
44
        }
2020
3.01M
    }
2021
46.6k
    return p;
2022
1.49M
}
2023
2024
void XMLElement::DeleteAttribute( XMLAttribute* attribute )
2025
1.51M
{
2026
1.51M
    if ( attribute == 0 ) {
2027
0
        return;
2028
0
    }
2029
1.51M
    MemPool* pool = attribute->_memPool;
2030
1.51M
    attribute->~XMLAttribute();
2031
1.51M
    pool->Free( attribute );
2032
1.51M
}
2033
2034
XMLAttribute* XMLElement::CreateAttribute()
2035
1.51M
{
2036
1.51M
    TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
2037
1.51M
    XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
2038
1.51M
    TIXMLASSERT( attrib );
2039
1.51M
    attrib->_memPool = &_document->_attributePool;
2040
1.51M
    attrib->_memPool->SetTracked();
2041
1.51M
    return attrib;
2042
1.51M
}
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.49M
{
2083
    // Read the element name.
2084
1.49M
    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.49M
    if ( *p == '/' ) {
2090
2.28k
        _closingType = CLOSING;
2091
2.28k
        ++p;
2092
2.28k
    }
2093
2094
1.49M
    p = _value.ParseName( p );
2095
1.49M
    if ( _value.Empty() ) {
2096
177
        return 0;
2097
177
    }
2098
2099
1.49M
    p = ParseAttributes( p, curLineNumPtr );
2100
1.49M
    if ( !p || !*p || _closingType != OPEN ) {
2101
1.45M
        return p;
2102
1.45M
    }
2103
2104
44.5k
    p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr );
2105
44.5k
    return p;
2106
1.49M
}
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.31k
    XMLNode( 0 ),
2191
2.31k
    _writeBOM( false ),
2192
2.31k
    _processEntities( processEntities ),
2193
2.31k
    _errorID(XML_SUCCESS),
2194
2.31k
    _whitespaceMode( whitespaceMode ),
2195
2.31k
    _errorStr(),
2196
2.31k
    _errorLineNum( 0 ),
2197
2.31k
    _charBuffer( 0 ),
2198
2.31k
    _parseCurLineNum( 0 ),
2199
2.31k
  _parsingDepth(0),
2200
2.31k
    _unlinked(),
2201
2.31k
    _elementPool(),
2202
2.31k
    _attributePool(),
2203
2.31k
    _textPool(),
2204
2.31k
    _commentPool()
2205
2.31k
{
2206
    // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
2207
2.31k
    _document = this;
2208
2.31k
}
2209
2210
2211
XMLDocument::~XMLDocument()
2212
2.31k
{
2213
2.31k
    Clear();
2214
2.31k
}
2215
2216
2217
void XMLDocument::MarkInUse(const XMLNode* const node)
2218
19.1M
{
2219
19.1M
  TIXMLASSERT(node);
2220
19.1M
  TIXMLASSERT(node->_parent == 0);
2221
2222
234M
  for (size_t i = 0; i < _unlinked.Size(); ++i) {
2223
224M
    if (node == _unlinked[i]) {
2224
9.62M
      _unlinked.SwapRemove(i);
2225
9.62M
      break;
2226
9.62M
    }
2227
224M
  }
2228
19.1M
}
2229
2230
void XMLDocument::Clear()
2231
4.62k
{
2232
4.62k
    DeleteChildren();
2233
4.62k
  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.62k
    ClearError();
2241
2242
4.62k
    delete [] _charBuffer;
2243
4.62k
    _charBuffer = 0;
2244
4.62k
  _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.62k
}
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
44.5k
void XMLDocument::DeleteNode( XMLNode* node ) {   
2333
44.5k
    if(node == 0) {
2334
0
        return; // check for null pointer
2335
0
    }
2336
44.5k
    TIXMLASSERT(node->_document == this);
2337
44.5k
    if (node->_parent) {
2338
0
        node->_parent->DeleteChild( node );
2339
0
    }
2340
44.5k
    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
44.5k
        node->_memPool->SetTracked();
2346
        // Call the static XMLNode version:
2347
44.5k
        XMLNode::DeleteNode(node);
2348
44.5k
    }
2349
44.5k
}
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.31k
{
2457
2.31k
    Clear();
2458
2459
2.31k
    if ( nBytes == 0 || !xml || !*xml ) {
2460
3
        SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2461
3
        return _errorID;
2462
3
    }
2463
2.31k
    if ( nBytes == static_cast<size_t>(-1) ) {
2464
2.31k
        nBytes = strlen( xml );
2465
2.31k
    }
2466
2.31k
    TIXMLASSERT( _charBuffer == 0 );
2467
2.31k
    _charBuffer = new char[ nBytes+1 ];
2468
2.31k
    memcpy( _charBuffer, xml, nBytes );
2469
2.31k
    _charBuffer[nBytes] = 0;
2470
2471
2.31k
    Parse();
2472
2.31k
    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.12k
        DeleteChildren();
2477
2.12k
        _elementPool.Clear();
2478
2.12k
        _attributePool.Clear();
2479
2.12k
        _textPool.Clear();
2480
2.12k
        _commentPool.Clear();
2481
2.12k
    }
2482
2.31k
    return _errorID;
2483
2.31k
}
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.62k
void XMLDocument::ClearError() {
2499
4.62k
    _errorID = XML_SUCCESS;
2500
4.62k
    _errorLineNum = 0;
2501
4.62k
    _errorStr.Reset();
2502
4.62k
}
2503
2504
2505
void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... )
2506
2.12k
{
2507
2.12k
    TIXMLASSERT(error >= 0 && error < XML_ERROR_COUNT);
2508
2.12k
    _errorID = error;
2509
2.12k
    _errorLineNum = lineNum;
2510
2.12k
  _errorStr.Reset();
2511
2512
2.12k
    const size_t BUFFER_SIZE = 1000;
2513
2.12k
    char* buffer = new char[BUFFER_SIZE];
2514
2515
2.12k
    TIXMLASSERT(sizeof(error) <= sizeof(int));
2516
2.12k
    TIXML_SNPRINTF(buffer, BUFFER_SIZE, "Error=%s ErrorID=%d (0x%x) Line number=%d",
2517
2.12k
        ErrorIDToName(error), static_cast<int>(error), static_cast<unsigned int>(error), lineNum);
2518
2519
2.12k
  if (format) {
2520
1.20k
    size_t len = strlen(buffer);
2521
1.20k
    TIXML_SNPRINTF(buffer + len, BUFFER_SIZE - len, ": ");
2522
1.20k
    len = strlen(buffer);
2523
2524
1.20k
    va_list va;
2525
1.20k
    va_start(va, format);
2526
1.20k
    TIXML_VSNPRINTF(buffer + len, BUFFER_SIZE - len, format, va);
2527
1.20k
    va_end(va);
2528
1.20k
  }
2529
2.12k
  _errorStr.SetStr(buffer);
2530
2.12k
  delete[] buffer;
2531
2.12k
}
2532
2533
2534
/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
2535
2.12k
{
2536
2.12k
  TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2537
2.12k
    const char* errorName = _errorNames[errorID];
2538
2.12k
    TIXMLASSERT( errorName && errorName[0] );
2539
2.12k
    return errorName;
2540
2.12k
}
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.31k
{
2560
2.31k
    TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2561
2.31k
    TIXMLASSERT( _charBuffer );
2562
2.31k
    _parseCurLineNum = 1;
2563
2.31k
    _parseLineNum = 1;
2564
2.31k
    char* p = _charBuffer;
2565
2.31k
    p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
2566
2.31k
    p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
2567
2.31k
    if ( !*p ) {
2568
23
        SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2569
23
        return;
2570
23
    }
2571
2.28k
    ParseDeep(p, 0, &_parseCurLineNum );
2572
2.28k
}
2573
2574
void XMLDocument::PushDepth()
2575
46.8k
{
2576
46.8k
  _parsingDepth++;
2577
46.8k
  if (_parsingDepth == TINYXML2_MAX_ELEMENT_DEPTH) {
2578
2
    SetError(XML_ELEMENT_DEPTH_EXCEEDED, _parseCurLineNum, "Element nesting is too deep." );
2579
2
  }
2580
46.8k
}
2581
2582
void XMLDocument::PopDepth()
2583
46.8k
{
2584
46.8k
  TIXMLASSERT(_parsingDepth > 0);
2585
46.8k
  --_parsingDepth;
2586
46.8k
}
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