Coverage Report

Created: 2026-03-20 06:30

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