Coverage Report

Created: 2025-10-10 06:05

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