Coverage Report

Created: 2025-12-20 06:23

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