Coverage Report

Created: 2025-01-24 06:31

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