From 7085f00e40de52981d8c630c49ec8844244948a6 Mon Sep 17 00:00:00 2001 From: Lee Thomason Date: Thu, 1 Jun 2017 18:09:43 -0700 Subject: [PATCH 1/4] deep copy and clone --- tinyxml2.cpp | 23 +++++++++++++++ tinyxml2.h | 28 ++++++++++++++++-- xmltest.cpp | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+), 2 deletions(-) diff --git a/tinyxml2.cpp b/tinyxml2.cpp index e9b275b..819382b 100755 --- a/tinyxml2.cpp +++ b/tinyxml2.cpp @@ -771,6 +771,18 @@ void XMLNode::SetValue( const char* str, bool staticMem ) } } +XMLNode* XMLNode::DeepClone(XMLDocument* document) const +{ + XMLNode* clone = this->ShallowClone(document); + if (!clone) return 0; + + for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) { + XMLNode* childClone = child->DeepClone(document); + TIXMLASSERT(childClone); + clone->InsertEndChild(childClone); + } + return clone; +} void XMLNode::DeleteChildren() { @@ -2006,6 +2018,17 @@ void XMLDocument::Clear() } +void XMLDocument::DeepCopy(XMLDocument* target) +{ + TIXMLASSERT(target); + TIXMLASSERT(target != this); + + target->Clear(); + for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) { + target->InsertEndChild(node->DeepClone(target)); + } +} + XMLElement* XMLDocument::NewElement( const char* name ) { TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() ); diff --git a/tinyxml2.h b/tinyxml2.h index de589bd..607d0c7 100755 --- a/tinyxml2.h +++ b/tinyxml2.h @@ -53,7 +53,7 @@ distribution. 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 # define DEBUG # endif @@ -846,6 +846,20 @@ public: */ virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0; + /** + Make a copy of this node and all of the children + of this node. + + If the 'document' is null, then the nodes will + be allocated in the current document. If specified, + memory will e allocated is the specified document. + + NOTE: This is probably not the correct tool to + copy a document, since XMLDocuments can have multiple + top level XMLNodes. You probably want XMLDocument::DeepCopy() + */ + XMLNode* DeepClone( XMLDocument* document ) const; + /** Test if 2 nodes are the same, but don't test children. The 2 nodes do not need to be in the same Document. @@ -1787,7 +1801,17 @@ public: /// Clear the document, resetting it to the initial state. void Clear(); - // internal + /** + Copies this document to a target. + The target will be completely cleared before the copy. + If you want to copy a sub-tree, see DeepClone. + + NOTE: that the 'target' must be non-null and not + the source document. + */ + void DeepCopy(XMLDocument* target); + + // internal char* Identify( char* p, XMLNode** node ); virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const { diff --git a/xmltest.cpp b/xmltest.cpp index b6bb76f..499d626 100644 --- a/xmltest.cpp +++ b/xmltest.cpp @@ -1131,6 +1131,86 @@ int main( int argc, const char ** argv ) } { + // Deep Cloning of root element. + XMLDocument doc2; + XMLPrinter printer1; + { + // Make sure doc1 is deleted before we test doc2 + const char* xml = + "" + " " + " " + " Text" + ""; + XMLDocument doc; + doc.Parse(xml); + + doc.Print(&printer1); + XMLNode* root = doc.RootElement()->DeepClone(&doc2); + doc2.InsertFirstChild(root); + } + XMLPrinter printer2; + doc2.Print(&printer2); + + XMLTest("Deep clone of element.", printer1.CStr(), printer2.CStr(), true); + } + + { + // Deep Cloning of sub element. + XMLDocument doc2; + XMLPrinter printer1; + { + // Make sure doc1 is deleted before we test doc2 + const char* xml = + "" + "" + " " + " " + " Text" + ""; + XMLDocument doc; + doc.Parse(xml); + + const XMLElement* subElement = doc.FirstChildElement("root")->FirstChildElement("child2"); + subElement->Accept(&printer1); + + XMLNode* clonedSubElement = subElement->DeepClone(&doc2); + doc2.InsertFirstChild(clonedSubElement); + } + XMLPrinter printer2; + doc2.Print(&printer2); + + XMLTest("Deep clone of sub-element.", printer1.CStr(), printer2.CStr(), true); + } + + { + // Deep cloning of document. + XMLDocument doc2; + XMLPrinter printer1; + { + // Make sure doc1 is deleted before we test doc2 + const char* xml = + "" + "" + "" + " " + " " + " Text" + ""; + XMLDocument doc; + doc.Parse(xml); + doc.Print(&printer1); + + doc.DeepCopy(&doc2); + } + XMLPrinter printer2; + doc2.Print(&printer2); + + XMLTest("DeepCopy of document.", printer1.CStr(), printer2.CStr(), true); + } + + + { // This shouldn't crash. XMLDocument doc; if(XML_SUCCESS != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" )) From b29f556ab0999f6255e062ce323b1e2c02687c14 Mon Sep 17 00:00:00 2001 From: Lee Thomason Date: Thu, 1 Jun 2017 18:45:32 -0700 Subject: [PATCH 2/4] comment --- tinyxml2.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tinyxml2.h b/tinyxml2.h index 607d0c7..473a6f1 100755 --- a/tinyxml2.h +++ b/tinyxml2.h @@ -1802,9 +1802,9 @@ public: void Clear(); /** - Copies this document to a target. + 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 DeepClone. + If you want to copy a sub-tree, see XMLNode::DeepClone(). NOTE: that the 'target' must be non-null and not the source document. From ced18c05b94ad98f66373560370aeaea133673a5 Mon Sep 17 00:00:00 2001 From: Lee Thomason Date: Thu, 1 Jun 2017 18:50:12 -0700 Subject: [PATCH 3/4] missing var?? --- xmltest.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/xmltest.cpp b/xmltest.cpp index f1dc97d..ee8592a 100644 --- a/xmltest.cpp +++ b/xmltest.cpp @@ -14,6 +14,7 @@ #define WIN32_LEAN_AND_MEAN #include _CrtMemState startMemState; + _CrtMemState endMemState; #endif using namespace tinyxml2; From 1346a174ae2f1282bbb93adf480093579fafad6e Mon Sep 17 00:00:00 2001 From: Lee Thomason Date: Wed, 14 Jun 2017 15:14:19 -0700 Subject: [PATCH 4/4] tweak comments. fix copy to self case. --- tinyxml2.cpp | 4 +++- tinyxml2.h | 14 +++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/tinyxml2.cpp b/tinyxml2.cpp index 0168d9b..5c459a6 100755 --- a/tinyxml2.cpp +++ b/tinyxml2.cpp @@ -2052,7 +2052,9 @@ void XMLDocument::Clear() void XMLDocument::DeepCopy(XMLDocument* target) { TIXMLASSERT(target); - TIXMLASSERT(target != this); + if (target == this) { + return; // technically success - a no-op. + } target->Clear(); for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) { diff --git a/tinyxml2.h b/tinyxml2.h index f7fc21f..f307059 100755 --- a/tinyxml2.h +++ b/tinyxml2.h @@ -866,16 +866,17 @@ public: virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0; /** - Make a copy of this node and all of the children - of this node. + Make a copy of this node and all its children. If the 'document' is null, then the nodes will - be allocated in the current document. If specified, - memory will e allocated is the specified document. + be allocated in the current document. If document + 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 XMLDocument::DeepCopy() + top level XMLNodes. You probably want to use + XMLDocument::DeepCopy() */ XMLNode* DeepClone( XMLDocument* document ) const; @@ -1825,8 +1826,7 @@ public: 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 and not - the source document. + NOTE: that the 'target' must be non-null. */ void DeepCopy(XMLDocument* target);