Coverage Report

Created: 2026-05-30 06:49

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