diff --git a/src/aws-cpp-sdk-core/include/aws/core/external/tinyxml2/tinyxml2.h b/src/aws-cpp-sdk-core/include/aws/core/external/tinyxml2/tinyxml2.h index 3721ed1f976..3917ce68620 100644 --- a/src/aws-cpp-sdk-core/include/aws/core/external/tinyxml2/tinyxml2.h +++ b/src/aws-cpp-sdk-core/include/aws/core/external/tinyxml2/tinyxml2.h @@ -106,18 +106,25 @@ This file has been modified from its original version by Amazon: /* Versioning, past 1.0.14: http://semver.org/ */ -static const int TIXML2_MAJOR_VERSION = 6; -static const int TIXML2_MINOR_VERSION = 1; +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 6 -#define TINYXML2_MINOR_VERSION 1 +#define TINYXML2_MAJOR_VERSION 11 +#define TINYXML2_MINOR_VERSION 0 #define TINYXML2_PATCH_VERSION 0 namespace Aws { namespace External { +// A fixed element depth limit is problematic. There needs to be a +// limit to avoid a stack overflow. However, that limit varies per +// 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 = 500; + namespace tinyxml2 { class XMLDocument; @@ -136,11 +143,13 @@ static const char* ALLOCATION_TAG = "AWS::TinyXML"; pointers into the XML file itself, and will apply normalization and entity translation if actually read. Can also store (and memory manage) a traditional char[] + + Isn't clear why TINYXML2_LIB is needed; but seems to fix #719 */ class TINYXML2_LIB StrPair { public: - enum { + enum Mode { NEEDS_ENTITY_PROCESSING = 0x01, NEEDS_NEWLINE_NORMALIZATION = 0x02, NEEDS_WHITESPACE_COLLAPSING = 0x04, @@ -197,7 +206,7 @@ class TINYXML2_LIB StrPair char* _end; StrPair( const StrPair& other ); // not supported - void operator=( StrPair& other ); // not supported, use TransferTo() + void operator=( const StrPair& other ); // not supported, use TransferTo() }; @@ -206,7 +215,7 @@ class TINYXML2_LIB StrPair 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: @@ -234,9 +243,8 @@ class DynArray ++_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; @@ -249,7 +257,7 @@ class DynArray return _mem[_size]; } - void PopArr( int count ) { + void PopArr( size_t count ) { TIXMLASSERT( _size >= count ); _size -= count; } @@ -258,13 +266,13 @@ class DynArray 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]; } @@ -273,18 +281,17 @@ class DynArray return _mem[ _size - 1]; } - int Size() const { - TIXMLASSERT( _size >= 0 ); + size_t Size() const { 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; @@ -295,7 +302,7 @@ class DynArray return _mem; } - T* Mem() { + T* Mem() { TIXMLASSERT( _mem ); return _mem; } @@ -304,14 +311,14 @@ class DynArray 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 ); - int newAllocated = cap * 2; + TIXMLASSERT( cap <= SIZE_MAX / 2 / sizeof(T)); + const size_t newAllocated = cap * 2; T* newMem = Aws::NewArray(newAllocated, ALLOCATION_TAG); 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 ) { Aws::DeleteArray(_mem); } @@ -322,8 +329,8 @@ class DynArray 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 }; @@ -337,24 +344,23 @@ class MemPool 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; - virtual void Clear() = 0; }; /* Template child class to create pools of the correct type. */ -template< int ITEM_SIZE > +template< size_t ITEM_SIZE > class MemPoolT : public MemPool { public: MemPoolT() : _blockPtrs(), _root(0), _currentAllocs(0), _nAllocs(0), _maxAllocs(0), _nUntracked(0) {} ~MemPoolT() { - Clear(); + MemPoolT< ITEM_SIZE >::Clear(); } void Clear() { @@ -370,21 +376,21 @@ class MemPoolT : public MemPool _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 = Aws::New(ALLOCATION_TAG); _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; @@ -403,7 +409,7 @@ class MemPoolT : public MemPool return result; } - virtual void Free( void* mem ) { + virtual void Free( void* mem ) override { if ( !mem ) { return; } @@ -421,11 +427,11 @@ class MemPoolT : public MemPool ITEM_SIZE, _nAllocs, _blockPtrs.Size() ); } - void SetTracked() { + void SetTracked() override { --_nUntracked; } - int Untracked() const { + size_t Untracked() const { return _nUntracked; } @@ -448,7 +454,7 @@ class MemPoolT : public MemPool union Item { Item* next; - char itemData[ITEM_SIZE]; + char itemData[static_cast(ITEM_SIZE)]; }; struct Block { Item items[ITEMS_PER_BLOCK]; @@ -456,10 +462,10 @@ class MemPoolT : public MemPool 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; }; @@ -532,10 +538,8 @@ enum XMLError { XML_ERROR_FILE_NOT_FOUND, XML_ERROR_FILE_COULD_NOT_BE_OPENED, XML_ERROR_FILE_READ_ERROR, - UNUSED_XML_ERROR_ELEMENT_MISMATCH, // remove at next major version XML_ERROR_PARSING_ELEMENT, XML_ERROR_PARSING_ATTRIBUTE, - UNUSED_XML_ERROR_IDENTIFYING_TAG, // remove at next major version XML_ERROR_PARSING_TEXT, XML_ERROR_PARSING_CDATA, XML_ERROR_PARSING_COMMENT, @@ -546,7 +550,7 @@ enum XMLError { XML_ERROR_PARSING, XML_CAN_NOT_CONVERT_TEXT, XML_NO_TEXT_NODE, - + XML_ELEMENT_DEPTH_EXCEEDED, XML_ERROR_COUNT }; @@ -569,7 +573,7 @@ class TINYXML2_LIB XMLUtil TIXMLASSERT( p ); return p; } - static char* SkipWhiteSpace( char* p, int* curLineNumPtr ) { + static char* SkipWhiteSpace( char* const p, int* curLineNumPtr ) { return const_cast( SkipWhiteSpace( const_cast(p), curLineNumPtr ) ); } @@ -597,6 +601,11 @@ class TINYXML2_LIB XMLUtil || ch == '-'; } + inline static bool IsPrefixHex( const char* p) { + p = SkipWhiteSpace(p, 0); + return p && *p == '0' && ( *(p + 1) == 'x' || *(p + 1) == 'X'); + } + inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) { if ( p == q ) { return true; @@ -604,10 +613,10 @@ class TINYXML2_LIB XMLUtil 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( char p ) { + inline static bool IsUTF8Continuation( const char p ) { return ( p & 0x80 ) != 0; } @@ -624,6 +633,7 @@ class TINYXML2_LIB XMLUtil static void ToStr( float v, char* buffer, int bufferSize ); static void ToStr( double v, char* buffer, int bufferSize ); static void ToStr(int64_t v, char* buffer, int bufferSize); + static void ToStr(uint64_t v, char* buffer, int bufferSize); // converts strings to primitive types static bool ToInt( const char* str, int* value ); @@ -632,7 +642,7 @@ class TINYXML2_LIB XMLUtil static bool ToFloat( const char* str, float* value ); static bool ToDouble( const char* str, double* value ); static bool ToInt64(const char* str, int64_t* value); - + static bool ToUnsigned64(const char* str, uint64_t* value); // Changes what is serialized for a boolean value. // Default to "true" and "false". Shouldn't be changed // unless you have a special testing or compatibility need. @@ -732,6 +742,12 @@ class TINYXML2_LIB XMLNode 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) @@ -946,7 +962,7 @@ class TINYXML2_LIB XMLNode void* GetUserData() const { return _userData; } protected: - XMLNode( XMLDocument* ); + explicit XMLNode( XMLDocument* ); virtual ~XMLNode(); virtual char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr); @@ -992,12 +1008,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; } @@ -1010,14 +1026,14 @@ class TINYXML2_LIB XMLText : public XMLNode 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: - XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {} + 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; @@ -1032,23 +1048,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: - XMLComment( XMLDocument* doc ); + 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 @@ -1071,23 +1087,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: - XMLDeclaration( XMLDocument* doc ); + 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 @@ -1106,23 +1122,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: - XMLUnknown( XMLDocument* doc ); + 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 @@ -1171,6 +1187,12 @@ class TINYXML2_LIB XMLAttribute return i; } + uint64_t Unsigned64Value() const { + uint64_t i = 0; + QueryUnsigned64Value(&i); + return i; + } + /// Query as an unsigned integer. See IntValue() unsigned UnsignedValue() const { unsigned i=0; @@ -1206,6 +1228,8 @@ class TINYXML2_LIB XMLAttribute /// See QueryIntValue XMLError QueryInt64Value(int64_t* value) const; /// See QueryIntValue + XMLError QueryUnsigned64Value(uint64_t* value) const; + /// See QueryIntValue XMLError QueryBoolValue( bool* value ) const; /// See QueryIntValue XMLError QueryDoubleValue( double* value ) const; @@ -1221,6 +1245,8 @@ class TINYXML2_LIB XMLAttribute /// Set the attribute to value. void SetAttribute(int64_t value); /// Set the attribute to value. + void SetAttribute(uint64_t value); + /// Set the attribute to value. void SetAttribute( bool value ); /// Set the attribute to value. void SetAttribute( double value ); @@ -1264,13 +1290,13 @@ class TINYXML2_LIB XMLElement : public XMLNode 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 @@ -1309,6 +1335,8 @@ class TINYXML2_LIB XMLElement : public XMLNode /// See IntAttribute() int64_t Int64Attribute(const char* name, int64_t defaultValue = 0) const; /// See IntAttribute() + uint64_t Unsigned64Attribute(const char* name, uint64_t defaultValue = 0) const; + /// See IntAttribute() bool BoolAttribute(const char* name, bool defaultValue = false) const; /// See IntAttribute() double DoubleAttribute(const char* name, double defaultValue = 0) const; @@ -1354,6 +1382,15 @@ class TINYXML2_LIB XMLElement : public XMLNode return a->QueryInt64Value(value); } + /// See QueryIntAttribute() + XMLError QueryUnsigned64Attribute(const char* name, uint64_t* value) const { + const XMLAttribute* a = FindAttribute(name); + if(!a) { + return XML_NO_ATTRIBUTE; + } + return a->QueryUnsigned64Value(value); + } + /// See QueryIntAttribute() XMLError QueryBoolAttribute( const char* name, bool* value ) const { const XMLAttribute* a = FindAttribute( name ); @@ -1379,6 +1416,17 @@ class TINYXML2_LIB XMLElement : public XMLNode return a->QueryFloatValue( value ); } + /// See QueryIntAttribute() + XMLError QueryStringAttribute(const char* name, const char** value) const { + const XMLAttribute* a = FindAttribute(name); + if (!a) { + return XML_NO_ATTRIBUTE; + } + *value = a->Value(); + return XML_SUCCESS; + } + + /** Given an attribute name, QueryAttribute() returns XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion @@ -1397,30 +1445,38 @@ class TINYXML2_LIB XMLElement : public XMLNode QueryAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10 @endverbatim */ - int QueryAttribute( const char* name, int* value ) const { + XMLError QueryAttribute( const char* name, int* value ) const { return QueryIntAttribute( name, value ); } - int QueryAttribute( const char* name, unsigned int* value ) const { + XMLError QueryAttribute( const char* name, unsigned int* value ) const { return QueryUnsignedAttribute( name, value ); } - int QueryAttribute(const char* name, int64_t* value) const { + XMLError QueryAttribute(const char* name, int64_t* value) const { return QueryInt64Attribute(name, value); } - int QueryAttribute( const char* name, bool* value ) const { + XMLError QueryAttribute(const char* name, uint64_t* value) const { + return QueryUnsigned64Attribute(name, value); + } + + XMLError QueryAttribute( const char* name, bool* value ) const { return QueryBoolAttribute( name, value ); } - int QueryAttribute( const char* name, double* value ) const { + XMLError QueryAttribute( const char* name, double* value ) const { return QueryDoubleAttribute( name, value ); } - int QueryAttribute( const char* name, float* value ) const { + XMLError QueryAttribute( const char* name, float* value ) const { return QueryFloatAttribute( name, value ); } + XMLError QueryAttribute(const char* name, const char** value) const { + return QueryStringAttribute(name, value); + } + /// Sets the named attribute to value. void SetAttribute( const char* name, const char* value ) { XMLAttribute* a = FindOrCreateAttribute( name ); @@ -1443,6 +1499,12 @@ class TINYXML2_LIB XMLElement : public XMLNode a->SetAttribute(value); } + /// Sets the named attribute to value. + void SetAttribute(const char* name, uint64_t value) { + XMLAttribute* a = FindOrCreateAttribute(name); + a->SetAttribute(value); + } + /// Sets the named attribute to value. void SetAttribute( const char* name, bool value ) { XMLAttribute* a = FindOrCreateAttribute( name ); @@ -1543,6 +1605,8 @@ class TINYXML2_LIB XMLElement : public XMLNode /// Convenience method for setting text inside an element. See SetText() for important limitations. void SetText(int64_t value); /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText(uint64_t value); + /// Convenience method for setting text inside an element. See SetText() for important limitations. void SetText( bool value ); /// Convenience method for setting text inside an element. See SetText() for important limitations. void SetText( double value ); @@ -1581,6 +1645,8 @@ class TINYXML2_LIB XMLElement : public XMLNode /// See QueryIntText() XMLError QueryInt64Text(int64_t* uval) const; /// See QueryIntText() + XMLError QueryUnsigned64Text(uint64_t* uval) const; + /// See QueryIntText() XMLError QueryBoolText( bool* bval ) const; /// See QueryIntText() XMLError QueryDoubleText( double* dval ) const; @@ -1594,12 +1660,29 @@ class TINYXML2_LIB XMLElement : public XMLNode /// See QueryIntText() int64_t Int64Text(int64_t defaultValue = 0) const; /// See QueryIntText() + uint64_t Unsigned64Text(uint64_t defaultValue = 0) const; + /// See QueryIntText() bool BoolText(bool defaultValue = false) const; /// See QueryIntText() double DoubleText(double defaultValue = 0) const; /// See QueryIntText() float FloatText(float defaultValue = 0) const; + /** + Convenience method to create a new XMLElement and add it as last (right) + child of this node. Returns the created and inserted element. + */ + XMLElement* InsertNewChildElement(const char* name); + /// See InsertNewChildElement() + XMLComment* InsertNewComment(const char* comment); + /// See InsertNewChildElement() + XMLText* InsertNewText(const char* text); + /// See InsertNewChildElement() + XMLDeclaration* InsertNewDeclaration(const char* text); + /// See InsertNewChildElement() + XMLUnknown* InsertNewUnknown(const char* text); + + // internal: enum ElementClosingType { OPEN, // @@ -1609,11 +1692,11 @@ class TINYXML2_LIB XMLElement : public XMLNode 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 ); @@ -1621,11 +1704,7 @@ class TINYXML2_LIB XMLElement : public XMLNode XMLElement( const XMLElement& ); // not supported void operator=( const XMLElement& ); // not supported - XMLAttribute* FindAttribute( const char* name ) { - return const_cast(const_cast(this)->FindAttribute( name )); - } XMLAttribute* FindOrCreateAttribute( const char* name ); - //void LinkAttribute( XMLAttribute* attrib ); char* ParseAttributes( char* p, int* curLineNumPtr ); static void DeleteAttribute( XMLAttribute* attribute ); XMLAttribute* CreateAttribute(); @@ -1641,7 +1720,8 @@ class TINYXML2_LIB XMLElement : public XMLNode enum Whitespace { PRESERVE_WHITESPACE, - COLLAPSE_WHITESPACE + COLLAPSE_WHITESPACE, + PEDANTIC_WHITESPACE }; @@ -1653,7 +1733,7 @@ enum Whitespace { class TINYXML2_LIB XMLDocument : public XMLNode { friend class XMLElement; - // Gives access to SetError, but over-access for everything else. + // Gives access to SetError and Push/PopDepth, but over-access for everything else. // Wishing C++ had "internal" scope. friend class XMLNode; friend class XMLText; @@ -1665,11 +1745,11 @@ class TINYXML2_LIB XMLDocument : public XMLNode 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; } @@ -1684,7 +1764,7 @@ class TINYXML2_LIB XMLDocument : public XMLNode specified, TinyXML-2 will assume 'xml' points to a null terminated string. */ - XMLError Parse( const char* xml, size_t nBytes=(size_t)(-1) ); + XMLError Parse( const char* xml, size_t nBytes=static_cast(-1) ); /** Load an XML file from disk. @@ -1766,7 +1846,7 @@ class TINYXML2_LIB XMLDocument : public XMLNode @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 @@ -1811,9 +1891,8 @@ class TINYXML2_LIB XMLDocument : public XMLNode */ 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 { @@ -1853,15 +1932,15 @@ class TINYXML2_LIB XMLDocument : public XMLNode void DeepCopy(XMLDocument* target) const; // internal - char* Identify( char* p, XMLNode** node ); + char* Identify( char* p, XMLNode** node, bool first ); // internal - void MarkInUse(XMLNode*); + 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; } @@ -1877,6 +1956,7 @@ class TINYXML2_LIB XMLDocument : public XMLNode int _errorLineNum; char* _charBuffer; int _parseCurLineNum; + int _parsingDepth; // Memory tracking does add some overhead. // However, the code assumes that you don't // have a bunch of unlinked nodes around. @@ -1896,11 +1976,29 @@ class TINYXML2_LIB XMLDocument : public XMLNode void SetError( XMLError error, int lineNum, const char* format, ... ); - template + // Something of an obvious security hole, once it was discovered. + // Either an ill-formed XML or an excessively deep one can overflow + // the stack. Track stack depth, and error out if needed. + class DepthTracker { + public: + explicit DepthTracker(XMLDocument * document) { + this->_document = document; + document->PushDepth(); + } + ~DepthTracker() { + _document->PopDepth(); + } + private: + XMLDocument * _document; + }; + void PushDepth(); + void PopDepth(); + + template NodeType* CreateUnlinkedNode( MemPoolT& pool ); }; -template +template inline NodeType* XMLDocument::CreateUnlinkedNode( MemPoolT& pool ) { TIXMLASSERT( sizeof( NodeType ) == PoolElementSize ); @@ -1972,10 +2070,10 @@ class TINYXML2_LIB XMLHandle { public: /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. - XMLHandle( XMLNode* node ) : _node( node ) { + explicit XMLHandle( XMLNode* node ) : _node( node ) { } /// Create a handle from a node. - XMLHandle( XMLNode& node ) : _node( &node ) { + explicit XMLHandle( XMLNode& node ) : _node( &node ) { } /// Copy constructor XMLHandle( const XMLHandle& ref ) : _node( ref._node ) { @@ -2052,9 +2150,9 @@ class TINYXML2_LIB XMLHandle class TINYXML2_LIB XMLConstHandle { public: - XMLConstHandle( const XMLNode* node ) : _node( node ) { + explicit XMLConstHandle( const XMLNode* node ) : _node( node ) { } - XMLConstHandle( const XMLNode& node ) : _node( &node ) { + explicit XMLConstHandle( const XMLNode& node ) : _node( &node ) { } XMLConstHandle( const XMLConstHandle& ref ) : _node( ref._node ) { } @@ -2156,13 +2254,18 @@ class TINYXML2_LIB XMLConstHandle class TINYXML2_LIB XMLPrinter : public XMLVisitor { public: + enum EscapeAposCharsInAttributes { + ESCAPE_APOS_CHARS_IN_ATTRIBUTES, + DONT_ESCAPE_APOS_CHARS_IN_ATTRIBUTES + }; + /** Construct the printer. If the FILE* is specified, this will print to the FILE. Else it will print to memory, and the result is available in CStr(). If 'compact' is set to true, then output is created with only required whitespace and newlines. */ - XMLPrinter( FILE* file=0, bool compact = false, int depth = 0 ); + XMLPrinter( FILE* file=0, bool compact = false, int depth = 0, EscapeAposCharsInAttributes aposInAttributes = ESCAPE_APOS_CHARS_IN_ATTRIBUTES ); virtual ~XMLPrinter() {} /** If streaming, write the BOM and declaration. */ @@ -2175,7 +2278,8 @@ class TINYXML2_LIB XMLPrinter : public XMLVisitor void PushAttribute( const char* name, const char* value ); void PushAttribute( const char* name, int value ); void PushAttribute( const char* name, unsigned value ); - void PushAttribute(const char* name, int64_t value); + void PushAttribute( const char* name, int64_t value ); + void PushAttribute( const char* name, uint64_t value ); void PushAttribute( const char* name, bool value ); void PushAttribute( const char* name, double value ); /// If streaming, close the Element. @@ -2187,8 +2291,10 @@ class TINYXML2_LIB XMLPrinter : public XMLVisitor void PushText( int value ); /// Add a text node from an unsigned. void PushText( unsigned value ); - /// Add a text node from an unsigned. - void PushText(int64_t value); + /// Add a text node from a signed 64bit integer. + void PushText( int64_t value ); + /// Add a text node from an unsigned 64bit integer. + void PushText( uint64_t value ); /// Add a text node from a bool. void PushText( bool value ); /// Add a text node from a float. @@ -2202,18 +2308,18 @@ class TINYXML2_LIB XMLPrinter : public XMLVisitor 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 @@ -2227,17 +2333,17 @@ class TINYXML2_LIB XMLPrinter : public XMLVisitor of the XML file in memory. (Note the size returned includes the terminating null.) */ - int CStrSize() const { + size_t CStrSize() const { return _buffer.Size(); } /** If in print to memory mode, reset the buffer to the beginning. */ - void ClearBuffer() { + void ClearBuffer( bool resetToFirstElement = true ) { _buffer.Clear(); _buffer.Push(0); - _firstElement = true; + _firstElement = resetToFirstElement; } protected: @@ -2247,16 +2353,22 @@ class TINYXML2_LIB XMLPrinter : public XMLVisitor the space and tabs used. A PrintSpace() override should call Print(). */ virtual void PrintSpace( int depth ); - void Print( const char* format, ... ); - void Write( const char* data, size_t size ); - inline void Write( const char* data ) { Write( data, strlen( data ) ); } - void Putc( char ch ); + virtual void Print( const char* format, ... ); + virtual void Write( const char* data, size_t size ); + virtual void Putc( char ch ); + + inline void Write(const char* data) { Write(data, strlen(data)); } void SealElementIfJustOpened(); bool _elementJustOpened; DynArray< const char*, 10 > _stack; private: + /** + Prepares to write a new node. This includes sealing an element that was + just opened, and writing any whitespace necessary if not in compact mode. + */ + void PrepareForNewNode( bool compactMode ); void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities. bool _firstElement; @@ -2289,4 +2401,4 @@ class TINYXML2_LIB XMLPrinter : public XMLVisitor # pragma warning(pop) #endif -#endif // TINYXML2_INCLUDED \ No newline at end of file +#endif // TINYXML2_INCLUDED diff --git a/src/aws-cpp-sdk-core/source/external/tinyxml2/tinyxml2.cpp b/src/aws-cpp-sdk-core/source/external/tinyxml2/tinyxml2.cpp index 151a3686765..9c01e730384 100644 --- a/src/aws-cpp-sdk-core/source/external/tinyxml2/tinyxml2.cpp +++ b/src/aws-cpp-sdk-core/source/external/tinyxml2/tinyxml2.cpp @@ -30,7 +30,7 @@ This file has been modified from its original version by Amazon: #include #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 @@ -38,6 +38,26 @@ This file has been modified from its original version by Amazon: # include #endif +// Handle fallthrough attribute for different compilers +#ifndef __has_attribute +# define __has_attribute(x) 0 +#endif +#ifndef __has_cpp_attribute +# define __has_cpp_attribute(x) 0 +#endif + +#if defined(_MSC_VER) +# define TIXML_FALLTHROUGH (void(0)) +#elif (__cplusplus >= 201703L && __has_cpp_attribute(fallthrough)) +# define TIXML_FALLTHROUGH [[fallthrough]] +#elif __has_cpp_attribute(clang::fallthrough) +# define TIXML_FALLTHROUGH [[clang::fallthrough]] +#elif __has_attribute(fallthrough) +# define TIXML_FALLTHROUGH __attribute__((fallthrough)) +#else +# define TIXML_FALLTHROUGH (void(0)) +#endif + #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE) // Microsoft Visual Studio, version 2005 and higher. Not WinCE. /*int _snprintf_s( @@ -51,14 +71,14 @@ This file has been modified from its original version by Amazon: { va_list va; va_start( va, format ); - int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va ); + const int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va ); va_end( va ); return result; } static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va ) { - int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va ); + const int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va ); return result; } @@ -106,10 +126,24 @@ This file has been modified from its original version by Amazon: #define TIXML_SSCANF sscanf #endif +#if defined(_WIN64) + #define TIXML_FSEEK _fseeki64 + #define TIXML_FTELL _ftelli64 +#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__CYGWIN__) + #define TIXML_FSEEK fseeko + #define TIXML_FTELL ftello +#elif defined(__ANDROID__) && __ANDROID_API__ > 24 + #define TIXML_FSEEK fseeko64 + #define TIXML_FTELL ftello64 +#else + #define TIXML_FSEEK fseek + #define TIXML_FTELL ftell +#endif + -static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF +static const char LINE_FEED = static_cast(0x0a); // all line endings are normalized to LF static const char LF = LINE_FEED; -static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out +static const char CARRIAGE_RETURN = static_cast(0x0d); // CR gets filtered out static const char CR = CARRIAGE_RETURN; static const char SINGLE_QUOTE = '\''; static const char DOUBLE_QUOTE = '\"'; @@ -209,7 +243,7 @@ char* StrPair::ParseText( char* p, const char* endTag, int strFlags, int* curLin TIXMLASSERT(curLineNumPtr); char* start = p; - char endChar = *endTag; + const char endChar = *endTag; size_t length = strlen( endTag ); // Inner loop of text parsing. @@ -232,13 +266,13 @@ char* StrPair::ParseName( char* p ) if ( !p || !(*p) ) { return 0; } - if ( !XMLUtil::IsNameStartChar( *p ) ) { + if ( !XMLUtil::IsNameStartChar( static_cast(*p) ) ) { return 0; } char* const start = p; ++p; - while ( *p && XMLUtil::IsNameChar( *p ) ) { + while ( *p && XMLUtil::IsNameChar( static_cast(*p) ) ) { ++p; } @@ -322,7 +356,7 @@ const char* StrPair::GetStr() const int buflen = 10; char buf[buflen] = { 0 }; int len = 0; - char* adjusted = const_cast( XMLUtil::GetCharacterRef( p, buf, &len ) ); + const char* adjusted = const_cast( XMLUtil::GetCharacterRef( p, buf, &len ) ); if ( adjusted == 0 ) { *q = *p; ++p; @@ -442,22 +476,22 @@ void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length switch (*length) { case 4: --output; - *output = (char)((input | BYTE_MARK) & BYTE_MASK); + *output = static_cast((input | BYTE_MARK) & BYTE_MASK); input >>= 6; - //fall through + TIXML_FALLTHROUGH; case 3: --output; - *output = (char)((input | BYTE_MARK) & BYTE_MASK); + *output = static_cast((input | BYTE_MARK) & BYTE_MASK); input >>= 6; - //fall through + TIXML_FALLTHROUGH; case 2: --output; - *output = (char)((input | BYTE_MARK) & BYTE_MASK); + *output = static_cast((input | BYTE_MARK) & BYTE_MASK); input >>= 6; - //fall through + TIXML_FALLTHROUGH; case 1: --output; - *output = (char)(input | FIRST_BYTE_MARK[*length]); + *output = static_cast(input | FIRST_BYTE_MARK[*length]); break; default: TIXMLASSERT( false ); @@ -465,102 +499,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 ); + TIXMLASSERT(digit < radix); - delta = q-p; - --q; + const unsigned int digitScaled = mult * digit; + ucs += digitScaled; + mult *= radix; - 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; + // 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 ); @@ -594,24 +620,38 @@ void XMLUtil::ToStr( double v, char* buffer, int bufferSize ) } -void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize) +void XMLUtil::ToStr( int64_t v, char* buffer, int bufferSize ) { // horrible syntax trick to make the compiler happy about %lld - TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v); + TIXML_SNPRINTF(buffer, bufferSize, "%lld", static_cast(v)); } +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", static_cast(v)); +} -bool XMLUtil::ToInt( const char* str, int* value ) +bool XMLUtil::ToInt(const char* str, int* value) { - if ( TIXML_SSCANF( str, "%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; } -bool XMLUtil::ToUnsigned( const char* str, unsigned *value ) +bool XMLUtil::ToUnsigned(const char* str, unsigned* value) { - if ( TIXML_SSCANF( str, "%u", value ) == 1 ) { + if (TIXML_SSCANF(str, IsPrefixHex(str) ? "%x" : "%u", value) == 1) { return true; } return false; @@ -624,13 +664,20 @@ bool XMLUtil::ToBool( const char* str, bool* value ) *value = (ival==0) ? false : true; return true; } - if ( StringEqual( str, "true" ) ) { - *value = true; - return true; + static const char* TRUE_VALS[] = { "true", "True", "TRUE", 0 }; + static const char* FALSE_VALS[] = { "false", "False", "FALSE", 0 }; + + for (int i = 0; TRUE_VALS[i]; ++i) { + if (StringEqual(str, TRUE_VALS[i])) { + *value = true; + return true; + } } - else if ( StringEqual( str, "false" ) ) { - *value = false; - return true; + for (int i = 0; FALSE_VALS[i]; ++i) { + if (StringEqual(str, FALSE_VALS[i])) { + *value = false; + return true; + } } return false; } @@ -656,16 +703,35 @@ 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, "%lld", &v) == 1) { - *value = (int64_t)v; + 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; +} + + +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 = 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 ); @@ -717,9 +783,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 ); @@ -772,6 +848,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. @@ -1016,44 +1120,60 @@ char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) // 'endTag' is the end tag for this node, it is returned by a call to a child. // 'parentEnd' is the end tag for the parent, which is filled in and returned. - while( p && *p ) { + XMLDocument::DepthTracker tracker(_document); + 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; - int initialLineNum = node->_parseLineNum; + 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); } break; } - XMLDeclaration* decl = node->ToDeclaration(); + const XMLDeclaration* const decl = node->ToDeclaration(); if ( decl ) { // Declarations are only allowed at document level - bool wellLocated = ( ToDocument() != 0 ); - if ( wellLocated ) { - // Multiple declarations are allowed but all declarations - // must occur before anything else - for ( const XMLNode* existingNode = _document->FirstChild(); existingNode; existingNode = existingNode->NextSibling() ) { - if ( !existingNode->ToDeclaration() ) { - wellLocated = false; - break; - } + // + // Multiple declarations are allowed but all declarations + // must occur before anything else. + // + // Optimized due to a security test case. If the first node is + // a declaration, and the last node is a declaration, then only + // declarations have so far been added. + bool wellLocated = false; + + if (ToDocument()) { + if (FirstChild()) { + wellLocated = + FirstChild() && + FirstChild()->ToDeclaration() && + LastChild() && + LastChild()->ToDeclaration(); + } + else { + wellLocated = true; } } if ( !wellLocated ) { _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, "XMLDeclaration value=%s", decl->Value()); - DeleteNode( node ); + _document->DeleteNode( node ); break; } } @@ -1088,7 +1208,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; } } @@ -1371,7 +1491,7 @@ char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr return 0; } - char endTag[2] = { *p, 0 }; + const char endTag[2] = { *p, 0 }; ++p; // move past opening quote p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr ); @@ -1412,6 +1532,15 @@ XMLError XMLAttribute::QueryInt64Value(int64_t* value) const } +XMLError XMLAttribute::QueryUnsigned64Value(uint64_t* value) const +{ + if(XMLUtil::ToUnsigned64(Value(), value)) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + XMLError XMLAttribute::QueryBoolValue( bool* value ) const { if ( XMLUtil::ToBool( Value(), value )) { @@ -1468,6 +1597,12 @@ void XMLAttribute::SetAttribute(int64_t v) _value.SetStr(buf); } +void XMLAttribute::SetAttribute(uint64_t v) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + _value.SetStr(buf); +} void XMLAttribute::SetAttribute( bool v ) @@ -1554,6 +1689,13 @@ int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const return i; } +uint64_t XMLElement::Unsigned64Attribute(const char* name, uint64_t defaultValue) const +{ + uint64_t i = defaultValue; + QueryUnsigned64Attribute(name, &i); + return i; +} + bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const { bool b = defaultValue; @@ -1577,8 +1719,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; } @@ -1618,6 +1770,12 @@ void XMLElement::SetText(int64_t v) SetText(buf); } +void XMLElement::SetText(uint64_t v) { + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + SetText(buf); +} + void XMLElement::SetText( bool v ) { @@ -1682,6 +1840,19 @@ XMLError XMLElement::QueryInt64Text(int64_t* ival) const } +XMLError XMLElement::QueryUnsigned64Text(uint64_t* uval) const +{ + if(FirstChild() && FirstChild()->ToText()) { + const char* t = FirstChild()->Value(); + if(XMLUtil::ToUnsigned64(t, uval)) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + XMLError XMLElement::QueryBoolText( bool* bval ) const { if ( FirstChild() && FirstChild()->ToText() ) { @@ -1741,6 +1912,13 @@ int64_t XMLElement::Int64Text(int64_t defaultValue) const return i; } +uint64_t XMLElement::Unsigned64Text(uint64_t defaultValue) const +{ + uint64_t i = defaultValue; + QueryUnsigned64Text(&i); + return i; +} + bool XMLElement::BoolText(bool defaultValue) const { bool b = defaultValue; @@ -1823,12 +2001,12 @@ char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr ) } // attribute. - if (XMLUtil::IsNameStartChar( *p ) ) { + if (XMLUtil::IsNameStartChar( static_cast(*p) ) ) { XMLAttribute* attrib = CreateAttribute(); TIXMLASSERT( attrib ); attrib->_parseLineNum = _document->_parseCurLineNum; - int attrLineNum = attrib->_parseLineNum; + const int attrLineNum = attrib->_parseLineNum; p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr ); if ( !p || Attribute( attrib->Name() ) ) { @@ -1889,6 +2067,39 @@ XMLAttribute* XMLElement::CreateAttribute() return attrib; } + +XMLElement* XMLElement::InsertNewChildElement(const char* name) +{ + XMLElement* node = _document->NewElement(name); + return InsertEndChild(node) ? node : 0; +} + +XMLComment* XMLElement::InsertNewComment(const char* comment) +{ + XMLComment* node = _document->NewComment(comment); + return InsertEndChild(node) ? node : 0; +} + +XMLText* XMLElement::InsertNewText(const char* text) +{ + XMLText* node = _document->NewText(text); + return InsertEndChild(node) ? node : 0; +} + +XMLDeclaration* XMLElement::InsertNewDeclaration(const char* text) +{ + XMLDeclaration* node = _document->NewDeclaration(text); + return InsertEndChild(node) ? node : 0; +} + +XMLUnknown* XMLElement::InsertNewUnknown(const char* text) +{ + XMLUnknown* node = _document->NewUnknown(text); + return InsertEndChild(node) ? node : 0; +} + + + // // // foobar @@ -1985,10 +2196,8 @@ const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = { "XML_ERROR_FILE_NOT_FOUND", "XML_ERROR_FILE_COULD_NOT_BE_OPENED", "XML_ERROR_FILE_READ_ERROR", - "UNUSED_XML_ERROR_ELEMENT_MISMATCH", "XML_ERROR_PARSING_ELEMENT", "XML_ERROR_PARSING_ATTRIBUTE", - "UNUSED_XML_ERROR_IDENTIFYING_TAG", "XML_ERROR_PARSING_TEXT", "XML_ERROR_PARSING_CDATA", "XML_ERROR_PARSING_COMMENT", @@ -1998,7 +2207,8 @@ const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = { "XML_ERROR_MISMATCHED_ELEMENT", "XML_ERROR_PARSING", "XML_CAN_NOT_CONVERT_TEXT", - "XML_NO_TEXT_NODE" + "XML_NO_TEXT_NODE", + "XML_ELEMENT_DEPTH_EXCEEDED" }; @@ -2012,6 +2222,7 @@ XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) : _errorLineNum( 0 ), _charBuffer( 0 ), _parseCurLineNum( 0 ), + _parsingDepth(0), _unlinked(), _elementPool(), _attributePool(), @@ -2029,12 +2240,12 @@ XMLDocument::~XMLDocument() } -void XMLDocument::MarkInUse(XMLNode* node) +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; @@ -2056,6 +2267,7 @@ void XMLDocument::Clear() Aws::DeleteArray(_charBuffer); _charBuffer = 0; + _parsingDepth = 0; #if 0 _textPool.Trace( "text" ); @@ -2133,7 +2345,7 @@ static FILE* callfopen( const char* filepath, const char* mode ) TIXMLASSERT( mode ); #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE) FILE* fp = 0; - errno_t err = fopen_s( &fp, filepath, mode ); + const errno_t err = fopen_s( &fp, filepath, mode ); if ( err ) { return 0; } @@ -2163,10 +2375,16 @@ void XMLDocument::DeleteNode( XMLNode* node ) { XMLError XMLDocument::LoadFile( const char* filename ) { + if ( !filename ) { + TIXMLASSERT( false ); + SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=" ); + return _errorID; + } + Clear(); FILE* fp = callfopen( filename, "rb" ); if ( !fp ) { - SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename ? filename : ""); + SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename ); return _errorID; } LoadFile( fp ); @@ -2174,49 +2392,34 @@ XMLError XMLDocument::LoadFile( const char* filename ) return _errorID; } -// This is likely overengineered template art to have a check that unsigned long value incremented -// by one still fits into size_t. If size_t type is larger than unsigned long type -// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit -// -Wtype-limits warning. This piece makes the compiler select code with a check when a check -// is useful and code with no check when a check is redundant depending on how size_t and unsigned long -// types sizes relate to each other. -template -= sizeof(size_t))> -struct LongFitsIntoSizeTMinusOne { - static bool Fits( unsigned long value ) - { - return value < (size_t)-1; - } -}; - -template <> -struct LongFitsIntoSizeTMinusOne { - static bool Fits( unsigned long ) - { - return true; - } -}; - XMLError XMLDocument::LoadFile( FILE* fp ) { Clear(); - fseek( fp, 0, SEEK_SET ); + TIXML_FSEEK( fp, 0, SEEK_SET ); if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) { SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); return _errorID; } - fseek( fp, 0, SEEK_END ); - const long filelength = ftell( fp ); - fseek( fp, 0, SEEK_SET ); - if ( filelength == -1L ) { - SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); - return _errorID; + TIXML_FSEEK( fp, 0, SEEK_END ); + + unsigned long long filelength; + { + const long long fileLengthSigned = TIXML_FTELL( fp ); + TIXML_FSEEK( fp, 0, SEEK_SET ); + if ( fileLengthSigned == -1L ) { + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); + return _errorID; + } + TIXMLASSERT( fileLengthSigned >= 0 ); + filelength = static_cast(fileLengthSigned); } - TIXMLASSERT( filelength >= 0 ); - if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) { + const size_t maxSizeT = static_cast(-1); + // We'll do the comparison as an unsigned long long, because that's guaranteed to be at + // least 8 bytes, even on a 32-bit platform. + if ( filelength >= static_cast(maxSizeT) ) { // Cannot handle files which won't fit in buffer together with null terminator SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); return _errorID; @@ -2227,10 +2430,10 @@ XMLError XMLDocument::LoadFile( FILE* fp ) return _errorID; } - const size_t size = filelength; + const size_t size = static_cast(filelength); TIXMLASSERT( _charBuffer == 0 ); _charBuffer = Aws::NewArray (size+1, ALLOCATION_TAG); - size_t read = fread( _charBuffer, 1, size, fp ); + const size_t read = fread( _charBuffer, 1, size, fp ); if ( read != size ) { SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); return _errorID; @@ -2245,9 +2448,15 @@ XMLError XMLDocument::LoadFile( FILE* fp ) XMLError XMLDocument::SaveFile( const char* filename, bool compact ) { + if ( !filename ) { + TIXMLASSERT( false ); + SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=" ); + return _errorID; + } + FILE* fp = callfopen( filename, "w" ); if ( !fp ) { - SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename ? filename : ""); + SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename ); return _errorID; } SaveFile(fp, compact); @@ -2267,21 +2476,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 == (size_t)(-1) ) { - len = strlen( p ); + if ( nBytes == static_cast(-1) ) { + nBytes = strlen( xml ); } TIXMLASSERT( _charBuffer == 0 ); - _charBuffer = Aws::NewArray(len+1, ALLOCATION_TAG); - memcpy( _charBuffer, p, len ); - _charBuffer[len] = 0; + _charBuffer = Aws::NewArray(nBytes+1, ALLOCATION_TAG); + memcpy( _charBuffer, xml, nBytes ); + _charBuffer[nBytes] = 0; Parse(); if ( Error() ) { @@ -2310,27 +2519,39 @@ 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(); - if (format) { - size_t BUFFER_SIZE = 1000; - char* buffer = Aws::NewArray(BUFFER_SIZE, ALLOCATION_TAG); - TIXML_SNPRINTF(buffer, BUFFER_SIZE, "Error=%s ErrorID=%d (0x%x) Line number=%d: ", ErrorIDToName(error), int(error), int(error), lineNum); - size_t len = strlen(buffer); + const size_t BUFFER_SIZE = 1000; + char* buffer = Aws::NewArray(BUFFER_SIZE, ALLOCATION_TAG); - va_list va; - va_start( va, format ); - TIXML_VSNPRINTF( buffer + len, BUFFER_SIZE - len, format, va ); - va_end( va ); + TIXMLASSERT(sizeof(error) <= sizeof(int)); + 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); + TIXML_SNPRINTF(buffer + len, BUFFER_SIZE - len, ": "); + len = strlen(buffer); - _errorStr.SetStr(buffer); + va_list va; + va_start(va, format); + TIXML_VSNPRINTF(buffer + len, BUFFER_SIZE - len, format, va); + va_end(va); + } + _errorStr.SetStr(buffer); Aws::DeleteArray(buffer); - } } @@ -2374,7 +2595,21 @@ void XMLDocument::Parse() ParseDeep(p, 0, &_parseCurLineNum ); } -XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) : +void XMLDocument::PushDepth() +{ + _parsingDepth++; + if (_parsingDepth == TINYXML2_MAX_ELEMENT_DEPTH) { + SetError(XML_ELEMENT_DEPTH_EXCEEDED, _parseCurLineNum, "Element nesting is too deep." ); + } +} + +void XMLDocument::PopDepth() +{ + TIXMLASSERT(_parsingDepth > 0); + --_parsingDepth; +} + +XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth, EscapeAposCharsInAttributes aposInAttributes ) : _elementJustOpened( false ), _stack(), _firstElement( true ), @@ -2391,13 +2626,15 @@ XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) : } for( int i=0; i(entityValue); + TIXMLASSERT( flagIndex < ENTITY_RANGE ); + _entityFlag[flagIndex] = true; + } } - _restrictedEntityFlag[(unsigned char)'&'] = true; - _restrictedEntityFlag[(unsigned char)'<'] = true; - _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice + _restrictedEntityFlag[static_cast('&')] = true; + _restrictedEntityFlag[static_cast('<')] = true; + _restrictedEntityFlag[static_cast('>')] = true; // not required, but consistency is nice _restrictedEntityFlag[(unsigned char)LF] = true; _restrictedEntityFlag[(unsigned char)CR] = true; _buffer.Push( 0 ); @@ -2432,7 +2669,7 @@ void XMLPrinter::Write( const char* data, size_t size ) fwrite ( data , sizeof(char), size, _fp); } else { - char* p = _buffer.PushArr( static_cast(size) ) - 1; // back up over the null terminator. + char* p = _buffer.PushArr( size ) - 1; // back up over the null terminator. memcpy( p, data, size ); p[size] = 0; } @@ -2474,10 +2711,10 @@ void XMLPrinter::PrintString( const char* p, bool restricted ) // Check for entities. If one is found, flush // the stream up until the entity, write the // entity, and keep looking. - if ( flag[(unsigned char)(*q)] ) { + if ( flag[static_cast(*q)] ) { while ( p < q ) { const size_t delta = q - p; - const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta; + const int toPrint = ( INT_MAX < delta ) ? INT_MAX : static_cast(delta); Write( p, toPrint ); p += toPrint; } @@ -2501,14 +2738,16 @@ void XMLPrinter::PrintString( const char* p, bool restricted ) ++q; TIXMLASSERT( p <= q ); } + // Flush the remaining string. This will be the entire + // string if an entity wasn't found. + if ( p < q ) { + const size_t delta = q - p; + const int toPrint = ( INT_MAX < delta ) ? INT_MAX : static_cast(delta); + Write( p, toPrint ); + } } - // Flush the remaining string. This will be the entire - // string if an entity wasn't found. - TIXMLASSERT( p <= q ); - if ( !_processEntities || ( p < q ) ) { - const size_t delta = q - p; - const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta; - Write( p, toPrint ); + else { + Write( p ); } } @@ -2524,24 +2763,33 @@ void XMLPrinter::PushHeader( bool writeBOM, bool writeDec ) } } - -void XMLPrinter::OpenElement( const char* name, bool compactMode ) +void XMLPrinter::PrepareForNewNode( bool compactMode ) { SealElementIfJustOpened(); - _stack.Push( name ); - if ( _textDepth < 0 && !_firstElement && !compactMode ) { - Putc( '\n' ); + if ( compactMode ) { + return; } - if ( !compactMode ) { + + if ( _firstElement ) { + PrintSpace (_depth); + } else if ( _textDepth < 0) { + Putc( '\n' ); PrintSpace( _depth ); } + _firstElement = false; +} + +void XMLPrinter::OpenElement( const char* name, bool compactMode ) +{ + PrepareForNewNode( compactMode ); + _stack.Push( name ); + Write ( "<" ); Write ( name ); _elementJustOpened = true; - _firstElement = false; ++_depth; } @@ -2581,6 +2829,14 @@ void XMLPrinter::PushAttribute(const char* name, int64_t v) } +void XMLPrinter::PushAttribute(const char* name, uint64_t v) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + PushAttribute(name, buf); +} + + void XMLPrinter::PushAttribute( const char* name, bool v ) { char buf[BUF_SIZE]; @@ -2650,6 +2906,7 @@ void XMLPrinter::PushText( const char* text, bool cdata ) } } + void XMLPrinter::PushText( int64_t value ) { char buf[BUF_SIZE]; @@ -2657,6 +2914,15 @@ void XMLPrinter::PushText( int64_t value ) PushText( buf, false ); } + +void XMLPrinter::PushText( uint64_t value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr(value, buf, BUF_SIZE); + PushText(buf, false); +} + + void XMLPrinter::PushText( int value ) { char buf[BUF_SIZE]; @@ -2699,12 +2965,7 @@ void XMLPrinter::PushText( double value ) void XMLPrinter::PushComment( const char* comment ) { - SealElementIfJustOpened(); - if ( _textDepth < 0 && !_firstElement && !_compactMode) { - Putc( '\n' ); - PrintSpace( _depth ); - } - _firstElement = false; + PrepareForNewNode( _compactMode ); Write( "