Updated TinyXML

This commit is contained in:
Dmitry-Me 2017-08-11 17:56:41 +03:00
parent b28b7712c1
commit c9a63ca606
2 changed files with 207 additions and 77 deletions

View File

@ -368,6 +368,19 @@ const char* StrPair::GetStr()
// --------- XMLUtil ----------- // // --------- XMLUtil ----------- //
const char* XMLUtil::writeBoolTrue = "true";
const char* XMLUtil::writeBoolFalse = "false";
void XMLUtil::SetBoolSerialization(const char* writeTrue, const char* writeFalse)
{
static const char* defTrue = "true";
static const char* defFalse = "false";
writeBoolTrue = (writeTrue) ? writeTrue : defTrue;
writeBoolFalse = (writeFalse) ? writeFalse : defFalse;
}
const char* XMLUtil::ReadBOM( const char* p, bool* bom ) const char* XMLUtil::ReadBOM( const char* p, bool* bom )
{ {
TIXMLASSERT( p ); TIXMLASSERT( p );
@ -411,20 +424,24 @@ void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length
output += *length; output += *length;
// Scary scary fall throughs. // Scary scary fall throughs are annotated with carefully designed comments
// to suppress compiler warnings such as -Wimplicit-fallthrough in gcc
switch (*length) { switch (*length) {
case 4: case 4:
--output; --output;
*output = (char)((input | BYTE_MARK) & BYTE_MASK); *output = (char)((input | BYTE_MARK) & BYTE_MASK);
input >>= 6; input >>= 6;
//fall through
case 3: case 3:
--output; --output;
*output = (char)((input | BYTE_MARK) & BYTE_MASK); *output = (char)((input | BYTE_MARK) & BYTE_MASK);
input >>= 6; input >>= 6;
//fall through
case 2: case 2:
--output; --output;
*output = (char)((input | BYTE_MARK) & BYTE_MASK); *output = (char)((input | BYTE_MARK) & BYTE_MASK);
input >>= 6; input >>= 6;
//fall through
case 1: case 1:
--output; --output;
*output = (char)(input | FIRST_BYTE_MARK[*length]); *output = (char)(input | FIRST_BYTE_MARK[*length]);
@ -545,7 +562,7 @@ void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
void XMLUtil::ToStr( bool v, char* buffer, int bufferSize ) void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
{ {
TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? "true" : "false" ); TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? writeBoolTrue : writeBoolFalse);
} }
/* /*
@ -665,46 +682,34 @@ char* XMLDocument::Identify( char* p, XMLNode** node )
TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
XMLNode* returnNode = 0; XMLNode* returnNode = 0;
if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) { if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() ); returnNode = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
returnNode->_parseLineNum = _parseCurLineNum; returnNode->_parseLineNum = _parseCurLineNum;
returnNode->_memPool = &_commentPool;
p += xmlHeaderLen; p += xmlHeaderLen;
} }
else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) { else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() ); returnNode = CreateUnlinkedNode<XMLComment>( _commentPool );
returnNode = new (_commentPool.Alloc()) XMLComment( this );
returnNode->_parseLineNum = _parseCurLineNum; returnNode->_parseLineNum = _parseCurLineNum;
returnNode->_memPool = &_commentPool;
p += commentHeaderLen; p += commentHeaderLen;
} }
else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) { else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() ); XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
XMLText* text = new (_textPool.Alloc()) XMLText( this );
returnNode = text; returnNode = text;
returnNode->_parseLineNum = _parseCurLineNum; returnNode->_parseLineNum = _parseCurLineNum;
returnNode->_memPool = &_textPool;
p += cdataHeaderLen; p += cdataHeaderLen;
text->SetCData( true ); text->SetCData( true );
} }
else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) { else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() ); returnNode = CreateUnlinkedNode<XMLUnknown>( _commentPool );
returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
returnNode->_parseLineNum = _parseCurLineNum; returnNode->_parseLineNum = _parseCurLineNum;
returnNode->_memPool = &_commentPool;
p += dtdHeaderLen; p += dtdHeaderLen;
} }
else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) { else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() ); returnNode = CreateUnlinkedNode<XMLElement>( _elementPool );
returnNode = new (_elementPool.Alloc()) XMLElement( this );
returnNode->_parseLineNum = _parseCurLineNum; returnNode->_parseLineNum = _parseCurLineNum;
returnNode->_memPool = &_elementPool;
p += elementHeaderLen; p += elementHeaderLen;
} }
else { else {
TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() ); returnNode = CreateUnlinkedNode<XMLText>( _textPool );
returnNode = new (_textPool.Alloc()) XMLText( this );
returnNode->_memPool = &_textPool;
returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character
p = start; // Back it up, all the text counts. p = start; // Back it up, all the text counts.
_parseCurLineNum = startLine; _parseCurLineNum = startLine;
@ -771,6 +776,18 @@ void XMLNode::SetValue( const char* str, bool staticMem )
} }
} }
XMLNode* XMLNode::DeepClone(XMLDocument* target) const
{
XMLNode* clone = this->ShallowClone(target);
if (!clone) return 0;
for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) {
XMLNode* childClone = child->DeepClone(target);
TIXMLASSERT(childClone);
clone->InsertEndChild(childClone);
}
return clone;
}
void XMLNode::DeleteChildren() void XMLNode::DeleteChildren()
{ {
@ -800,6 +817,8 @@ void XMLNode::Unlink( XMLNode* child )
if ( child->_next ) { if ( child->_next ) {
child->_next->_prev = child->_prev; child->_next->_prev = child->_prev;
} }
child->_next = 0;
child->_prev = 0;
child->_parent = 0; child->_parent = 0;
} }
@ -810,6 +829,9 @@ void XMLNode::DeleteChild( XMLNode* node )
TIXMLASSERT( node->_document == _document ); TIXMLASSERT( node->_document == _document );
TIXMLASSERT( node->_parent == this ); TIXMLASSERT( node->_parent == this );
Unlink( node ); Unlink( node );
TIXMLASSERT(node->_prev == 0);
TIXMLASSERT(node->_next == 0);
TIXMLASSERT(node->_parent == 0);
DeleteNode( node ); DeleteNode( node );
} }
@ -954,7 +976,7 @@ const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
} }
char* XMLNode::ParseDeep( char* p, StrPair* parentEnd, int* curLineNumPtr ) char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
{ {
// This is a recursive method, but thinking about it "at the current level" // This is a recursive method, but thinking about it "at the current level"
// it is a pretty simple flat list: // it is a pretty simple flat list:
@ -1019,8 +1041,8 @@ char* XMLNode::ParseDeep( char* p, StrPair* parentEnd, int* curLineNumPtr )
if ( ele ) { if ( ele ) {
// We read the end tag. Return it to the parent. // We read the end tag. Return it to the parent.
if ( ele->ClosingType() == XMLElement::CLOSING ) { if ( ele->ClosingType() == XMLElement::CLOSING ) {
if ( parentEnd ) { if ( parentEndTag ) {
ele->_value.TransferTo( parentEnd ); ele->_value.TransferTo( parentEndTag );
} }
node->_memPool->SetTracked(); // created and then immediately deleted. node->_memPool->SetTracked(); // created and then immediately deleted.
DeleteNode( node ); DeleteNode( node );
@ -1054,11 +1076,16 @@ char* XMLNode::ParseDeep( char* p, StrPair* parentEnd, int* curLineNumPtr )
return 0; return 0;
} }
void XMLNode::DeleteNode( XMLNode* node ) /*static*/ void XMLNode::DeleteNode( XMLNode* node )
{ {
if ( node == 0 ) { if ( node == 0 ) {
return; return;
} }
TIXMLASSERT(node->_document);
if (!node->ToDocument()) {
node->_document->MarkInUse(node);
}
MemPool* pool = node->_memPool; MemPool* pool = node->_memPool;
node->~XMLNode(); node->~XMLNode();
pool->Free( node ); pool->Free( node );
@ -1069,10 +1096,13 @@ void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
TIXMLASSERT( insertThis ); TIXMLASSERT( insertThis );
TIXMLASSERT( insertThis->_document == _document ); TIXMLASSERT( insertThis->_document == _document );
if ( insertThis->_parent ) if (insertThis->_parent) {
insertThis->_parent->Unlink( insertThis ); insertThis->_parent->Unlink( insertThis );
else }
else {
insertThis->_document->MarkInUse(insertThis);
insertThis->_memPool->SetTracked(); insertThis->_memPool->SetTracked();
}
} }
const XMLElement* XMLNode::ToElementWithName( const char* name ) const const XMLElement* XMLNode::ToElementWithName( const char* name ) const
@ -1132,6 +1162,7 @@ XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
bool XMLText::ShallowEqual( const XMLNode* compare ) const bool XMLText::ShallowEqual( const XMLNode* compare ) const
{ {
TIXMLASSERT( compare );
const XMLText* text = compare->ToText(); const XMLText* text = compare->ToText();
return ( text && XMLUtil::StringEqual( text->Value(), Value() ) ); return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
} }
@ -1447,7 +1478,7 @@ void XMLAttribute::SetAttribute( float v )
// --------- XMLElement ---------- // // --------- XMLElement ---------- //
XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ), XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
_closingType( 0 ), _closingType( OPEN ),
_rootAttribute( 0 ) _rootAttribute( 0 )
{ {
} }
@ -1837,6 +1868,7 @@ XMLAttribute* XMLElement::CreateAttribute()
{ {
TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() ); TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute(); XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
TIXMLASSERT( attrib );
attrib->_memPool = &_document->_attributePool; attrib->_memPool = &_document->_attributePool;
attrib->_memPool->SetTracked(); attrib->_memPool->SetTracked();
return attrib; return attrib;
@ -1846,7 +1878,7 @@ XMLAttribute* XMLElement::CreateAttribute()
// <ele></ele> // <ele></ele>
// <ele>foo<b>bar</b></ele> // <ele>foo<b>bar</b></ele>
// //
char* XMLElement::ParseDeep( char* p, StrPair* strPair, int* curLineNumPtr ) char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
{ {
// Read the element name. // Read the element name.
p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
@ -1865,11 +1897,11 @@ char* XMLElement::ParseDeep( char* p, StrPair* strPair, int* curLineNumPtr )
} }
p = ParseAttributes( p, curLineNumPtr ); p = ParseAttributes( p, curLineNumPtr );
if ( !p || !*p || _closingType ) { if ( !p || !*p || _closingType != OPEN ) {
return p; return p;
} }
p = XMLNode::ParseDeep( p, strPair, curLineNumPtr ); p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr );
return p; return p;
} }
@ -1938,10 +1970,10 @@ const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
"XML_ERROR_FILE_NOT_FOUND", "XML_ERROR_FILE_NOT_FOUND",
"XML_ERROR_FILE_COULD_NOT_BE_OPENED", "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
"XML_ERROR_FILE_READ_ERROR", "XML_ERROR_FILE_READ_ERROR",
"XML_ERROR_ELEMENT_MISMATCH", "UNUSED_XML_ERROR_ELEMENT_MISMATCH",
"XML_ERROR_PARSING_ELEMENT", "XML_ERROR_PARSING_ELEMENT",
"XML_ERROR_PARSING_ATTRIBUTE", "XML_ERROR_PARSING_ATTRIBUTE",
"XML_ERROR_IDENTIFYING_TAG", "UNUSED_XML_ERROR_IDENTIFYING_TAG",
"XML_ERROR_PARSING_TEXT", "XML_ERROR_PARSING_TEXT",
"XML_ERROR_PARSING_CDATA", "XML_ERROR_PARSING_CDATA",
"XML_ERROR_PARSING_COMMENT", "XML_ERROR_PARSING_COMMENT",
@ -1955,13 +1987,15 @@ const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
}; };
XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) : XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :
XMLNode( 0 ), XMLNode( 0 ),
_writeBOM( false ), _writeBOM( false ),
_processEntities( processEntities ), _processEntities( processEntities ),
_errorID(XML_SUCCESS), _errorID(XML_SUCCESS),
_whitespace( whitespace ), _whitespaceMode( whitespaceMode ),
_charBuffer( 0 ) _errorLineNum( 0 ),
_charBuffer( 0 ),
_parseCurLineNum( 0 )
{ {
// avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+) // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
_document = this; _document = this;
@ -1974,9 +2008,25 @@ XMLDocument::~XMLDocument()
} }
void XMLDocument::MarkInUse(XMLNode* node)
{
TIXMLASSERT(node);
TIXMLASSERT(node->_parent == 0);
for (int i = 0; i < _unlinked.Size(); ++i) {
if (node == _unlinked[i]) {
_unlinked.SwapRemove(i);
break;
}
}
}
void XMLDocument::Clear() void XMLDocument::Clear()
{ {
DeleteChildren(); DeleteChildren();
while( _unlinked.Size()) {
DeleteNode(_unlinked[0]); // Will remove from _unlinked as part of delete.
}
#ifdef DEBUG #ifdef DEBUG
const bool hadError = Error(); const bool hadError = Error();
@ -2004,11 +2054,22 @@ void XMLDocument::Clear()
} }
void XMLDocument::DeepCopy(XMLDocument* target)
{
TIXMLASSERT(target);
if (target == this) {
return; // technically success - a no-op.
}
target->Clear();
for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {
target->InsertEndChild(node->DeepClone(target));
}
}
XMLElement* XMLDocument::NewElement( const char* name ) XMLElement* XMLDocument::NewElement( const char* name )
{ {
TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() ); XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );
XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
ele->_memPool = &_elementPool;
ele->SetName( name ); ele->SetName( name );
return ele; return ele;
} }
@ -2016,9 +2077,7 @@ XMLElement* XMLDocument::NewElement( const char* name )
XMLComment* XMLDocument::NewComment( const char* str ) XMLComment* XMLDocument::NewComment( const char* str )
{ {
TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() ); XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
comment->_memPool = &_commentPool;
comment->SetValue( str ); comment->SetValue( str );
return comment; return comment;
} }
@ -2026,9 +2085,7 @@ XMLComment* XMLDocument::NewComment( const char* str )
XMLText* XMLDocument::NewText( const char* str ) XMLText* XMLDocument::NewText( const char* str )
{ {
TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() ); XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
XMLText* text = new (_textPool.Alloc()) XMLText( this );
text->_memPool = &_textPool;
text->SetValue( str ); text->SetValue( str );
return text; return text;
} }
@ -2036,9 +2093,7 @@ XMLText* XMLDocument::NewText( const char* str )
XMLDeclaration* XMLDocument::NewDeclaration( const char* str ) XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
{ {
TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() ); XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
dec->_memPool = &_commentPool;
dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" ); dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
return dec; return dec;
} }
@ -2046,9 +2101,7 @@ XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
XMLUnknown* XMLDocument::NewUnknown( const char* str ) XMLUnknown* XMLDocument::NewUnknown( const char* str )
{ {
TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() ); XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
unk->_memPool = &_commentPool;
unk->SetValue( str ); unk->SetValue( str );
return unk; return unk;
} }
@ -2259,6 +2312,16 @@ void XMLDocument::SetError( XMLError error, const char* str1, const char* str2,
return errorName; return errorName;
} }
const char* XMLDocument::GetErrorStr1() const
{
return _errorStr1.GetStr();
}
const char* XMLDocument::GetErrorStr2() const
{
return _errorStr2.GetStr();
}
const char* XMLDocument::ErrorName() const const char* XMLDocument::ErrorName() const
{ {
return ErrorIDToName(_errorID); return ErrorIDToName(_errorID);

View File

@ -53,7 +53,7 @@ distribution.
AStyle.exe --style=1tbs --indent-switches --break-closing-brackets --indent-preprocessor tinyxml2.cpp tinyxml2.h AStyle.exe --style=1tbs --indent-switches --break-closing-brackets --indent-preprocessor tinyxml2.cpp tinyxml2.h
*/ */
#if defined( _DEBUG ) || defined( DEBUG ) || defined (__DEBUG__) #if defined( _DEBUG ) || defined (__DEBUG__)
# ifndef DEBUG # ifndef DEBUG
# define DEBUG # define DEBUG
# endif # endif
@ -98,7 +98,7 @@ distribution.
/* Versioning, past 1.0.14: /* Versioning, past 1.0.14:
http://semver.org/ http://semver.org/
*/ */
static const int TIXML2_MAJOR_VERSION = 4; static const int TIXML2_MAJOR_VERSION = 5;
static const int TIXML2_MINOR_VERSION = 0; static const int TIXML2_MINOR_VERSION = 0;
static const int TIXML2_PATCH_VERSION = 1; static const int TIXML2_PATCH_VERSION = 1;
@ -264,6 +264,13 @@ public:
return _allocated; return _allocated;
} }
void SwapRemove(int i) {
TIXMLASSERT(i >= 0 && i < _size);
TIXMLASSERT(_size > 0);
_mem[i] = _mem[_size - 1];
--_size;
}
const T* Mem() const { const T* Mem() const {
TIXMLASSERT( _mem ); TIXMLASSERT( _mem );
return _mem; return _mem;
@ -284,6 +291,7 @@ private:
TIXMLASSERT( cap <= INT_MAX / 2 ); TIXMLASSERT( cap <= INT_MAX / 2 );
int newAllocated = cap * 2; int newAllocated = cap * 2;
T* newMem = new T[newAllocated]; 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 ) { if ( _mem != _pool ) {
delete [] _mem; delete [] _mem;
@ -333,8 +341,8 @@ public:
void Clear() { void Clear() {
// Delete the blocks. // Delete the blocks.
while( !_blockPtrs.Empty()) { while( !_blockPtrs.Empty()) {
Block* b = _blockPtrs.Pop(); Block* lastBlock = _blockPtrs.Pop();
delete b; delete lastBlock;
} }
_root = 0; _root = 0;
_currentAllocs = 0; _currentAllocs = 0;
@ -505,10 +513,10 @@ enum XMLError {
XML_ERROR_FILE_NOT_FOUND, XML_ERROR_FILE_NOT_FOUND,
XML_ERROR_FILE_COULD_NOT_BE_OPENED, XML_ERROR_FILE_COULD_NOT_BE_OPENED,
XML_ERROR_FILE_READ_ERROR, XML_ERROR_FILE_READ_ERROR,
XML_ERROR_ELEMENT_MISMATCH, UNUSED_XML_ERROR_ELEMENT_MISMATCH, // remove at next major version
XML_ERROR_PARSING_ELEMENT, XML_ERROR_PARSING_ELEMENT,
XML_ERROR_PARSING_ATTRIBUTE, XML_ERROR_PARSING_ATTRIBUTE,
XML_ERROR_IDENTIFYING_TAG, UNUSED_XML_ERROR_IDENTIFYING_TAG, // remove at next major version
XML_ERROR_PARSING_TEXT, XML_ERROR_PARSING_TEXT,
XML_ERROR_PARSING_CDATA, XML_ERROR_PARSING_CDATA,
XML_ERROR_PARSING_COMMENT, XML_ERROR_PARSING_COMMENT,
@ -527,7 +535,7 @@ enum XMLError {
/* /*
Utility functionality. Utility functionality.
*/ */
class XMLUtil class TINYXML2_LIB XMLUtil
{ {
public: public:
static const char* SkipWhiteSpace( const char* p, int* curLineNumPtr ) { static const char* SkipWhiteSpace( const char* p, int* curLineNumPtr ) {
@ -605,6 +613,17 @@ public:
static bool ToFloat( const char* str, float* value ); static bool ToFloat( const char* str, float* value );
static bool ToDouble( const char* str, double* value ); static bool ToDouble( const char* str, double* value );
static bool ToInt64(const char* str, int64_t* value); static bool ToInt64(const char* str, int64_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.
// Be careful: static, global, & not thread safe.
// Be sure to set static const memory as parameters.
static void SetBoolSerialization(const char* writeTrue, const char* writeFalse);
private:
static const char* writeBoolTrue;
static const char* writeBoolFalse;
}; };
@ -846,6 +865,21 @@ public:
*/ */
virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0; virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0;
/**
Make a copy of this node and all its children.
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
specified XMLDocument.
NOTE: This is probably not the correct tool to
copy a document, since XMLDocuments can have multiple
top level XMLNodes. You probably want to use
XMLDocument::DeepCopy()
*/
XMLNode* DeepClone( XMLDocument* target ) const;
/** /**
Test if 2 nodes are the same, but don't test children. Test if 2 nodes are the same, but don't test children.
The 2 nodes do not need to be in the same Document. The 2 nodes do not need to be in the same Document.
@ -896,7 +930,7 @@ protected:
XMLNode( XMLDocument* ); XMLNode( XMLDocument* );
virtual ~XMLNode(); virtual ~XMLNode();
virtual char* ParseDeep( char*, StrPair*, int* ); virtual char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr);
XMLDocument* _document; XMLDocument* _document;
XMLNode* _parent; XMLNode* _parent;
@ -964,7 +998,7 @@ protected:
XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {} XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {}
virtual ~XMLText() {} virtual ~XMLText() {}
char* ParseDeep( char*, StrPair* endTag, int* curLineNumPtr ); char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr );
private: private:
bool _isCData; bool _isCData;
@ -995,7 +1029,7 @@ protected:
XMLComment( XMLDocument* doc ); XMLComment( XMLDocument* doc );
virtual ~XMLComment(); virtual ~XMLComment();
char* ParseDeep( char*, StrPair* endTag, int* curLineNumPtr); char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr);
private: private:
XMLComment( const XMLComment& ); // not supported XMLComment( const XMLComment& ); // not supported
@ -1034,7 +1068,7 @@ protected:
XMLDeclaration( XMLDocument* doc ); XMLDeclaration( XMLDocument* doc );
virtual ~XMLDeclaration(); virtual ~XMLDeclaration();
char* ParseDeep( char*, StrPair* endTag, int* curLineNumPtr ); char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr );
private: private:
XMLDeclaration( const XMLDeclaration& ); // not supported XMLDeclaration( const XMLDeclaration& ); // not supported
@ -1069,7 +1103,7 @@ protected:
XMLUnknown( XMLDocument* doc ); XMLUnknown( XMLDocument* doc );
virtual ~XMLUnknown(); virtual ~XMLUnknown();
char* ParseDeep( char*, StrPair* endTag, int* curLineNumPtr ); char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr );
private: private:
XMLUnknown( const XMLUnknown& ); // not supported XMLUnknown( const XMLUnknown& ); // not supported
@ -1177,7 +1211,7 @@ public:
private: private:
enum { BUF_SIZE = 200 }; enum { BUF_SIZE = 200 };
XMLAttribute() : _next( 0 ), _memPool( 0 ) {} XMLAttribute() : _parseLineNum( 0 ), _next( 0 ), _memPool( 0 ) {}
virtual ~XMLAttribute() {} virtual ~XMLAttribute() {}
XMLAttribute( const XMLAttribute& ); // not supported XMLAttribute( const XMLAttribute& ); // not supported
@ -1548,19 +1582,19 @@ public:
float FloatText(float defaultValue = 0) const; float FloatText(float defaultValue = 0) const;
// internal: // internal:
enum { enum ElementClosingType {
OPEN, // <foo> OPEN, // <foo>
CLOSED, // <foo/> CLOSED, // <foo/>
CLOSING // </foo> CLOSING // </foo>
}; };
int ClosingType() const { ElementClosingType ClosingType() const {
return _closingType; return _closingType;
} }
virtual XMLNode* ShallowClone( XMLDocument* document ) const; virtual XMLNode* ShallowClone( XMLDocument* document ) const;
virtual bool ShallowEqual( const XMLNode* compare ) const; virtual bool ShallowEqual( const XMLNode* compare ) const;
protected: protected:
char* ParseDeep( char* p, StrPair* endTag, int* curLineNumPtr ); char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr );
private: private:
XMLElement( XMLDocument* doc ); XMLElement( XMLDocument* doc );
@ -1578,7 +1612,7 @@ private:
XMLAttribute* CreateAttribute(); XMLAttribute* CreateAttribute();
enum { BUF_SIZE = 200 }; enum { BUF_SIZE = 200 };
int _closingType; ElementClosingType _closingType;
// The attribute list is ordered; there is no 'lastAttribute' // The attribute list is ordered; there is no 'lastAttribute'
// because the list needs to be scanned for dupes before adding // because the list needs to be scanned for dupes before adding
// a new attribute. // a new attribute.
@ -1602,7 +1636,7 @@ class TINYXML2_LIB XMLDocument : public XMLNode
friend class XMLElement; friend class XMLElement;
public: public:
/// constructor /// constructor
XMLDocument( bool processEntities = true, Whitespace = PRESERVE_WHITESPACE ); XMLDocument( bool processEntities = true, Whitespace whitespaceMode = PRESERVE_WHITESPACE );
~XMLDocument(); ~XMLDocument();
virtual XMLDocument* ToDocument() { virtual XMLDocument* ToDocument() {
@ -1666,7 +1700,7 @@ public:
return _processEntities; return _processEntities;
} }
Whitespace WhitespaceMode() const { Whitespace WhitespaceMode() const {
return _whitespace; return _whitespaceMode;
} }
/** /**
@ -1769,13 +1803,11 @@ public:
static const char* ErrorIDToName(XMLError errorID); static const char* ErrorIDToName(XMLError errorID);
/// Return a possibly helpful diagnostic location or string. /// Return a possibly helpful diagnostic location or string.
const char* GetErrorStr1() const { const char* GetErrorStr1() const;
return _errorStr1.GetStr();
}
/// Return a possibly helpful secondary diagnostic location or string. /// Return a possibly helpful secondary diagnostic location or string.
const char* GetErrorStr2() const { const char* GetErrorStr2() const;
return _errorStr2.GetStr();
}
/// Return the line where the error occured, or zero if unknown. /// Return the line where the error occured, or zero if unknown.
int GetErrorLineNum() const int GetErrorLineNum() const
{ {
@ -1787,9 +1819,21 @@ public:
/// Clear the document, resetting it to the initial state. /// Clear the document, resetting it to the initial state.
void Clear(); void Clear();
/**
Copies this document to a target document.
The target will be completely cleared before the copy.
If you want to copy a sub-tree, see XMLNode::DeepClone().
NOTE: that the 'target' must be non-null.
*/
void DeepCopy(XMLDocument* target);
// internal // internal
char* Identify( char* p, XMLNode** node ); char* Identify( char* p, XMLNode** node );
// internal
void MarkInUse(XMLNode*);
virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const { virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const {
return 0; return 0;
} }
@ -1804,12 +1848,19 @@ private:
bool _writeBOM; bool _writeBOM;
bool _processEntities; bool _processEntities;
XMLError _errorID; XMLError _errorID;
Whitespace _whitespace; Whitespace _whitespaceMode;
mutable StrPair _errorStr1; mutable StrPair _errorStr1;
mutable StrPair _errorStr2; mutable StrPair _errorStr2;
int _errorLineNum; int _errorLineNum;
char* _charBuffer; char* _charBuffer;
int _parseCurLineNum; int _parseCurLineNum;
// Memory tracking does add some overhead.
// However, the code assumes that you don't
// have a bunch of unlinked nodes around.
// Therefore it takes less memory to track
// in the document vs. a linked list in the XMLNode,
// and the performance is the same.
DynArray<XMLNode*, 10> _unlinked;
MemPoolT< sizeof(XMLElement) > _elementPool; MemPoolT< sizeof(XMLElement) > _elementPool;
MemPoolT< sizeof(XMLAttribute) > _attributePool; MemPoolT< sizeof(XMLAttribute) > _attributePool;
@ -1819,8 +1870,23 @@ private:
static const char* _errorNames[XML_ERROR_COUNT]; static const char* _errorNames[XML_ERROR_COUNT];
void Parse(); void Parse();
template<class NodeType, int PoolElementSize>
NodeType* CreateUnlinkedNode( MemPoolT<PoolElementSize>& pool );
}; };
template<class NodeType, int PoolElementSize>
inline NodeType* XMLDocument::CreateUnlinkedNode( MemPoolT<PoolElementSize>& pool )
{
TIXMLASSERT( sizeof( NodeType ) == PoolElementSize );
TIXMLASSERT( sizeof( NodeType ) == pool.ItemSize() );
NodeType* returnNode = new (pool.Alloc()) NodeType( this );
TIXMLASSERT( returnNode );
returnNode->_memPool = &pool;
_unlinked.Push(returnNode);
return returnNode;
}
/** /**
A XMLHandle is a class that wraps a node pointer with null checks; this is A XMLHandle is a class that wraps a node pointer with null checks; this is
@ -2152,6 +2218,7 @@ public:
void ClearBuffer() { void ClearBuffer() {
_buffer.Clear(); _buffer.Clear();
_buffer.Push(0); _buffer.Push(0);
_firstElement = true;
} }
protected: protected: