From: Dimitris Panokostas Date: Mon, 1 Sep 2025 14:12:14 +0000 (+0200) Subject: Upgrade tinyxml2 from v8.0 to v11.0 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=069084553ba8f3fc094443b205cd829438735b88;p=francis%2Fwinuae.git Upgrade tinyxml2 from v8.0 to v11.0 --- diff --git a/include/tinyxml2.h b/include/tinyxml2.h index 172413ec..9626be8a 100644 --- a/include/tinyxml2.h +++ b/include/tinyxml2.h @@ -42,9 +42,6 @@ distribution. #endif #include -/* - TODO: intern strings instead of allocation. -*/ /* gcc: g++ -Wall -DTINYXML2_DEBUG tinyxml2.cpp xmltest.cpp -o gccxmltest.exe @@ -64,7 +61,7 @@ distribution. # pragma warning(disable: 4251) #endif -#ifdef _WIN32 +#ifdef _MSC_VER # ifdef TINYXML2_EXPORT # define TINYXML2_LIB __declspec(dllexport) # elif defined(TINYXML2_IMPORT) @@ -79,30 +76,31 @@ distribution. #endif +#if !defined(TIXMLASSERT) #if defined(TINYXML2_DEBUG) # if defined(_MSC_VER) # // "(void)0," is for suppressing C4127 warning in "assert(false)", "assert(true)" and the like -# define TIXMLASSERT( x ) if ( !((void)0,(x))) { __debugbreak(); } +# define TIXMLASSERT( x ) do { if ( !((void)0,(x))) { __debugbreak(); } } while(false) # elif defined (ANDROID_NDK) # include -# define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); } +# define TIXMLASSERT( x ) do { if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); } } while(false) # else # include # define TIXMLASSERT assert # endif #else -# define TIXMLASSERT( x ) {} +# define TIXMLASSERT( x ) do {} while(false) +#endif #endif - /* Versioning, past 1.0.14: http://semver.org/ */ -static const int TIXML2_MAJOR_VERSION = 8; +static const int TIXML2_MAJOR_VERSION = 11; static const int TIXML2_MINOR_VERSION = 0; static const int TIXML2_PATCH_VERSION = 0; -#define TINYXML2_MAJOR_VERSION 8 +#define TINYXML2_MAJOR_VERSION 11 #define TINYXML2_MINOR_VERSION 0 #define TINYXML2_PATCH_VERSION 0 @@ -111,7 +109,7 @@ static const int TIXML2_PATCH_VERSION = 0; // system, and the capacity of the stack. On the other hand, it's a trivial // attack that can result from ill, malicious, or even correctly formed XML, // so there needs to be a limit in place. -static const int TINYXML2_MAX_ELEMENT_DEPTH = 100; +static const int TINYXML2_MAX_ELEMENT_DEPTH = 500; namespace tinyxml2 { @@ -135,7 +133,7 @@ class XMLPrinter; class TINYXML2_LIB StrPair { public: - enum { + enum Mode { NEEDS_ENTITY_PROCESSING = 0x01, NEEDS_NEWLINE_NORMALIZATION = 0x02, NEEDS_WHITESPACE_COLLAPSING = 0x04, @@ -201,7 +199,7 @@ private: Has a small initial memory pool, so that low or no usage will not cause a call to new/delete */ -template +template class DynArray { public: @@ -229,9 +227,8 @@ public: ++_size; } - T* PushArr( int count ) { - TIXMLASSERT( count >= 0 ); - TIXMLASSERT( _size <= INT_MAX - count ); + T* PushArr( size_t count ) { + TIXMLASSERT( _size <= SIZE_MAX - count ); EnsureCapacity( _size+count ); T* ret = &_mem[_size]; _size += count; @@ -244,7 +241,7 @@ public: return _mem[_size]; } - void PopArr( int count ) { + void PopArr( size_t count ) { TIXMLASSERT( _size >= count ); _size -= count; } @@ -253,13 +250,13 @@ public: return _size == 0; } - T& operator[](int i) { - TIXMLASSERT( i>= 0 && i < _size ); + T& operator[](size_t i) { + TIXMLASSERT( i < _size ); return _mem[i]; } - const T& operator[](int i) const { - TIXMLASSERT( i>= 0 && i < _size ); + const T& operator[](size_t i) const { + TIXMLASSERT( i < _size ); return _mem[i]; } @@ -268,18 +265,18 @@ public: return _mem[ _size - 1]; } - int Size() const { + size_t Size() const { TIXMLASSERT( _size >= 0 ); return _size; } - int Capacity() const { + size_t Capacity() const { TIXMLASSERT( _allocated >= INITIAL_SIZE ); return _allocated; } - void SwapRemove(int i) { - TIXMLASSERT(i >= 0 && i < _size); + void SwapRemove(size_t i) { + TIXMLASSERT(i < _size); TIXMLASSERT(_size > 0); _mem[i] = _mem[_size - 1]; --_size; @@ -299,14 +296,14 @@ private: DynArray( const DynArray& ); // not supported void operator=( const DynArray& ); // not supported - void EnsureCapacity( int cap ) { + void EnsureCapacity( size_t cap ) { TIXMLASSERT( cap > 0 ); if ( cap > _allocated ) { - TIXMLASSERT( cap <= INT_MAX / 2 ); - const int newAllocated = cap * 2; + TIXMLASSERT( cap <= SIZE_MAX / 2 / sizeof(T)); + const size_t newAllocated = cap * 2; T* newMem = new T[newAllocated]; TIXMLASSERT( newAllocated >= _size ); - memcpy( newMem, _mem, sizeof(T)*_size ); // warning: not using constructors, only works for PODs + memcpy( newMem, _mem, sizeof(T) * _size ); // warning: not using constructors, only works for PODs if ( _mem != _pool ) { delete [] _mem; } @@ -317,8 +314,8 @@ private: T* _mem; T _pool[INITIAL_SIZE]; - int _allocated; // objects allocated - int _size; // number objects in use + size_t _allocated; // objects allocated + size_t _size; // number objects in use }; @@ -332,7 +329,7 @@ public: MemPool() {} virtual ~MemPool() {} - virtual int ItemSize() const = 0; + virtual size_t ItemSize() const = 0; virtual void* Alloc() = 0; virtual void Free( void* ) = 0; virtual void SetTracked() = 0; @@ -342,7 +339,7 @@ public: /* Template child class to create pools of the correct type. */ -template< int ITEM_SIZE > +template< size_t ITEM_SIZE > class MemPoolT : public MemPool { public: @@ -364,21 +361,21 @@ public: _nUntracked = 0; } - virtual int ItemSize() const { + virtual size_t ItemSize() const override { return ITEM_SIZE; } - int CurrentAllocs() const { + size_t CurrentAllocs() const { return _currentAllocs; } - virtual void* Alloc() { + virtual void* Alloc() override{ if ( !_root ) { // Need a new block. - Block* block = new Block(); + Block* block = new Block; _blockPtrs.Push( block ); Item* blockItems = block->items; - for( int i = 0; i < ITEMS_PER_BLOCK - 1; ++i ) { + for( size_t i = 0; i < ITEMS_PER_BLOCK - 1; ++i ) { blockItems[i].next = &(blockItems[i + 1]); } blockItems[ITEMS_PER_BLOCK - 1].next = 0; @@ -397,7 +394,7 @@ public: return result; } - virtual void Free( void* mem ) { + virtual void Free( void* mem ) override { if ( !mem ) { return; } @@ -415,11 +412,11 @@ public: ITEM_SIZE, _nAllocs, _blockPtrs.Size() ); } - void SetTracked() { + void SetTracked() override { --_nUntracked; } - int Untracked() const { + size_t Untracked() const { return _nUntracked; } @@ -442,7 +439,7 @@ private: union Item { Item* next; - char itemData[ITEM_SIZE]; + char itemData[static_cast(ITEM_SIZE)]; }; struct Block { Item items[ITEMS_PER_BLOCK]; @@ -450,10 +447,10 @@ private: DynArray< Block*, 10 > _blockPtrs; Item* _root; - int _currentAllocs; - int _nAllocs; - int _maxAllocs; - int _nUntracked; + size_t _currentAllocs; + size_t _nAllocs; + size_t _maxAllocs; + size_t _nUntracked; }; @@ -602,7 +599,7 @@ public: TIXMLASSERT( p ); TIXMLASSERT( q ); TIXMLASSERT( nChar >= 0 ); - return strncmp( p, q, nChar ) == 0; + return strncmp( p, q, static_cast(nChar) ) == 0; } inline static bool IsUTF8Continuation( const char p ) { @@ -731,6 +728,12 @@ public: return 0; } + // ChildElementCount was originally suggested by msteiger on the sourceforge page for TinyXML and modified by KB1SPH for TinyXML-2. + + int ChildElementCount(const char *value) const; + + int ChildElementCount() const; + /** The meaning of 'value' changes for the specific type. @verbatim Document: empty (NULL is returned, not an empty string) @@ -888,7 +891,7 @@ public: If the 'target' is null, then the nodes will be allocated in the current document. If 'target' - is specified, the memory will be allocated is the + is specified, the memory will be allocated in the specified XMLDocument. NOTE: This is probably not the correct tool to @@ -991,12 +994,12 @@ class TINYXML2_LIB XMLText : public XMLNode { friend class XMLDocument; public: - virtual bool Accept( XMLVisitor* visitor ) const; + virtual bool Accept( XMLVisitor* visitor ) const override; - virtual XMLText* ToText() { + virtual XMLText* ToText() override { return this; } - virtual const XMLText* ToText() const { + virtual const XMLText* ToText() const override { return this; } @@ -1009,14 +1012,14 @@ public: return _isCData; } - virtual XMLNode* ShallowClone( XMLDocument* document ) const; - virtual bool ShallowEqual( const XMLNode* compare ) const; + virtual XMLNode* ShallowClone( XMLDocument* document ) const override; + virtual bool ShallowEqual( const XMLNode* compare ) const override; protected: explicit XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {} virtual ~XMLText() {} - char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ); + char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) override; private: bool _isCData; @@ -1031,23 +1034,23 @@ class TINYXML2_LIB XMLComment : public XMLNode { friend class XMLDocument; public: - virtual XMLComment* ToComment() { + virtual XMLComment* ToComment() override { return this; } - virtual const XMLComment* ToComment() const { + virtual const XMLComment* ToComment() const override { return this; } - virtual bool Accept( XMLVisitor* visitor ) const; + virtual bool Accept( XMLVisitor* visitor ) const override; - virtual XMLNode* ShallowClone( XMLDocument* document ) const; - virtual bool ShallowEqual( const XMLNode* compare ) const; + virtual XMLNode* ShallowClone( XMLDocument* document ) const override; + virtual bool ShallowEqual( const XMLNode* compare ) const override; protected: explicit XMLComment( XMLDocument* doc ); virtual ~XMLComment(); - char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr); + char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr) override; private: XMLComment( const XMLComment& ); // not supported @@ -1070,23 +1073,23 @@ class TINYXML2_LIB XMLDeclaration : public XMLNode { friend class XMLDocument; public: - virtual XMLDeclaration* ToDeclaration() { + virtual XMLDeclaration* ToDeclaration() override { return this; } - virtual const XMLDeclaration* ToDeclaration() const { + virtual const XMLDeclaration* ToDeclaration() const override { return this; } - virtual bool Accept( XMLVisitor* visitor ) const; + virtual bool Accept( XMLVisitor* visitor ) const override; - virtual XMLNode* ShallowClone( XMLDocument* document ) const; - virtual bool ShallowEqual( const XMLNode* compare ) const; + virtual XMLNode* ShallowClone( XMLDocument* document ) const override; + virtual bool ShallowEqual( const XMLNode* compare ) const override; protected: explicit XMLDeclaration( XMLDocument* doc ); virtual ~XMLDeclaration(); - char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ); + char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) override; private: XMLDeclaration( const XMLDeclaration& ); // not supported @@ -1105,23 +1108,23 @@ class TINYXML2_LIB XMLUnknown : public XMLNode { friend class XMLDocument; public: - virtual XMLUnknown* ToUnknown() { + virtual XMLUnknown* ToUnknown() override { return this; } - virtual const XMLUnknown* ToUnknown() const { + virtual const XMLUnknown* ToUnknown() const override { return this; } - virtual bool Accept( XMLVisitor* visitor ) const; + virtual bool Accept( XMLVisitor* visitor ) const override; - virtual XMLNode* ShallowClone( XMLDocument* document ) const; - virtual bool ShallowEqual( const XMLNode* compare ) const; + virtual XMLNode* ShallowClone( XMLDocument* document ) const override; + virtual bool ShallowEqual( const XMLNode* compare ) const override; protected: explicit XMLUnknown( XMLDocument* doc ); virtual ~XMLUnknown(); - char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ); + char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) override; private: XMLUnknown( const XMLUnknown& ); // not supported @@ -1273,13 +1276,13 @@ public: SetValue( str, staticMem ); } - virtual XMLElement* ToElement() { + virtual XMLElement* ToElement() override { return this; } - virtual const XMLElement* ToElement() const { + virtual const XMLElement* ToElement() const override { return this; } - virtual bool Accept( XMLVisitor* visitor ) const; + virtual bool Accept( XMLVisitor* visitor ) const override; /** Given an attribute name, Attribute() returns the value for the attribute of that name, or null if none @@ -1675,11 +1678,11 @@ public: ElementClosingType ClosingType() const { return _closingType; } - virtual XMLNode* ShallowClone( XMLDocument* document ) const; - virtual bool ShallowEqual( const XMLNode* compare ) const; + virtual XMLNode* ShallowClone( XMLDocument* document ) const override; + virtual bool ShallowEqual( const XMLNode* compare ) const override; protected: - char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ); + char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) override; private: XMLElement( XMLDocument* doc ); @@ -1703,7 +1706,8 @@ private: enum Whitespace { PRESERVE_WHITESPACE, - COLLAPSE_WHITESPACE + COLLAPSE_WHITESPACE, + PEDANTIC_WHITESPACE }; @@ -1727,11 +1731,11 @@ public: XMLDocument( bool processEntities = true, Whitespace whitespaceMode = PRESERVE_WHITESPACE ); ~XMLDocument(); - virtual XMLDocument* ToDocument() { + virtual XMLDocument* ToDocument() override { TIXMLASSERT( this == _document ); return this; } - virtual const XMLDocument* ToDocument() const { + virtual const XMLDocument* ToDocument() const override { TIXMLASSERT( this == _document ); return this; } @@ -1828,7 +1832,7 @@ public: @endverbatim */ void Print( XMLPrinter* streamer=0 ) const; - virtual bool Accept( XMLVisitor* visitor ) const; + virtual bool Accept( XMLVisitor* visitor ) const override; /** Create a new Element associated with @@ -1873,9 +1877,8 @@ public: */ void DeleteNode( XMLNode* node ); - void ClearError() { - SetError(XML_SUCCESS, 0, 0); - } + /// Clears the error flags. + void ClearError(); /// Return true if there was an error parsing the document. bool Error() const { @@ -1915,15 +1918,15 @@ public: void DeepCopy(XMLDocument* target) const; // internal - char* Identify( char* p, XMLNode** node ); + char* Identify( char* p, XMLNode** node, bool first ); // internal void MarkInUse(const XMLNode* const); - virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const { + virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const override{ return 0; } - virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const { + virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const override{ return false; } @@ -1977,11 +1980,11 @@ private: void PushDepth(); void PopDepth(); - template + template NodeType* CreateUnlinkedNode( MemPoolT& pool ); }; -template +template inline NodeType* XMLDocument::CreateUnlinkedNode( MemPoolT& pool ) { TIXMLASSERT( sizeof( NodeType ) == PoolElementSize ); @@ -2286,18 +2289,18 @@ public: void PushDeclaration( const char* value ); void PushUnknown( const char* value ); - virtual bool VisitEnter( const XMLDocument& /*doc*/ ); - virtual bool VisitExit( const XMLDocument& /*doc*/ ) { + virtual bool VisitEnter( const XMLDocument& /*doc*/ ) override; + virtual bool VisitExit( const XMLDocument& /*doc*/ ) override { return true; } - virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute ); - virtual bool VisitExit( const XMLElement& element ); + virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute ) override; + virtual bool VisitExit( const XMLElement& element ) override; - virtual bool Visit( const XMLText& text ); - virtual bool Visit( const XMLComment& comment ); - virtual bool Visit( const XMLDeclaration& declaration ); - virtual bool Visit( const XMLUnknown& unknown ); + virtual bool Visit( const XMLText& text ) override; + virtual bool Visit( const XMLComment& comment ) override; + virtual bool Visit( const XMLDeclaration& declaration ) override; + virtual bool Visit( const XMLUnknown& unknown ) override; /** If in print to memory mode, return a pointer to @@ -2311,7 +2314,7 @@ public: of the XML file in memory. (Note the size returned includes the terminating null.) */ - int CStrSize() const { + size_t CStrSize() const { return _buffer.Size(); } /** @@ -2371,7 +2374,7 @@ private: }; -} // tinyxml2 +} // namespace tinyxml2 #if defined(_MSC_VER) # pragma warning(pop) diff --git a/tinyxml2.cpp b/tinyxml2.cpp index 3dcd3ef2..8bb96358 100644 --- a/tinyxml2.cpp +++ b/tinyxml2.cpp @@ -24,7 +24,7 @@ distribution. #include "tinyxml2.h" #include // yes, this one new style header, is in the Android SDK. -#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__) +#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__) || defined(__CC_ARM) # include # include #else @@ -103,10 +103,10 @@ distribution. #if defined(_WIN64) #define TIXML_FSEEK _fseeki64 #define TIXML_FTELL _ftelli64 -#elif defined(__APPLE__) || (__FreeBSD__) +#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__CYGWIN__) #define TIXML_FSEEK fseeko #define TIXML_FTELL ftello -#elif defined(__unix__) && defined(__x86_64__) +#elif defined(__ANDROID__) && __ANDROID_API__ > 24 #define TIXML_FSEEK fseeko64 #define TIXML_FTELL ftello64 #else @@ -234,13 +234,13 @@ char* StrPair::ParseName( char* p ) if ( !p || !(*p) ) { return 0; } - if ( !XMLUtil::IsNameStartChar( (unsigned char) *p ) ) { + if ( !XMLUtil::IsNameStartChar( static_cast(*p) ) ) { return 0; } char* const start = p; ++p; - while ( *p && XMLUtil::IsNameChar( (unsigned char) *p ) ) { + while ( *p && XMLUtil::IsNameChar( static_cast(*p) ) ) { ++p; } @@ -467,102 +467,94 @@ void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length } -const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length ) +const char* XMLUtil::GetCharacterRef(const char* p, char* value, int* length) { - // Presume an entity, and pull it out. + // Assume an entity, and pull it out. *length = 0; - if ( *(p+1) == '#' && *(p+2) ) { - unsigned long ucs = 0; - TIXMLASSERT( sizeof( ucs ) >= 4 ); + static const uint32_t MAX_CODE_POINT = 0x10FFFF; + + if (*(p + 1) == '#' && *(p + 2)) { + uint32_t ucs = 0; ptrdiff_t delta = 0; - unsigned mult = 1; + uint32_t mult = 1; static const char SEMICOLON = ';'; - if ( *(p+2) == 'x' ) { + bool hex = false; + uint32_t radix = 10; + const char* q = 0; + char terminator = '#'; + + if (*(p + 2) == 'x') { // Hexadecimal. - const char* q = p+3; - if ( !(*q) ) { - return 0; - } + hex = true; + radix = 16; + terminator = 'x'; - q = strchr( q, SEMICOLON ); + q = p + 3; + } + else { + // Decimal. + q = p + 2; + } + if (!(*q)) { + return 0; + } - if ( !q ) { - return 0; - } - TIXMLASSERT( *q == SEMICOLON ); + q = strchr(q, SEMICOLON); + if (!q) { + return 0; + } + TIXMLASSERT(*q == SEMICOLON); - delta = q-p; - --q; + delta = q - p; + --q; - while ( *q != 'x' ) { - unsigned int digit = 0; + while (*q != terminator) { + uint32_t digit = 0; - if ( *q >= '0' && *q <= '9' ) { - digit = *q - '0'; - } - else if ( *q >= 'a' && *q <= 'f' ) { - digit = *q - 'a' + 10; - } - else if ( *q >= 'A' && *q <= 'F' ) { - digit = *q - 'A' + 10; - } - else { - return 0; - } - TIXMLASSERT( digit < 16 ); - TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit ); - const unsigned int digitScaled = mult * digit; - TIXMLASSERT( ucs <= ULONG_MAX - digitScaled ); - ucs += digitScaled; - TIXMLASSERT( mult <= UINT_MAX / 16 ); - mult *= 16; - --q; + if (*q >= '0' && *q <= '9') { + digit = *q - '0'; } - } - else { - // Decimal. - const char* q = p+2; - if ( !(*q) ) { - return 0; + else if (hex && (*q >= 'a' && *q <= 'f')) { + digit = *q - 'a' + 10; } - - q = strchr( q, SEMICOLON ); - - if ( !q ) { + else if (hex && (*q >= 'A' && *q <= 'F')) { + digit = *q - 'A' + 10; + } + else { return 0; } - TIXMLASSERT( *q == SEMICOLON ); - - delta = q-p; - --q; - - while ( *q != '#' ) { - if ( *q >= '0' && *q <= '9' ) { - const unsigned int digit = *q - '0'; - TIXMLASSERT( digit < 10 ); - TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit ); - const unsigned int digitScaled = mult * digit; - TIXMLASSERT( ucs <= ULONG_MAX - digitScaled ); - ucs += digitScaled; - } - else { - return 0; - } - TIXMLASSERT( mult <= UINT_MAX / 10 ); - mult *= 10; - --q; + TIXMLASSERT(digit < radix); + + const unsigned int digitScaled = mult * digit; + ucs += digitScaled; + mult *= radix; + + // Security check: could a value exist that is out of range? + // Easily; limit to the MAX_CODE_POINT, which also allows for a + // bunch of leading zeroes. + if (mult > MAX_CODE_POINT) { + mult = MAX_CODE_POINT; } + --q; + } + // Out of range: + if (ucs > MAX_CODE_POINT) { + return 0; } // convert the UCS to UTF-8 - ConvertUTF32ToUTF8( ucs, value, length ); + ConvertUTF32ToUTF8(ucs, value, length); + if (length == 0) { + // If length is 0, there was an error. (Security? Bad input?) + // Fail safely. + return 0; + } return p + delta + 1; } - return p+1; + return p + 1; } - void XMLUtil::ToStr( int v, char* buffer, int bufferSize ) { TIXML_SNPRINTF( buffer, bufferSize, "%d", v ); @@ -605,13 +597,22 @@ void XMLUtil::ToStr( int64_t v, char* buffer, int bufferSize ) void XMLUtil::ToStr( uint64_t v, char* buffer, int bufferSize ) { // horrible syntax trick to make the compiler happy about %llu - TIXML_SNPRINTF(buffer, bufferSize, "%llu", (long long)v); + TIXML_SNPRINTF(buffer, bufferSize, "%llu", static_cast(v)); } bool XMLUtil::ToInt(const char* str, int* value) { - if (TIXML_SSCANF(str, IsPrefixHex(str) ? "%x" : "%d", value) == 1) { - return true; + if (IsPrefixHex(str)) { + unsigned v; + if (TIXML_SSCANF(str, "%x", &v) == 1) { + *value = static_cast(v); + return true; + } + } + else { + if (TIXML_SSCANF(str, "%d", value) == 1) { + return true; + } } return false; } @@ -670,11 +671,20 @@ bool XMLUtil::ToDouble( const char* str, double* value ) bool XMLUtil::ToInt64(const char* str, int64_t* value) { - long long v = 0; // horrible syntax trick to make the compiler happy about %lld - if (TIXML_SSCANF(str, IsPrefixHex(str) ? "%llx" : "%lld", &v) == 1) { - *value = static_cast(v); - return true; - } + if (IsPrefixHex(str)) { + unsigned long long v = 0; // horrible syntax trick to make the compiler happy about %llx + if (TIXML_SSCANF(str, "%llx", &v) == 1) { + *value = static_cast(v); + return true; + } + } + else { + long long v = 0; // horrible syntax trick to make the compiler happy about %lld + if (TIXML_SSCANF(str, "%lld", &v) == 1) { + *value = static_cast(v); + return true; + } + } return false; } @@ -682,14 +692,14 @@ bool XMLUtil::ToInt64(const char* str, int64_t* value) bool XMLUtil::ToUnsigned64(const char* str, uint64_t* value) { unsigned long long v = 0; // horrible syntax trick to make the compiler happy about %llu if(TIXML_SSCANF(str, IsPrefixHex(str) ? "%llx" : "%llu", &v) == 1) { - *value = (uint64_t)v; + *value = static_cast(v); return true; } return false; } -char* XMLDocument::Identify( char* p, XMLNode** node ) +char* XMLDocument::Identify( char* p, XMLNode** node, bool first ) { TIXMLASSERT( node ); TIXMLASSERT( p ); @@ -741,9 +751,19 @@ char* XMLDocument::Identify( char* p, XMLNode** node ) p += dtdHeaderLen; } else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) { - returnNode = CreateUnlinkedNode( _elementPool ); - returnNode->_parseLineNum = _parseCurLineNum; - p += elementHeaderLen; + + // Preserve whitespace pedantically before closing tag, when it's immediately after opening tag + if (WhitespaceMode() == PEDANTIC_WHITESPACE && first && p != start && *(p + elementHeaderLen) == '/') { + returnNode = CreateUnlinkedNode(_textPool); + returnNode->_parseLineNum = startLine; + p = start; // Back it up, all the text counts. + _parseCurLineNum = startLine; + } + else { + returnNode = CreateUnlinkedNode(_elementPool); + returnNode->_parseLineNum = _parseCurLineNum; + p += elementHeaderLen; + } } else { returnNode = CreateUnlinkedNode( _textPool ); @@ -796,6 +816,34 @@ XMLNode::~XMLNode() } } +// ChildElementCount was originally suggested by msteiger on the sourceforge page for TinyXML and modified by KB1SPH for TinyXML-2. + +int XMLNode::ChildElementCount(const char *value) const { + int count = 0; + + const XMLElement *e = FirstChildElement(value); + + while (e) { + e = e->NextSiblingElement(value); + count++; + } + + return count; +} + +int XMLNode::ChildElementCount() const { + int count = 0; + + const XMLElement *e = FirstChildElement(); + + while (e) { + e = e->NextSiblingElement(); + count++; + } + + return count; +} + const char* XMLNode::Value() const { // Edge case: XMLDocuments don't have a Value. Return null. @@ -1044,21 +1092,23 @@ char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) if (_document->Error()) return 0; + bool first = true; while( p && *p ) { XMLNode* node = 0; - p = _document->Identify( p, &node ); + p = _document->Identify( p, &node, first ); TIXMLASSERT( p ); if ( node == 0 ) { break; } + first = false; const int initialLineNum = node->_parseLineNum; StrPair endTag; p = node->ParseDeep( p, &endTag, curLineNumPtr ); if ( !p ) { - DeleteNode( node ); + _document->DeleteNode( node ); if ( !_document->Error() ) { _document->SetError( XML_ERROR_PARSING, initialLineNum, 0); } @@ -1091,7 +1141,7 @@ char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) } if ( !wellLocated ) { _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, "XMLDeclaration value=%s", decl->Value()); - DeleteNode( node ); + _document->DeleteNode( node ); break; } } @@ -1126,7 +1176,7 @@ char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) } if ( mismatch ) { _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, "XMLElement name=%s", ele->Name()); - DeleteNode( node ); + _document->DeleteNode( node ); break; } } @@ -1637,8 +1687,18 @@ float XMLElement::FloatAttribute(const char* name, float defaultValue) const const char* XMLElement::GetText() const { - if ( FirstChild() && FirstChild()->ToText() ) { - return FirstChild()->Value(); + /* skip comment node */ + const XMLNode* node = FirstChild(); + while (node) { + if (node->ToComment()) { + node = node->NextSibling(); + continue; + } + break; + } + + if ( node && node->ToText() ) { + return node->Value(); } return 0; } @@ -1748,11 +1808,11 @@ XMLError XMLElement::QueryInt64Text(int64_t* ival) const } -XMLError XMLElement::QueryUnsigned64Text(uint64_t* ival) const +XMLError XMLElement::QueryUnsigned64Text(uint64_t* uval) const { if(FirstChild() && FirstChild()->ToText()) { const char* t = FirstChild()->Value(); - if(XMLUtil::ToUnsigned64(t, ival)) { + if(XMLUtil::ToUnsigned64(t, uval)) { return XML_SUCCESS; } return XML_CAN_NOT_CONVERT_TEXT; @@ -1909,7 +1969,7 @@ char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr ) } // attribute. - if (XMLUtil::IsNameStartChar( (unsigned char) *p ) ) { + if (XMLUtil::IsNameStartChar( static_cast(*p) ) ) { XMLAttribute* attrib = CreateAttribute(); TIXMLASSERT( attrib ); attrib->_parseLineNum = _document->_parseCurLineNum; @@ -2153,7 +2213,7 @@ void XMLDocument::MarkInUse(const XMLNode* const node) TIXMLASSERT(node); TIXMLASSERT(node->_parent == 0); - for (int i = 0; i < _unlinked.Size(); ++i) { + for (size_t i = 0; i < _unlinked.Size(); ++i) { if (node == _unlinked[i]) { _unlinked.SwapRemove(i); break; @@ -2384,21 +2444,21 @@ XMLError XMLDocument::SaveFile( FILE* fp, bool compact ) } -XMLError XMLDocument::Parse( const char* p, size_t len ) +XMLError XMLDocument::Parse( const char* xml, size_t nBytes ) { Clear(); - if ( len == 0 || !p || !*p ) { + if ( nBytes == 0 || !xml || !*xml ) { SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); return _errorID; } - if ( len == static_cast(-1) ) { - len = strlen( p ); + if ( nBytes == static_cast(-1) ) { + nBytes = strlen( xml ); } TIXMLASSERT( _charBuffer == 0 ); - _charBuffer = new char[ len+1 ]; - memcpy( _charBuffer, p, len ); - _charBuffer[len] = 0; + _charBuffer = new char[ nBytes+1 ]; + memcpy( _charBuffer, xml, nBytes ); + _charBuffer[nBytes] = 0; Parse(); if ( Error() ) { @@ -2427,9 +2487,16 @@ void XMLDocument::Print( XMLPrinter* streamer ) const } +void XMLDocument::ClearError() { + _errorID = XML_SUCCESS; + _errorLineNum = 0; + _errorStr.Reset(); +} + + void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... ) { - TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT ); + TIXMLASSERT(error >= 0 && error < XML_ERROR_COUNT); _errorID = error; _errorLineNum = lineNum; _errorStr.Reset(); @@ -2438,7 +2505,8 @@ void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... char* buffer = new char[BUFFER_SIZE]; TIXMLASSERT(sizeof(error) <= sizeof(int)); - TIXML_SNPRINTF(buffer, BUFFER_SIZE, "Error=%s ErrorID=%d (0x%x) Line number=%d", ErrorIDToName(error), int(error), int(error), lineNum); + TIXML_SNPRINTF(buffer, BUFFER_SIZE, "Error=%s ErrorID=%d (0x%x) Line number=%d", + ErrorIDToName(error), static_cast(error), static_cast(error), lineNum); if (format) { size_t len = strlen(buffer);