Coverage Report

Created: 2025-12-14 06:07

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