Browse Source

* Added XMLSerializer library
* Updated file format documentation
* Added name field to ReAntTweakBar
* Updated external AntTweakBar to version 1.16
* Updated external tinyxml2 to latest version


Former-commit-id: 382af7d7dc368a09f1fc18ad5c36461216805683

schuellc 12 years ago
parent
commit
85a594f582

+ 1 - 0
file-formats/index.html

@@ -38,6 +38,7 @@
     <li><a href=./rbr.html>.rbr</a> ASCII files for saving state of ReAntTweakBar</li>
     <li><a href=http://en.wikipedia.org/wiki/Truevision_TGA>.tga</a> Truevision TGA or TARGA image file format. IGLLIB supports only very basic reading and writing RGB/RGBA files without colormaps and (unverified) run-length compression.</li>
     <li><a href="./tgf.html">.tgf</a> ASCII files for representing control handle graphs</li>
+	<li><a href="./xml.html">.xml</a> XMLSerializer's file format containing the serialization of object data structures.</li>
   </ul>
   <h3>Triangle mesh file format performance</h3>
   <p>

+ 86 - 0
file-formats/xml.html

@@ -0,0 +1,86 @@
+<!DOCTYPE HTML>
+<html>
+  <head>
+    <link rel='stylesheet' type='text/css' href='../style.css' >
+    <title>libigl file formats | .xml</title>
+  </head>
+  <body class=article_body>
+  <div  class=article>
+    <a href=..><img src=../libigl-logo.jpg alt="igl logo" class=center></a>
+    <h1>.xml - serialization format</h1>
+    <hr>
+    <p>
+A .xml file contains the serialization of an object data structure generated with the XMLSerializer:
+    </p>
+    <p>
+The top level elements represent the groups in which the object are organised. The object names are unique within these groups.
+    </p>
+    <pre><code>&lt;group1&gt;
+  &lt;object1 val="value of object 1"/&gt;
+  &lt;object2 val="value of object 2"/&gt;
+&lt;/group1&gt;
+
+&lt;group2&gt;
+  &lt;object1 val="value of object 1"/&gt;
+&lt;/group2&gt;</code></pre>
+    <p>
+An object can be of following type:<br/>
+<br/>
+Basic types: <b>char, char*, std::string, bool, usigned int, int, float, double</b><br/>
+STL containers: <b>std::array, std::vector, std::pair</b><br/>
+Eigen types: <b>Eigen::Matrix, Eigen::SparseMatrix</b><br/>
+User defined types: <b>XMLSerializable*.</b><br/>
+<br/>
+There can also be a hierachical structure like vector&lt;int&gt;, this will result in the following serialization:
+    </p>
+    <pre><code>&lt;group&gt;
+  &lt;vector size="3"&gt;
+    &lt;value0 val="1"/&gt;
+    &lt;value1 val="2"/&gt;
+    &lt;value2 val="3"/&gt;
+  &lt;/vector&gt;
+&lt;/group&gt;</code></pre>
+
+    <p>An example of a serialization of an instance of the class Test</p>
+    
+	<pre><code>class Test{
+  int var1;
+  vector&ltfloat&gt; vec1;  
+};</code></pre>
+
+<p> is shown here:</p>
+
+<pre><code>&lt;group&gt;
+  &lt;Test&gt;
+    &lt;var1 val="0"&gt;
+    &lt;vec1 size="2"&gt;
+      &lt;value0 val="1"/&gt;
+      &lt;value1 val="2"/&gt;
+    &lt;/vector&gt;
+  &lt;/Test&gt;
+&lt;/group&gt;</code></pre>
+
+<p>In the following we show the serialization of Eigen matrices.</p>
+
+<p>Eigen::Matrix&lt;int,4,3&gt;:</p>
+<pre><code>&lt;group&gt;
+  &lt;matrix row="4" col="3" matrix="
+1,2,3,
+4,5,6,
+7,8,9,
+10,11,12/&gt;
+&lt;/group&gt;</code></pre>
+
+<p>Eigen::SparseMatrix&lt;int&gt; (3x3 identity saved as triplets of the non-zero entries):</p>
+<pre><code>&lt;group&gt;
+  &lt;matrix row="3" col="3" matrix="
+0,0,1,
+1,1,1,
+2,2,1/&gt;
+&lt;/group&gt;</code></pre>
+
+    <p>See also: <a href=.>file formats</a></p>
+  </div>
+  </body>
+</html>
+

+ 3 - 2
include/igl/ReAntTweakBar.cpp

@@ -100,11 +100,12 @@ igl::ReTwBar & igl::ReTwBar::operator=(const igl::ReTwBar & that)
 
 
 // BAR WRAPPERS
-void igl::ReTwBar::TwNewBar(const char *barName)
+void igl::ReTwBar::TwNewBar(const char *name)
 {
   // double colon without anything in front of it means look for this in the
   // global namespace... I hope...
-  this->bar = ::TwNewBar(barName);
+  this->name = name;
+  this->bar = ::TwNewBar(name);
 }
 
 int igl::ReTwBar::TwAddVarRW(

+ 1 - 0
include/igl/ReAntTweakBar.h

@@ -148,6 +148,7 @@ namespace igl
     // anytime AntTweakBar functions can be called directly on the bar
     public:
       TwBar * bar;
+	  std::string name;
     protected:
       std::vector<ReTwRWItem> rw_items;
       std::vector<ReTwCBItem> cb_items;

+ 6 - 0
include/igl/xml/README

@@ -0,0 +1,6 @@
+IGL xml serializer
+
+Dependencies:
+  tinyxml2  
+  
+Travel to $IGL/external/tinyxml2

+ 205 - 0
include/igl/xml/ReAntTweakBarXMLSerialization.cpp

@@ -0,0 +1,205 @@
+#include "ReAntTweakBarXMLSerialization.h"
+
+#include "igl/ReAntTweakBar.h"
+
+IGL_INLINE bool igl::save_ReAntTweakBar(igl::ReTwBar* bar, const char* file_name)
+{
+  std::string name = bar->name + "_AntTweakBar";
+	
+  const std::vector<igl::ReTwRWItem>& rw_items = bar->get_rw_items();
+	for(std::vector<ReTwRWItem>::const_iterator it = rw_items.begin(); it != rw_items.end(); it++)
+	{	
+		std::string val = bar->get_value_as_string(it->var,it->type);
+		igl::XMLSerializer::SaveObject(val,it->name,name,file_name,false);
+	}
+
+	char var[MAX_CB_VAR_SIZE];
+	// Print all CB variables
+  const std::vector<igl::ReTwCBItem>& cb_items = bar->get_cb_items();
+  for(std::vector<ReTwCBItem>::const_iterator it = cb_items.begin(); it != cb_items.end(); it++)
+	{
+		TwType type = it->type;
+		//TwSetVarCallback setCallback = it->setCallback;
+		TwGetVarCallback getCallback = it->getCallback;
+		void * clientData = it->clientData;
+		// I'm not sure how to do what I want to do. getCallback needs to be sure
+		// that it can write to var. So var needs to point to a valid and big
+		// enough chunk of memory
+		getCallback(var,clientData);
+		
+		std::string val = bar->get_value_as_string(var,type);
+		igl::XMLSerializer::SaveObject(val,it->name,name,file_name,false);
+	}
+
+	return true;
+}
+
+IGL_INLINE bool igl::save_ReAntTweakBar(igl::ReTwBar* bar, tinyxml2::XMLDocument* doc)
+{
+  std::vector<char**> buffer;
+	
+	std::string name = bar->name + "_AntTweakBar";
+	igl::XMLSerializer* s = new igl::XMLSerializer(name);
+	
+  const std::vector<igl::ReTwRWItem>& rw_items = bar->get_rw_items();
+	for(std::vector<ReTwRWItem>::const_iterator it = rw_items.begin(); it != rw_items.end(); it++)
+	{	
+		std::string val = bar->get_value_as_string(it->var,it->type);
+		char** cval = new char*; // create char* on heap
+		*cval = new char[val.size()+1];
+		buffer.push_back(cval);
+		strcpy(*cval,val.c_str());
+		s->Add(*cval,it->name);
+	}
+
+	char var[MAX_CB_VAR_SIZE];
+	// Print all CB variables
+  const std::vector<igl::ReTwCBItem>& cb_items = bar->get_cb_items();
+	for(std::vector<ReTwCBItem>::const_iterator it = cb_items.begin(); it != cb_items.end(); it++)
+	{
+		TwType type = it->type;
+		//TwSetVarCallback setCallback = it->setCallback;
+		TwGetVarCallback getCallback = it->getCallback;
+		void * clientData = it->clientData;
+		// I'm not sure how to do what I want to do. getCallback needs to be sure
+		// that it can write to var. So var needs to point to a valid and big
+		// enough chunk of memory
+		getCallback(var,clientData);
+		
+		std::string val = bar->get_value_as_string(var,type);
+		char** cval = new char*; // create char* on heap
+		*cval = new char[val.size()+1];
+		buffer.push_back(cval);
+		strcpy(*cval,val.c_str());
+		s->Add(*cval,it->name);
+	}
+
+	s->SaveToXMLDoc(name,doc);
+
+	// delete pointer buffers
+	for(int i=0;i<buffer.size();i++)
+	{
+		delete[] *buffer[i];
+		delete buffer[i];
+	}
+
+	delete s;
+
+	return true;
+}
+
+IGL_INLINE bool igl::load_ReAntTweakBar(igl::ReTwBar* bar, const char *file_name)
+{
+	char type_str[MAX_WORD];
+	char value_str[MAX_WORD];
+	TwType type;
+	
+  std::string name = bar->name + "_AntTweakBar";
+
+  const std::vector<igl::ReTwRWItem>& rw_items = bar->get_rw_items();
+	for(std::vector<ReTwRWItem>::const_iterator it = rw_items.begin(); it != rw_items.end(); it++)
+	{	
+		char* val;
+		igl::XMLSerializer::LoadObject(val,it->name,name,file_name);
+		sscanf(val,"%s %[^\n]",type_str,value_str);
+		
+		if(!bar->type_from_string(type_str,type))
+		{
+		  printf("ERROR: %s type not found... Skipping...\n",type_str);
+		  continue;
+		}
+		
+		bar->set_value_from_string(it->name.c_str(),type,value_str);
+		delete[] val;
+	}
+
+  const std::vector<igl::ReTwCBItem>& cb_items = bar->get_cb_items();
+	for(std::vector<ReTwCBItem>::const_iterator it = cb_items.begin(); it != cb_items.end(); it++)
+	{
+		char* val;
+		igl::XMLSerializer::LoadObject(val,it->name,name,file_name);
+		sscanf(val,"%s %[^\n]",type_str,value_str);
+		
+		if(!bar->type_from_string(type_str,type))
+		{
+		  printf("ERROR: %s type not found... Skipping...\n",type_str);
+		  continue;
+		}
+		
+		bar->set_value_from_string(it->name.c_str(),type,value_str);
+		delete[] val;
+	}
+
+	return true;
+}
+
+IGL_INLINE bool igl::load_ReAntTweakBar(igl::ReTwBar* bar, tinyxml2::XMLDocument* doc)
+{
+	std::map<std::string,char*> variables;
+	std::map<std::string,char*> cbVariables;
+
+	std::string name = bar->name + "_AntTweakBar";
+	igl::XMLSerializer* s = new igl::XMLSerializer(name);
+	
+	std::map<std::string,char*>::iterator iter;
+  const std::vector<igl::ReTwRWItem>& rw_items = bar->get_rw_items();
+	for(std::vector<ReTwRWItem>::const_iterator it = rw_items.begin(); it != rw_items.end(); it++)
+	{	
+		variables[it->name] = NULL;
+		iter = variables.find(it->name);
+		s->Add(iter->second,iter->first);
+	}
+
+	// Add all CB variables
+  const std::vector<igl::ReTwCBItem>& cb_items = bar->get_cb_items();
+	for(std::vector<ReTwCBItem>::const_iterator it = cb_items.begin(); it != cb_items.end(); it++)
+	{
+		cbVariables[it->name] = NULL;
+		iter = cbVariables.find(it->name);
+		s->Add(iter->second,iter->first);
+	}
+	
+	s->LoadFromXMLDoc(doc);
+
+	// Set loaded values
+	char type_str[MAX_WORD];
+	char value_str[MAX_WORD];
+	TwType type;
+
+	for(iter = variables.begin(); iter != variables.end(); iter++)
+	{
+		sscanf(iter->second,"%s %[^\n]",type_str,value_str);
+		
+		if(!bar->type_from_string(type_str,type))
+		{
+		  printf("ERROR: %s type not found... Skipping...\n",type_str);
+		  continue;
+		}
+		
+		bar->set_value_from_string(iter->first.c_str(),type,value_str);
+	}
+
+	for(iter = cbVariables.begin(); iter != cbVariables.end(); iter++)
+	{
+		sscanf(iter->second,"%s %[^\n]",type_str,value_str);
+		
+		if(!bar->type_from_string(type_str,type))
+		{
+		  printf("ERROR: %s type not found... Skipping...\n",type_str);
+		  continue;
+		}
+		
+		bar->set_value_from_string(iter->first.c_str(),type,value_str);
+	}
+
+	// delete buffers
+	for(iter = variables.begin(); iter != variables.end(); iter++)
+		delete[] iter->second;
+
+	for(iter = cbVariables.begin(); iter != cbVariables.end(); iter++)
+		delete[] iter->second;	
+
+	delete s;
+
+	return true;
+}

+ 17 - 0
include/igl/xml/ReAntTweakBarXMLSerialization.h

@@ -0,0 +1,17 @@
+#ifndef IGL_REANTTWEAKBAR_XML_SERIALIZATION_H
+#define IGL_REANTTWEAKBAR_XML_SERIALIZATION_H
+#include "../igl_inline.h"
+
+namespace igl
+{  
+  IGL_INLINE bool save_ReAntTweakBar(igl::ReTwBar* bar, const char* file_name);
+  IGL_INLINE bool save_ReAntTweakBar(igl::ReTwBar* bar, tinyxml2::XMLDocument* doc);
+  IGL_INLINE bool load_ReAntTweakBar(igl::ReTwBar* bar, const char *file_name);
+  IGL_INLINE bool load_ReAntTweakBar(igl::ReTwBar* bar, tinyxml2::XMLDocument* doc);
+}
+
+#ifdef IGL_HEADER_ONLY
+#  include "ReAntTweakBarXMLSerialization.cpp"
+#endif
+
+#endif

+ 1878 - 0
include/igl/xml/XMLSerializer.cpp

@@ -0,0 +1,1878 @@
+#include "XMLSerializer.h"
+
+namespace igl
+{
+  int numForbiddenChars = 8;
+  char forbiddenChars[] = {' ','/','~','#','&','>','<','='};
+}
+
+void igl::ReplaceSubString(std::string& str, const std::string& search, const std::string& replace)
+{
+  size_t pos = 0;
+  while ((pos = str.find(search, pos)) != std::string::npos)
+  {
+    str.replace(pos, search.length(), replace);
+    pos += replace.length();
+  }
+}
+
+void igl::EncodeXMLElementName(std::string& name)
+{    
+  // must not start with a digit
+  if(isdigit(*name.begin()))
+  {
+    name = ":::" + name;
+  }
+    
+  std::stringstream stream;
+  for(int i=0;i<numForbiddenChars;i++)
+  {
+    std::string search;
+    search = forbiddenChars[i];
+    std::stringstream replaces;
+    replaces << ":" << (int)forbiddenChars[i];
+    std::string replace = replaces.str(); 
+      
+    ReplaceSubString(name,search,replace);
+  }
+}
+
+/*void igl::DecodeXMLElementName(std::string& name)
+{
+  if(name.find("::", 0) == 0)
+    name.replace(0,3,"");
+
+  std::stringstream stream;
+  for(int i=0;i<numForbiddenChars;i++)
+  {
+    std::stringstream searchs;
+    searchs << ":" << (int)forbiddenChars[i];
+    std::string search = searchs.str();
+    std::string replace;
+    replace = forbiddenChars[i];
+      
+    ReplaceSubString(name,search,replace);
+  }
+}*/
+
+void igl::XMLSerialization::Init()
+{
+}
+
+bool igl::XMLSerialization::Serialize(tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element)
+{
+  bool serialized;
+  
+  if(BeforeSerialization())
+  {
+    serialized = xmlSerializer->SaveGroupToXMLElement(doc,element,Name);
+    AfterSerialization();
+  }
+
+  return serialized;
+}
+
+bool igl::XMLSerialization::Deserialize(tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element)
+{
+  bool serialized;
+  
+  if(BeforeDeserialization())
+  {
+    serialized = xmlSerializer->LoadGroupFromXMLElement(Name,doc,element);
+    AfterDeserialization();
+  }
+  
+  return serialized;
+}
+
+igl::XMLSerialization::XMLSerialization(const std::string& name)
+{
+  Name = name;
+  xmlSerializer = new igl::XMLSerializer(name);
+}
+
+igl::XMLSerialization::~XMLSerialization()
+{
+  delete xmlSerializer;
+}
+
+bool igl::XMLSerialization::BeforeSerialization()
+{
+  return true;
+}
+
+void igl::XMLSerialization::AfterSerialization()
+{
+}
+
+bool igl::XMLSerialization::BeforeDeserialization()
+{
+  return true;
+}
+
+void igl::XMLSerialization::AfterDeserialization()
+{
+}
+
+igl::XMLSerializableObject::XMLSerializableObject(const std::string& name, const std::string& group)
+{
+  std::string groupName = group;
+  std::string objectName = name;
+    
+  igl::EncodeXMLElementName(groupName);
+  igl::EncodeXMLElementName(objectName);
+    
+  Name = objectName;
+}
+
+igl::XMLSerializableObject::~XMLSerializableObject()
+{
+}
+
+// set attribute conversion functions
+void igl::XMLSerializableObject::SetAttribute(tinyxml2::XMLElement* element, const char* name, char& dest)
+{ 
+  element->SetAttribute(name,dest);
+}
+  
+void igl::XMLSerializableObject::SetAttribute(tinyxml2::XMLElement* element, const char* name, char*& dest)
+{ 
+  element->SetAttribute(name,const_cast<const char*>(dest));
+}
+
+void igl::XMLSerializableObject::SetAttribute(tinyxml2::XMLElement* element, const char* name, std::string& dest)
+{
+  element->SetAttribute(name,dest.c_str());
+}
+
+void igl::XMLSerializableObject::SetAttribute(tinyxml2::XMLElement* element, const char* name, bool& dest)
+{
+  element->SetAttribute(name,dest);
+}
+  
+void igl::XMLSerializableObject::SetAttribute(tinyxml2::XMLElement* element, const char* name, unsigned int& dest)
+{
+  element->SetAttribute(name,dest);
+}
+
+void igl::XMLSerializableObject::SetAttribute(tinyxml2::XMLElement* element, const char* name, int& dest)
+{
+  element->SetAttribute(name,dest);
+}
+
+void igl::XMLSerializableObject::SetAttribute(tinyxml2::XMLElement* element, const char* name, float& dest)
+{
+  element->SetAttribute(name,dest);
+}
+
+void igl::XMLSerializableObject::SetAttribute(tinyxml2::XMLElement* element, const char* name, double& dest)
+{
+  element->SetAttribute(name,dest);
+}
+
+// get attribute conversion functions
+void igl::XMLSerializableObject::GetAttribute(const char* src, char& dest)
+{ 
+  dest = (char)atoi(src);
+}
+  
+void igl::XMLSerializableObject::GetAttribute(const char* src, char*& dest)
+{ 
+  unsigned int length = strlen(src)+1;
+  dest = new char[length];
+  strcpy(dest, src);
+}
+
+void igl::XMLSerializableObject::GetAttribute(const char* src, std::string& dest)
+{
+  dest = src;
+}
+  
+void igl::XMLSerializableObject::GetAttribute(const char* src, bool& dest)
+{
+  tinyxml2::XMLUtil::ToBool(src,&dest);
+}
+  
+void igl::XMLSerializableObject::GetAttribute(const char* src, unsigned int& dest)
+{
+  tinyxml2::XMLUtil::ToUnsigned(src,&dest);
+}
+
+void igl::XMLSerializableObject::GetAttribute(const char* src, int& dest)
+{
+  tinyxml2::XMLUtil::ToInt(src,&dest);
+}
+
+void igl::XMLSerializableObject::GetAttribute(const char* src, float& dest)
+{
+  tinyxml2::XMLUtil::ToFloat(src,&dest);
+}
+
+void igl::XMLSerializableObject::GetAttribute(const char* src, double& dest)
+{
+  tinyxml2::XMLUtil::ToDouble(src,&dest);
+}
+
+// specify default value of types
+template<typename T>
+void igl::XMLSerializableObject::Init(T*& obj)
+{
+  igl::XMLSerializable* object = static_cast<igl::XMLSerializable*>(obj);
+  object->Init();  
+}
+
+template<>
+void igl::XMLSerializableObject::Init(char& val)
+{
+  val = '0';
+}
+
+template<>
+void igl::XMLSerializableObject::Init(char*& val)
+{
+  val = NULL;
+}
+
+template<>
+void igl::XMLSerializableObject::Init(std::string& val)
+{
+  val = "";
+}
+
+template<>
+void igl::XMLSerializableObject::Init(bool& val)
+{
+  val = false;
+}
+
+template<>
+void igl::XMLSerializableObject::Init(unsigned int& val)
+{
+  val = 0;
+}
+
+template<>
+void igl::XMLSerializableObject::Init(int& val)
+{
+  val = 0;
+}
+
+template<>
+void igl::XMLSerializableObject::Init(float& val)
+{
+  val = 0.0f;
+}
+
+template<>
+void igl::XMLSerializableObject::Init(double& val)
+{
+  val = 0.000000000000000;
+}
+
+template<typename T, int S>
+void igl::XMLSerializableObject::Init(std::array<T,S>& obj)
+{
+  for(int i=0;i<obj.size();i++)
+    Init(obj[i]);  
+}
+
+template<typename T0, typename T1>
+void igl::XMLSerializableObject::Init(std::pair<T0,T1>& obj)
+{
+  Init(obj.first);
+  Init(obj.second);
+}
+
+template<typename T>
+void igl::XMLSerializableObject::Init(std::vector<T>& obj)
+{
+  obj.clear();
+}
+
+template<typename T, int R, int C>
+void igl::XMLSerializableObject::Init(Eigen::Matrix<T,R,C>& obj)
+{
+  obj.setZero(obj.rows(),obj.cols());
+}
+
+template<typename T>
+void  igl::XMLSerializableObject::Init(Eigen::SparseMatrix<T>& obj)
+{
+  obj.setZero();
+}
+
+template<typename T>
+bool igl::XMLSerializableObject::Serialize(T& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name)
+{ 
+  return false;
+}
+
+template<typename T>
+bool igl::XMLSerializableObject::Serialize(T*& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name)
+{
+  // Serialize object implementing XMLSerializable interface
+  igl::XMLSerializable* object = static_cast<igl::XMLSerializable*>(obj);
+  
+  tinyxml2::XMLElement* child = doc->NewElement(name.c_str());
+  element->InsertEndChild(child);
+  
+  return object->Serialize(doc,child);
+}
+
+template<>
+bool igl::XMLSerializableObject::Serialize(char& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name)
+{
+  return setElementAttribute(obj,doc,element,name);
+}
+
+// template specialisation for char*, it interpreted as char array and can be used to handle strings
+template<>
+bool igl::XMLSerializableObject::Serialize(char*& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name)
+{
+  return setElementAttribute(obj,doc,element,name);
+}
+
+template<>
+bool igl::XMLSerializableObject::Serialize(std::string& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name)
+{
+  return setElementAttribute(obj,doc,element,name);
+}
+
+template<>
+bool igl::XMLSerializableObject::Serialize(std::string*& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name)
+{
+  return Serialize(*obj,doc,element,name);
+}
+
+template<>
+bool igl::XMLSerializableObject::Serialize(bool& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name)
+{
+  return setElementAttribute(obj,doc,element,name);
+}
+
+template<>
+bool igl::XMLSerializableObject::Serialize(bool*& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name)
+{
+  return Serialize(*obj,doc,element,name);
+}
+
+template<>
+bool igl::XMLSerializableObject::Serialize(unsigned int& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name)
+{
+  return setElementAttribute(obj,doc,element,name);
+}
+
+template<>
+bool igl::XMLSerializableObject::Serialize(unsigned int*& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name)
+{
+  return Serialize(*obj,doc,element,name);
+}
+
+template<>
+bool igl::XMLSerializableObject::Serialize(int& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name)
+{
+  return setElementAttribute(obj,doc,element,name);
+}
+
+template<>
+bool igl::XMLSerializableObject::Serialize(int*& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name)
+{
+  return Serialize(*obj,doc,element,name);
+}
+
+template<>
+bool igl::XMLSerializableObject::Serialize(float& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name)
+{
+  return setElementAttribute(obj,doc,element,name);
+}
+
+template<>
+bool igl::XMLSerializableObject::Serialize(float*& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name)
+{
+  return Serialize(*obj,doc,element,name);
+}
+
+template<>
+bool igl::XMLSerializableObject::Serialize(double& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name)
+{
+  return setElementAttribute(obj,doc,element,name);
+}
+
+template<>
+bool igl::XMLSerializableObject::Serialize(double*& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name)
+{
+  return Serialize(*obj,doc,element,name);
+}
+
+template<typename T>
+bool igl::XMLSerializableObject::Deserialize(T& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name)
+{
+  return false;  
+}
+
+template<typename T>
+bool igl::XMLSerializableObject::Deserialize(T*& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name)
+{
+  obj = new T();
+  igl::XMLSerializable* object = static_cast<igl::XMLSerializable*>(obj);
+  
+  const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str());
+
+  object->Name = child->FirstChild()->Value();
+
+  if(child != NULL)
+  {  
+    obj->Deserialize(doc,child);
+  }
+  else
+  {
+    obj->Init();
+    return false;
+  }
+}
+
+template<>
+bool igl::XMLSerializableObject::Deserialize(char& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name)
+{
+  return getElementAttribute(obj,doc,element,name);      
+}
+
+// template specialisation for char*, it interpreted as char array and can be used to handle strings
+template<>
+bool igl::XMLSerializableObject::Deserialize(char*& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name)
+{
+  return getElementAttribute(obj,doc,element,name);    
+}
+
+template<>
+bool igl::XMLSerializableObject::Deserialize(std::string& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name)
+{
+  return getElementAttribute(obj,doc,element,name);
+}
+
+template<>
+bool igl::XMLSerializableObject::Deserialize(std::string*& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name)
+{
+  return Deserialize(*obj,doc,element,name);
+}
+
+template<>
+bool igl::XMLSerializableObject::Deserialize(bool& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name)
+{
+  return getElementAttribute(obj,doc,element,name);
+}
+
+template<>
+bool igl::XMLSerializableObject::Deserialize(bool*& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name)
+{
+  return Deserialize(*obj,doc,element,name);
+}
+
+template<>
+bool igl::XMLSerializableObject::Deserialize(unsigned int& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name)
+{
+  return getElementAttribute(obj,doc,element,name);
+}
+
+template<>
+bool igl::XMLSerializableObject::Deserialize(unsigned int*& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name)
+{
+  return Deserialize(*obj,doc,element,name);
+}
+
+template<>
+bool igl::XMLSerializableObject::Deserialize(int& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name)
+{
+  return getElementAttribute(obj,doc,element,name);
+}
+
+template<>
+bool igl::XMLSerializableObject::Deserialize(int*& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name)
+{
+  return Deserialize(*obj,doc,element,name);
+}
+
+template<>
+bool igl::XMLSerializableObject::Deserialize(float& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name)
+{
+  return getElementAttribute(obj,doc,element,name);
+}
+
+template<>
+bool igl::XMLSerializableObject::Deserialize(float*& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name)
+{
+  return Deserialize(*obj,doc,element,name);
+}
+
+template<>
+bool igl::XMLSerializableObject::Deserialize(double& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name)
+{
+  return getElementAttribute(obj,doc,element,name);
+}
+
+template<>
+bool igl::XMLSerializableObject::Deserialize(double*& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name)
+{
+  return Deserialize(*obj,doc,element,name);
+}
+
+template<typename T, int S>
+bool igl::XMLSerializableObject::Serialize(std::array<T,S>& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name)
+{
+  tinyxml2::XMLElement* ar = doc->NewElement(name.c_str());
+  element->InsertEndChild(ar);
+  
+  ar->SetAttribute("size",obj.size());
+    
+  std::stringstream num;
+  for(int i=0;i<obj.size();i++)
+  {
+    num.str("");
+    num << "value" << i;
+    Serialize(obj[i],doc,ar,num.str());
+  }
+
+  return true;
+}
+
+template<typename T, int S>
+bool igl::XMLSerializableObject::Serialize(std::array<T,S>*& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name)
+{
+  return Serialize(*obj,doc,element,name);
+}
+
+template<typename T, int S>
+bool igl::XMLSerializableObject::Deserialize(std::array<T,S>& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name)
+{
+  bool res = true;
+     
+  const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str());
+  if(child != NULL)
+  {  
+    int size = child->UnsignedAttribute("size");
+    size = std::min(S,size);
+
+    std::stringstream num;
+    const tinyxml2::XMLAttribute* attribute = NULL;
+    for(int i=0;i<size;i++)
+    {
+      num.str("");
+      num << "value" << i;
+      
+      res &= Deserialize(obj[i],doc,child,num.str());
+    }
+  }
+  else
+    return false;
+  
+  return res;
+}
+
+template<typename T, int S>
+bool igl::XMLSerializableObject::Deserialize(std::array<T,S>*& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name)
+{
+  obj = new std::array<T,S>();
+  return Deserialize(*obj,doc,element,name);
+}
+
+template<typename T0, typename T1>
+bool igl::XMLSerializableObject::Serialize(std::pair<T0,T1>& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name)
+{
+  bool res = true;
+
+  tinyxml2::XMLElement* pair = doc->NewElement(name.c_str());
+  element->InsertEndChild(pair);
+
+  res &= Serialize(obj.first,doc,pair,"first");
+  res &= Serialize(obj.second,doc,pair,"second");
+
+  return res;
+}
+
+template<typename T0, typename T1>
+bool igl::XMLSerializableObject::Serialize(std::pair<T0,T1>*& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name)
+{
+  return Serialize(*obj,doc,element,name);
+}
+
+template<typename T0, typename T1>
+bool igl::XMLSerializableObject::Deserialize(std::pair<T0,T1>& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name)
+{
+  bool res = true;
+  
+  const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str());
+  if(child != NULL)
+  {  
+    res &= Deserialize(obj.first,doc,child,"first");
+    res &= Deserialize(obj.second,doc,child,"second");
+  }
+  else
+  {
+    Init(obj.first);
+    Init(obj.second);
+    return false;
+  }
+
+  return res;
+}
+
+template<typename T0, typename T1>
+bool igl::XMLSerializableObject::Deserialize(std::pair<T0,T1>*& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name)
+{
+  obj = new std::pair<T0,T1>();
+  return Deserialize(*obj,doc,element,name);
+}
+
+template<typename T>
+bool igl::XMLSerializableObject::Serialize(std::vector<T>& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name)
+{
+  tinyxml2::XMLElement* vector = doc->NewElement(name.c_str());
+  element->InsertEndChild(vector);
+  
+  vector->SetAttribute("size",obj.size());
+    
+  std::stringstream num;
+  for(int i=0;i<obj.size();i++)
+  {
+    num.str("");
+    num << "value" << i;
+    Serialize(obj[i],doc,vector,num.str());
+  }
+
+  return true;
+}
+
+template<typename T>
+bool igl::XMLSerializableObject::Deserialize(std::vector<T>& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name)
+{
+  bool res = true;
+  obj.clear();
+    
+  const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str());
+  if(child != NULL)
+  {  
+    int size = child->UnsignedAttribute("size");
+    obj.resize(size);
+
+    std::stringstream num;
+    const tinyxml2::XMLAttribute* attribute = NULL;
+    for(int i=0;i<size;i++)
+    {
+      num.str("");
+      num << "value" << i;
+      
+      res &= Deserialize(obj[i],doc,child,num.str());
+    }
+  }
+  else
+    return false;
+  
+  return res;
+}
+
+template<typename T>
+bool igl::XMLSerializableObject::Serialize(std::vector<T>*& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name)
+{
+  return Serialize(*obj,doc,element,name);
+}
+
+template<typename T>
+bool igl::XMLSerializableObject::Deserialize(std::vector<T>*& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name)
+{
+  obj = new vector<T>();
+  return Deserialize(*obj,doc,element,name);
+}
+
+template<typename T, int R, int C>
+bool igl::XMLSerializableObject::Serialize(Eigen::Matrix<T,R,C>& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name)
+{
+  tinyxml2::XMLElement* matrix = doc->NewElement(name.c_str());
+  element->InsertEndChild(matrix);
+  
+  const int rows = obj.rows();
+  const int cols = obj.cols();
+
+  matrix->SetAttribute("rows",rows);
+  matrix->SetAttribute("cols",cols);
+
+  std::stringstream ms;
+  ms << "\n";
+  for(int r=0;r<rows;r++)
+  {
+    for(int c=0;c<cols;c++)
+    {
+      ms << obj(r,c) << ",";
+    }
+    ms << "\n";
+  }
+
+  std::string mString = ms.str();
+  if(mString.size() > 1)
+    mString[mString.size()-2] = '\0';
+
+  matrix->SetAttribute("matrix",mString.c_str());
+    
+  return true;
+}
+
+template<typename T, int R, int C>
+bool igl::XMLSerializableObject::Serialize(Eigen::Matrix<T,R,C>*& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name)
+{
+  return Serialize(*obj,doc,element,name);
+}
+
+template<typename T, int R, int C>
+bool igl::XMLSerializableObject::Deserialize(Eigen::Matrix<T,R,C>& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name)
+{
+  const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str());
+  if(child != NULL)
+  {
+    const int rows = child->UnsignedAttribute("rows");
+    const int cols = child->UnsignedAttribute("cols");
+    
+    obj.resize(rows,cols);
+    
+    const tinyxml2::XMLAttribute* attribute = child->FindAttribute("matrix");
+    if(attribute == NULL)
+    {
+      Init(obj);
+      return false;
+    }
+    
+    char* matTemp; 
+    GetAttribute(attribute->Value(),matTemp);
+    
+    std::string line, srows, scols;
+    std::stringstream mats;
+    mats.str(matTemp);
+    
+    int r=0;
+    std::string val;
+    // for each line
+    getline(mats,line);
+    while(getline(mats,line))
+    {
+      // get current line
+      std::stringstream liness(line);
+
+      for(int c=0;c<cols-1;c++)
+      {
+        // split line
+        getline(liness, val, ',');
+
+        // push pack the data if any
+        if(!val.empty())
+          GetAttribute(val.c_str(),obj.coeffRef(r,c));
+      }
+
+      getline(liness, val);
+      GetAttribute(val.c_str(),obj.coeffRef(r,cols-1));
+
+      r++;
+    }
+  }
+  else
+  {
+    Init(obj);
+    return false;
+  }
+    
+  return true;
+}
+
+template<typename T, int R, int C>
+bool igl::XMLSerializableObject::Deserialize(Eigen::Matrix<T,R,C>*& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name)
+{
+  obj = new Eigen::PlainObjectBase<T>();
+  return Deserialize(*obj,doc,element,name);
+}
+
+template<typename T>
+bool igl::XMLSerializableObject::Serialize(Eigen::SparseMatrix<T>& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name)
+{
+  tinyxml2::XMLElement* matrix = doc->NewElement(name.c_str());
+  element->InsertEndChild(matrix);
+
+  const int rows = obj.rows();
+  const int cols = obj.cols();
+
+  matrix->SetAttribute("rows",rows);
+  matrix->SetAttribute("cols",cols);
+    
+  std::stringstream ms;
+  ms << "\n";
+  for (int k=0;k<obj.outerSize();++k)
+  {
+    for (Eigen::SparseMatrix<T>::InnerIterator it(obj,k);it;++it)
+    {
+      ms << it.row() << "," << it.col() << "," << it.value() << "\n";
+    }
+  }
+
+  std::string mString = ms.str();
+  if(mString.size() > 0)
+    mString[mString.size()-1] = '\0';
+
+  matrix->SetAttribute("matrix",mString.c_str());
+
+  return true;
+}
+
+template<typename T>
+bool igl::XMLSerializableObject::Serialize(Eigen::SparseMatrix<T>*& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name)
+{
+  return Serialize(*obj,doc,element,name);
+}
+
+template<typename T>
+bool igl::XMLSerializableObject::Deserialize(Eigen::SparseMatrix<T>& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name)
+{
+  const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str());
+  if(child != NULL)
+  {
+    const int rows = child->UnsignedAttribute("rows");
+    const int cols = child->UnsignedAttribute("cols");
+    
+    obj.resize(rows,cols);
+    obj.setZero();
+    
+    const tinyxml2::XMLAttribute* attribute = child->FindAttribute("matrix");
+    if(attribute == NULL)
+    {
+      Init(obj);
+      return false;
+    }
+    
+    char* matTemp; 
+    GetAttribute(attribute->Value(),matTemp);
+
+    std::string line, srows, scols;
+    std::stringstream mats;
+    mats.str(matTemp);
+
+    std::vector<Eigen::Triplet<T>> triplets;
+    int r=0;
+    std::string val;
+
+    // for each line
+    getline(mats,line);
+    while(getline(mats,line))
+    {
+      // get current line
+      std::stringstream liness(line);
+
+      // row
+      getline(liness, val, ',');
+      int row = atoi(val.c_str());
+      // col
+      getline(liness, val, ',');
+      int col = atoi(val.c_str());
+      // val
+      getline(liness, val);
+      T value;
+      GetAttribute(val.c_str(),value);
+
+      triplets.push_back(Eigen::Triplet<T>(row,col,value));
+
+      r++;
+    }
+
+    obj.setFromTriplets(triplets.begin(),triplets.end());
+  }
+  else
+  {
+    Init(obj);
+    return false;
+  }
+    
+  return true;
+}
+
+template<typename T>
+bool igl::XMLSerializableObject::Deserialize(Eigen::SparseMatrix<T>*& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name)
+{
+  obj = new Eigen::SparseMatrix<T>();
+  return Deserialize(*obj,doc,element,name);
+}
+
+template<typename T>
+bool igl::XMLSerializableObject::setElementAttribute(T& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name)
+{
+  tinyxml2::XMLElement* child = doc->NewElement(name.c_str());
+  element->InsertEndChild(child);
+  SetAttribute(child,"val",obj);
+  return true;
+}
+
+template<typename T>
+bool igl::XMLSerializableObject::getElementAttribute(T& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name)
+{
+// basic data type
+  const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str());
+  if(child != NULL)
+  {  
+    igl::XMLSerializableObject::GetAttribute(child->Attribute("val"),obj);
+    return true;
+  }
+  else
+  {
+    Init(obj);
+    return false;
+  }
+}
+
+template<typename T>
+igl::XMLSerializableInstance<T>::XMLSerializableInstance(T& obj, const std::string& name, const std::string group)
+  : XMLSerializableObject(name, group), Object(obj)
+{
+  igl::XMLSerializableObject::Init(DefaultValue);
+}
+
+template<typename T>
+igl::XMLSerializableInstance<T>::XMLSerializableInstance(T& obj, const std::string& name, const std::string group, T defaultValue)
+  : XMLSerializableObject(name, group), Object(obj), DefaultValue(defaultValue)
+{
+}
+
+template<typename T>
+igl::XMLSerializableInstance<T>::~XMLSerializableInstance()
+{
+}
+
+template<typename T>
+void igl::XMLSerializableInstance<T>::Init()
+{
+  igl::XMLSerializableObject::Init(DefaultValue);
+}
+
+template<typename T>
+bool igl::XMLSerializableInstance<T>::Serialize(tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element)
+{
+  return igl::XMLSerializableObject::Serialize(Object,doc,element,Name);
+}
+
+template<typename T>
+bool igl::XMLSerializableInstance<T>::Deserialize(tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element)
+{
+  return igl::XMLSerializableObject::Deserialize(Object,doc,element,Name);
+}
+
+template<typename T>
+static bool igl::XMLSerializer::SaveObject(T& object, const char* filename)
+{
+  return SaveObject(object,"Object","Serialization",filename,true);
+}
+
+template<typename T>
+static bool igl::XMLSerializer::SaveObject(T& object, const std::string& objectName, const std::string& groupName, const char* filename, bool overwrite)
+{
+  bool result = true;
+  XMLSerializer* serializer = new XMLSerializer(groupName);
+  result &= serializer->Add(object,objectName);
+  result &= serializer->Save(objectName,groupName,filename,overwrite);
+  delete serializer;
+  return result;
+}
+
+template<typename T>
+static bool igl::XMLSerializer::LoadObject(T& object, const char* filename)
+{
+  return LoadObject(object,"Object","Serialization",filename);
+}
+
+template<typename T>
+static bool igl::XMLSerializer::LoadObject(T& object, const std::string& objectName, const std::string& groupName, const char* filename)
+{
+  bool result = true;
+  XMLSerializer* serializer = new XMLSerializer(groupName);
+  result &= serializer->Add(object,objectName);
+  result &= serializer->Load(objectName,groupName,filename);
+  delete serializer;
+  return result;
+}
+    
+igl::XMLSerializer::XMLSerializer(const std::string& defaultGroup) 
+{
+  SetCurrentGroup(defaultGroup);
+}
+
+igl::XMLSerializer::~XMLSerializer()
+{
+  std::map<std::string,XMLSerializerGroup*>::iterator it;
+  for (it=groups.begin();it!=groups.end();it++)
+  {
+    delete it->second->Objects;
+    delete it->second;
+  }
+}
+
+bool igl::XMLSerializer::Save(const char* filename, bool overwrite)
+{
+  tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument();
+
+  if(overwrite == false)
+  {
+    // Check if file exists
+    tinyxml2::XMLError error = doc->LoadFile(filename);
+    if(error != tinyxml2::XML_NO_ERROR)
+      doc->Clear();
+  }
+
+  if(SaveToXMLDoc(doc) == false)
+    return false;
+    
+  // Save
+  tinyxml2::XMLError error = doc->SaveFile(filename);
+  if(error != tinyxml2::XML_NO_ERROR)
+  {
+    doc->PrintError();
+    return false;
+  }
+
+  delete doc;
+
+  return true;
+}
+
+bool igl::XMLSerializer::SaveToXMLDoc(tinyxml2::XMLDocument* doc)
+{
+  std::map<std::string,XMLSerializerGroup*>::iterator it;
+  for (it=groups.begin();it!=groups.end();it++)
+  {
+    // Update group
+    tinyxml2::XMLElement* element = doc->FirstChildElement(it->first.c_str());
+    if(element != NULL)
+    {
+      element->DeleteChildren();
+    }
+    else
+    {
+      element = doc->NewElement(it->first.c_str());
+      doc->InsertEndChild(element);
+    }
+
+    std::vector<XMLSerializable*>* group = it->second->Objects;
+    for(int i=0;i<group->size();i++)
+    {
+      if((*group)[i]->Serialize(doc,element) == false)
+        return false;
+    }
+  }
+
+  return true;
+}
+
+bool igl::XMLSerializer::Save(const std::string& groupName, const char* filename, bool overwrite)
+{
+  tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument();
+    
+  if(overwrite == false)
+  {
+    // Check if file exists
+    tinyxml2::XMLError error = doc->LoadFile(filename);
+    if(error != tinyxml2::XML_NO_ERROR)
+      doc->Clear();
+  }
+
+  if(SaveToXMLDoc(groupName, doc) == false)
+    return false;
+
+  // Save
+  tinyxml2::XMLError error = doc->SaveFile(filename);
+  if(error != tinyxml2::XML_NO_ERROR)
+  {
+    doc->PrintError();
+    return false;
+  }
+
+  delete doc;
+    
+  return true;
+}
+
+bool igl::XMLSerializer::SaveToXMLDoc(const std::string& groupName, tinyxml2::XMLDocument* doc)
+{
+  std::string gn = groupName;
+  EncodeXMLElementName(gn);
+    
+  std::map<std::string,XMLSerializerGroup*>::iterator it = groups.find(gn);
+  if(it == groups.end())
+    return false;
+
+  // Update group
+  tinyxml2::XMLElement* element = doc->FirstChildElement(it->first.c_str());
+  if(element != NULL)
+  {
+    element->DeleteChildren();
+  }
+  else
+  {
+    element = doc->NewElement(it->first.c_str());
+    doc->InsertEndChild(element);
+  }
+    
+  std::vector<XMLSerializable*>* groups = it->second->Objects;
+  for(int i=0;i<groups->size();i++)
+  {
+    if((*groups)[i]->Serialize(doc,element) == false)
+      return false;
+  }
+    
+  return true;
+}
+
+bool igl::XMLSerializer::Save(const std::string& objectName, const std::string& groupName, const char* filename, bool overwrite)
+{
+  tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument();
+    
+  if(overwrite == false)
+  {
+    // Check if file exists
+    tinyxml2::XMLError error = doc->LoadFile(filename);
+    if(error != tinyxml2::XML_NO_ERROR)
+      doc->Clear();
+  }
+    
+  if(SaveToXMLDoc(objectName, groupName, doc) == false)
+    return false;
+
+  // Save
+  tinyxml2::XMLError error = doc->SaveFile(filename);
+  if(error != tinyxml2::XML_NO_ERROR)
+  {
+    doc->PrintError();
+    return false;
+  }
+
+  delete doc;
+    
+  return true;
+}
+
+bool igl::XMLSerializer::SaveToXMLDoc(const std::string& objectName, const std::string& groupName, tinyxml2::XMLDocument* doc)
+{
+  std::string gn = groupName;
+  EncodeXMLElementName(gn);
+
+  std::string on = objectName;
+  EncodeXMLElementName(on);
+    
+  std::map<std::string,XMLSerializerGroup*>::iterator it = groups.find(gn);
+  if(it == groups.end())
+    return false;
+
+  // Get/Add group
+  tinyxml2::XMLElement* element = findAddGroup(doc, it->first.c_str());
+    
+  // Serialize
+  std::vector<XMLSerializable*>* groups = it->second->Objects;
+  bool found = false;
+  for(int i=0;i<groups->size();i++)
+  {
+    if((*groups)[i]->Name == on)
+    {
+      found = true;
+        
+      tinyxml2::XMLElement* child = element->FirstChildElement(on.c_str());
+      if(child != NULL)
+      {
+        element->DeleteChild(child);
+      }
+
+      if((*groups)[i]->Serialize(doc,element) == false)
+        return false;
+    }
+  }
+
+  return found;
+}
+
+bool igl::XMLSerializer::SaveGroupToXMLElement(tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name)
+{
+  return SaveGroupToXMLElement(currentGroup->first,doc,element,name);
+}
+
+bool igl::XMLSerializer::SaveGroupToXMLElement(const std::string& groupName, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name)
+{ 
+  std::string gn = groupName;
+  EncodeXMLElementName(gn);
+    
+  std::map<std::string,XMLSerializerGroup*>::iterator it = groups.find(gn);
+  if(it == groups.end())
+    return false;
+
+  // Add new group
+  tinyxml2::XMLElement* group = doc->NewElement(name.c_str());
+  element->InsertEndChild(group);
+    
+  std::vector<XMLSerializable*>* groups = it->second->Objects;
+  for(int i=0;i<groups->size();i++)
+  {
+    if((*groups)[i]->Serialize(doc,group) == false)
+      return false;
+  } 
+
+  return true;
+}
+
+bool igl::XMLSerializer::Load(const char* filename)
+{
+  tinyxml2::XMLDocument* doc = openDoc(filename);
+  if(doc == NULL)
+    return false;
+
+  if(LoadFromXMLDoc(doc) == false)
+    return false;
+
+  delete doc;
+
+  return true;
+}
+
+bool igl::XMLSerializer::LoadFromXMLDoc(tinyxml2::XMLDocument* doc)
+{
+  std::map<std::string,XMLSerializerGroup*>::iterator it;
+  for (it=groups.begin();it!=groups.end();it++)
+  {
+    tinyxml2::XMLElement* element = doc->FirstChildElement(it->first.c_str());
+    if(element == NULL)
+    return false;
+      
+    // Deserialize
+    std::vector<XMLSerializable*>* group = it->second->Objects;
+    for(int i=0;i<group->size();i++)
+    {
+      if(element == NULL || (*group)[i]->Deserialize(doc,element) == false)
+        (*group)[i]->Init(); // Load default value;
+    }
+  }
+
+  return true;
+}
+
+bool igl::XMLSerializer::Load(const std::string& groupName, const char* filename)
+{
+  tinyxml2::XMLDocument* doc = openDoc(filename);
+  if(doc == NULL)
+    return false;
+
+  if(LoadFromXMLDoc(groupName, doc) == false)
+    return false;
+
+  delete doc;
+    
+  return true;
+}
+
+bool igl::XMLSerializer::LoadFromXMLDoc(const std::string& groupName, tinyxml2::XMLDocument* doc)
+{
+  std::string gn = groupName;
+  EncodeXMLElementName(gn);
+
+  std::map<std::string,XMLSerializerGroup*>::iterator it = groups.find(gn);
+  if(it == groups.end())
+    return false;
+
+  tinyxml2::XMLElement* element = doc->FirstChildElement(it->first.c_str());
+  if(element == NULL)
+    return false;
+
+  // Deserialize
+  std::vector<XMLSerializable*>* groups = it->second->Objects;
+  for(int i=0;i<groups->size();i++)
+  {
+    if(element == NULL || (*groups)[i]->Deserialize(doc,element) == false)
+      (*groups)[i]->Init(); // Load default value;
+  }
+    
+  return true;
+}
+
+bool igl::XMLSerializer::Load(const std::string& objectName, const std::string& groupName, const char* filename)
+{
+  tinyxml2::XMLDocument* doc = openDoc(filename);
+  if(doc == NULL)
+    return false;
+
+  if(LoadFromXMLDoc(objectName,groupName,doc) == false)
+    return false;
+
+  delete doc;
+    
+  return true;
+}
+
+bool igl::XMLSerializer::LoadFromXMLDoc(const std::string& objectName, const std::string& groupName, tinyxml2::XMLDocument* doc)
+{
+  std::string gn = groupName;
+  EncodeXMLElementName(gn);
+    
+  std::string on = objectName;
+  EncodeXMLElementName(on);
+    
+  std::map<std::string,XMLSerializerGroup*>::iterator it = groups.find(gn);
+  if(it == groups.end())
+    return false;
+
+  tinyxml2::XMLElement* element = doc->FirstChildElement(it->first.c_str());
+  if(element == NULL)
+    return false;
+
+  // Deserialize
+  std::vector<XMLSerializable*>* groups = it->second->Objects;
+  bool found = false;
+  for(int i=0;i<groups->size();i++)
+  {
+    if((*groups)[i]->Name == on)
+    {
+      found = true;
+      if(element == NULL || (*groups)[i]->Deserialize(doc,element) == false)
+        (*groups)[i]->Init(); // Load default value;
+    }
+  }
+    
+  return found;
+}
+
+bool igl::XMLSerializer::LoadGroupFromXMLElement(const std::string& groupName, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element)
+{
+  std::string gn = groupName;
+  EncodeXMLElementName(gn);
+
+  std::map<std::string,XMLSerializerGroup*>::iterator it = groups.find(gn);
+  if(it == groups.end())
+    return false;
+
+  const tinyxml2::XMLElement* group = element->FirstChildElement(groupName.c_str());
+  if(group == NULL)
+    return false;
+
+  // Deserialize
+  std::vector<XMLSerializable*>* groups = it->second->Objects;
+  for(int i=0;i<groups->size();i++)
+  {
+    if(element == NULL || (*groups)[i]->Deserialize(doc,group) == false)
+      (*groups)[i]->Init(); // Load default value;
+  }
+    
+  return true;
+}
+
+void igl::XMLSerializer::SetCurrentGroup(const std::string& group)
+{
+  currentGroup = setGetGroup(group);
+}
+
+std::string igl::XMLSerializer::GetCurrentGroup()
+{
+  return currentGroup->first;
+}
+  
+template<typename T>
+bool igl::XMLSerializer::Add(T& obj, const std::string& name)
+{
+  igl::XMLSerializable* object = static_cast<igl::XMLSerializable*>(obj);
+  
+  object->Name = name;
+  return addObjectToGroup(object,currentGroup);  
+}
+
+template<>
+bool igl::XMLSerializer::Add(char& obj, const std::string& name)
+{
+  return add(obj,name);
+}
+
+template<>
+bool igl::XMLSerializer::Add(char*& obj, const std::string& name)
+{
+  return add(obj,name);
+}
+
+template<>
+bool igl::XMLSerializer::Add(std::string& obj, const std::string& name)
+{
+  return add(obj,name);
+}
+
+template<>
+bool igl::XMLSerializer::Add(bool& obj, const std::string& name)
+{
+  return add(obj,name);
+}
+
+template<>
+bool igl::XMLSerializer::Add(unsigned int& obj, const std::string& name)
+{
+  return add(obj,name);
+}
+
+template<>
+bool igl::XMLSerializer::Add(int& obj, const std::string& name)
+{
+  return add(obj,name);
+}
+
+template<>
+bool igl::XMLSerializer::Add(float& obj, const std::string& name)
+{
+  return add(obj,name);
+}
+
+template<>
+bool igl::XMLSerializer::Add(double& obj, const std::string& name)
+{
+  return add(obj,name);
+}
+
+template<typename T, int S>
+bool igl::XMLSerializer::Add(std::array<T,S>& obj, const std::string& name)
+{
+  return add(obj,name);
+}
+
+template<typename T0, typename T1>
+bool igl::XMLSerializer::Add(std::pair<T0,T1>& obj, const std::string& name)
+{
+  return add(obj,name);
+}
+
+template<typename T>
+bool igl::XMLSerializer::Add(std::vector<T>& obj, const std::string& name)
+{
+  return add(obj,name);
+}
+
+template<typename T, int R, int C>
+bool igl::XMLSerializer::Add(Eigen::Matrix<T,R,C>& obj, const std::string& name)
+{
+  return add(obj,name);
+}
+
+template<typename T>
+bool igl::XMLSerializer::Add(Eigen::SparseMatrix<T>& obj, const std::string& name)
+{
+  return add(obj,name);
+}
+
+template<typename T>
+bool igl::XMLSerializer::Add(T& object, const std::string& name, T defaultValue)
+{
+    
+}
+
+template<>
+bool igl::XMLSerializer::Add(char& obj, const std::string& name, char defaultValue)
+{
+  return add(obj,name,defaultValue);
+}
+
+template<>
+bool igl::XMLSerializer::Add(char*& obj, const std::string& name, char* defaultValue)
+{
+  return add(obj,name,defaultValue);
+}
+
+template<>
+bool igl::XMLSerializer::Add(std::string& obj, const std::string& name, std::string defaultValue)
+{
+  return add(obj,name,defaultValue);
+}
+
+template<>
+bool igl::XMLSerializer::Add(bool& obj, const std::string& name, bool defaultValue)
+{
+  return add(obj,name,defaultValue);
+}
+
+template<>
+bool igl::XMLSerializer::Add(unsigned int& obj, const std::string& name, unsigned int defaultValue)
+{
+  return add(obj,name,defaultValue);
+}
+
+template<>
+bool igl::XMLSerializer::Add(int& obj, const std::string& name, int defaultValue)
+{
+  return add(obj,name,defaultValue);
+}
+
+template<>
+bool igl::XMLSerializer::Add(float& obj, const std::string& name, float defaultValue)
+{
+  return add(obj,name,defaultValue);
+}
+
+template<>
+bool igl::XMLSerializer::Add(double& obj, const std::string& name, double defaultValue)
+{
+  return add(obj,name,defaultValue);
+}
+
+template<typename T>
+bool igl::XMLSerializer::add(T& obj, const std::string& name)
+{
+  XMLSerializable* object = new igl::XMLSerializableInstance<T>(obj,name,currentGroup->first);
+  return addObjectToGroup(object,currentGroup);
+}
+
+template<typename T>
+bool igl::XMLSerializer::add(T& obj, const std::string& name, T defaultValue)
+{
+  igl::XMLSerializable* object = new igl::XMLSerializableInstance<T>(obj,name,currentGroup->first,defaultValue);
+  return addObjectToGroup(object,currentGroup);
+}
+  
+bool igl::XMLSerializer::addObjectToGroup(XMLSerializable* obj, const std::string& group)
+{
+  std::map<std::string,XMLSerializerGroup*>::iterator it = setGetGroup(group);
+  return addObjectToGroup(obj, it);
+}
+  
+bool igl::XMLSerializer::addObjectToGroup(XMLSerializable* object, std::map<std::string,XMLSerializerGroup*>::iterator it)
+{
+  std::vector<XMLSerializable*>* objects = it->second->Objects;
+  for(int i=0;i<objects->size();i++)
+  {
+    if((*objects)[i]->Name == object->Name)
+      return false;
+  }
+
+  objects->push_back(object);
+    
+  return true;
+}
+
+std::map<std::string,igl::XMLSerializerGroup*>::iterator igl::XMLSerializer::setGetGroup(const std::string& group)
+{
+  std::string groupName = group;
+  EncodeXMLElementName(groupName);
+    
+  std::map<std::string,XMLSerializerGroup*>::iterator it = groups.find(groupName);
+  if(it == groups.end())
+  {
+    XMLSerializerGroup* newGroup = new XMLSerializerGroup();
+    newGroup->Objects = new std::vector<XMLSerializable*>();
+    groups[groupName] = newGroup;
+    it = groups.find(groupName);
+  }
+    
+  return it;
+}
+
+tinyxml2::XMLDocument* igl::XMLSerializer::openDoc(const char* filename)
+{
+  tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument();
+
+  tinyxml2::XMLError error = doc->LoadFile(filename);
+  if(error != tinyxml2::XML_NO_ERROR)
+  {
+    doc->PrintError();
+    doc = NULL;
+  }
+
+  return doc;
+}
+
+tinyxml2::XMLElement* igl::XMLSerializer::findAddGroup(tinyxml2::XMLDocument* doc, const char* groupName)
+{
+  tinyxml2::XMLElement* group = doc->FirstChildElement(groupName);
+  if(group == NULL)
+  {
+    group = doc->NewElement(groupName);
+    doc->InsertEndChild(group);
+  }
+  return group;
+}
+
+igl::XMLSerializerTest::XMLSerializerTest()
+  : XMLSerialization("testObject")
+{
+  xmlSerializer->Add(testInt,"testInt");
+  xmlSerializer->Add(testVector,"testVector");
+
+  testInt = 10;
+  
+  testVector.push_back(1.0001f);
+  testVector.push_back(2.0001f);
+  testVector.push_back(3.0001f);
+}
+
+bool igl::XMLSerializerTest::Test()
+{
+  // test vars 0
+  char testChar0 = 'a';
+  char* testCharArray0 = "testCharArray0";
+  std::string testString0 = "testString0";
+  bool testBool0 = true;
+  unsigned int testUnsigned0 = 13;
+  int testInt0 = 1000;
+  float testFloat0 = 0.00001f;
+  double testDouble0 = 0.01000000005;
+
+  std::array<float,2> testArray0 = {0.001f,1.001f};
+
+  std::pair<int,bool> testPair0;
+  testPair0.first = 5;
+  testPair0.second = true;
+
+  std::vector<int> testVector0;
+  testVector0.push_back(1);
+  testVector0.push_back(2);
+  testVector0.push_back(3);
+
+  Eigen::MatrixXi testDenseMatrix0;
+  testDenseMatrix0 = Eigen::Matrix3i::Identity();
+
+  Eigen::SparseMatrix<double> testSparseMatrix0(3,3);
+  std::vector<Eigen::Triplet<double>> triplets;
+  triplets.push_back(Eigen::Triplet<double>(0,0,1));
+  triplets.push_back(Eigen::Triplet<double>(1,1,2));
+  triplets.push_back(Eigen::Triplet<double>(2,2,3));
+  testSparseMatrix0.setFromTriplets(triplets.begin(),triplets.end());
+
+  igl::XMLSerializerTest* testObject0 = new igl::XMLSerializerTest();
+
+  std::vector<std::pair<int,bool>*> testComplex10;
+  testComplex10.push_back(&testPair0);
+  testComplex10.push_back(&testPair0);
+
+  std::vector<igl::XMLSerializerTest*> testComplex20;
+  testComplex20.push_back(testObject0);
+  testComplex20.push_back(testObject0);
+  
+  // test vars 1
+  char testChar1 = 'b';
+  char* testCharArray1 = "testCharArray1";
+  std::string testString1 = "testString1";
+  bool testBool1 = false;
+  unsigned int testUnsigned1 = 12;
+  int testInt1 = -1000;
+  float testFloat1 = -0.00001f;
+  double testDouble1 = -0.000000000001;
+
+  std::array<float,2> testArray1 = {-0.001f,-1.001f};
+
+  std::pair<int,bool> testPair1;
+  testPair1.first = -5;
+  testPair1.second = false;
+
+  std::vector<int> testVector1;
+  testVector1.push_back(-1);
+  testVector1.push_back(-2);
+  testVector1.push_back(-3);
+
+  Eigen::MatrixXi testDenseMatrix1;
+  testDenseMatrix1 = Eigen::Matrix3i::Identity();
+  testDenseMatrix1 *= 2;
+
+  Eigen::SparseMatrix<double> testSparseMatrix1(3,3);
+  triplets.clear();
+  triplets.push_back(Eigen::Triplet<double>(0,0,-1));
+  triplets.push_back(Eigen::Triplet<double>(1,1,-2));
+  triplets.push_back(Eigen::Triplet<double>(2,2,-3));
+  testSparseMatrix1.setFromTriplets(triplets.begin(),triplets.end());
+
+  igl::XMLSerializerTest* testObject1 = new igl::XMLSerializerTest();
+  testObject1->testInt = 3;
+  testObject1->testVector.clear();
+
+  std::vector<std::pair<int,bool>*> testComplex11;
+  testComplex11.push_back(&testPair1);
+  testComplex11.push_back(&testPair1);
+
+  std::vector<igl::XMLSerializerTest*> testComplex21;
+  testComplex21.push_back(testObject1);
+  testComplex21.push_back(testObject1);
+  
+  // test Serializer
+  bool testResult = true;
+  
+  // test static functions
+  
+  // check static updating
+  int testInt = 5;
+  testResult &= igl::XMLSerializer::SaveObject(testInt0,"test.xml");
+  testResult &= igl::XMLSerializer::SaveObject(testChar0,"testChar","test","test.xml",false);
+  testResult &= igl::XMLSerializer::LoadObject(testInt,"test.xml");
+  testResult &= testInt0 == testInt;
+
+  // check static overwriting
+  testInt = 3;
+  testResult &= igl::XMLSerializer::SaveObject(testInt0,"test.xml");
+  testResult &= igl::XMLSerializer::SaveObject(testChar0,"testChar","test","test.xml",true);
+  testResult &= igl::XMLSerializer::LoadObject(testInt,"test.xml") == false;
+  testResult &= testInt0 != testInt;
+
+  // check static based type saving
+  testResult &= igl::XMLSerializer::SaveObject(testChar0,"testChar","test0","test.xml",true);
+  testResult &= igl::XMLSerializer::SaveObject(testCharArray0,"testCharArray","test0","test.xml",false);
+  testResult &= igl::XMLSerializer::SaveObject(testString0,"testString","test0","test.xml",false);
+  testResult &= igl::XMLSerializer::SaveObject(testBool0,"testBool","test0","test.xml",false);
+  testResult &= igl::XMLSerializer::SaveObject(testUnsigned0,"testUnsigned","test0","test.xml",false);
+  testResult &= igl::XMLSerializer::SaveObject(testInt0,"testInt","test0","test.xml",false);
+  testResult &= igl::XMLSerializer::SaveObject(testFloat0,"testFloat","test0","test.xml",false);
+  testResult &= igl::XMLSerializer::SaveObject(testDouble0,"testDouble","test0","test.xml",false);
+  testResult &= igl::XMLSerializer::SaveObject(testArray0,"testArray","test1","test.xml",false);
+  testResult &= igl::XMLSerializer::SaveObject(testPair0,"testPair","test1","test.xml",false);
+  testResult &= igl::XMLSerializer::SaveObject(testVector0,"testVector","test1","test.xml",false);
+  testResult &= igl::XMLSerializer::SaveObject(testDenseMatrix0,"testDense","test1","test.xml",false);
+  testResult &= igl::XMLSerializer::SaveObject(testSparseMatrix0,"testSparse","test1","test.xml",false);
+  testResult &= igl::XMLSerializer::SaveObject(testObject0,"testObject","test1","test.xml",false);
+  testResult &= igl::XMLSerializer::SaveObject(testComplex10,"testComplex1","test1","test.xml",false);
+  testResult &= igl::XMLSerializer::SaveObject(testComplex20,"testComplex2","test1","test.xml",false);
+
+  testResult &= igl::XMLSerializer::LoadObject(testChar1,"testChar","test0","test.xml");
+  testResult &= igl::XMLSerializer::LoadObject(testCharArray1,"testCharArray","test0","test.xml");
+  testResult &= igl::XMLSerializer::LoadObject(testString1,"testString","test0","test.xml");
+  testResult &= igl::XMLSerializer::LoadObject(testBool1,"testBool","test0","test.xml");
+  testResult &= igl::XMLSerializer::LoadObject(testUnsigned1,"testUnsigned","test0","test.xml");
+  testResult &= igl::XMLSerializer::LoadObject(testInt1,"testInt","test0","test.xml");
+  testResult &= igl::XMLSerializer::LoadObject(testFloat1,"testFloat","test0","test.xml");
+  testResult &= igl::XMLSerializer::LoadObject(testDouble1,"testDouble","test0","test.xml");
+  testResult &= igl::XMLSerializer::LoadObject(testArray1,"testArray","test1","test.xml");
+  testResult &= igl::XMLSerializer::LoadObject(testPair1,"testPair","test1","test.xml");
+  testResult &= igl::XMLSerializer::LoadObject(testVector1,"testVector","test1","test.xml");
+  testResult &= igl::XMLSerializer::LoadObject(testDenseMatrix1,"testDense","test1","test.xml");
+  testResult &= igl::XMLSerializer::LoadObject(testSparseMatrix1,"testSparse","test1","test.xml");
+  testResult &= igl::XMLSerializer::LoadObject(testObject1,"testObject","test1","test.xml");
+  testResult &= igl::XMLSerializer::LoadObject(testComplex11,"testComplex1","test1","test.xml");
+  testResult &= igl::XMLSerializer::LoadObject(testComplex21,"testComplex2","test1","test.xml");
+
+  testResult &= testChar0 == testChar1;
+  testResult &= strcmp(testCharArray0,testCharArray1) == 0;
+  testResult &= testString0 == testString1;
+  testResult &= testBool0 == testBool1;
+  testResult &= testUnsigned0 == testUnsigned1;
+  testResult &= testInt0 == testInt1;
+  testResult &= testFloat0 == testFloat1;
+  testResult &= testDouble0 == testDouble1;
+  for(int i=0;i<testArray0.size();i++)
+    testResult &= testArray0[i] == testArray1[i];
+  testResult &= testPair0.first == testPair1.first;
+  testResult &= testPair0.second == testPair1.second;
+  testResult &= testVector0.size() == testVector1.size();
+  for(int i=0;i<testVector0.size();i++)
+    testResult &= testVector0[i] == testVector1[i];
+  testResult &= (testDenseMatrix0-testDenseMatrix1).sum() == 0;
+  testResult &= (testSparseMatrix0-testSparseMatrix1).norm() == 0;
+  testResult &= testObject0->testInt == testObject1->testInt;
+  testResult &= testObject0->testVector.size() == testObject1->testVector.size();
+  for(int i=0;i<testObject0->testVector.size();i++)
+    testResult &= testObject0->testVector[i] == testObject1->testVector[i];
+  testResult &= testComplex10.size() == testComplex11.size();
+  for(int i=0;i<testComplex10.size();i++)
+  {
+    testResult &= testComplex10[i]->first == testComplex11[0]->first;
+    testResult &= testComplex10[i]->second == testComplex11[0]->second;
+  }
+  testResult &= testComplex20.size() == testComplex21.size();
+  for(int i=0;i<testComplex20.size();i++)
+  {
+    testResult &= ((XMLSerializerTest*)testComplex20[i])->testInt == ((XMLSerializerTest*)testComplex21[i])->testInt;
+    testResult &= ((XMLSerializerTest*)testComplex20[i])->testVector.size() == ((XMLSerializerTest*)testComplex21[i])->testVector.size();
+    for(int j=0;j<((XMLSerializerTest*)testComplex20[i])->testVector.size();j++)
+       testResult &= ((XMLSerializerTest*)testComplex20[i])->testVector[j] == ((XMLSerializerTest*)testComplex21[i])->testVector[j];
+  }
+
+  igl::XMLSerializer* s = new igl::XMLSerializer("test0");
+
+  // clear file
+  testResult &= s->Save("test.xml",true);
+
+  testResult &= s->Add(testChar0,"testChar");
+  testResult &= s->Add(testCharArray0,"testCharArray");
+  testResult &= s->Add(testString0,"testString");
+  testResult &= s->Add(testBool0,"testBool");
+  testResult &= s->Add(testUnsigned0,"testUnsigned");
+  testResult &= s->Add(testInt0,"testInt");
+  testResult &= s->Add(testFloat0,"testFloat");
+  testResult &= s->Add(testDouble0,"testDouble");
+
+  s->SetCurrentGroup("test1");
+
+  testResult &= s->Add(testArray0,"testArray");
+  testResult &= s->Add(testPair0,"testPair");
+  testResult &= s->Add(testVector0,"testVector");
+  testResult &= s->Add(testDenseMatrix0,"testDenseMatrix");
+  testResult &= s->Add(testSparseMatrix0,"testSparseMatrix");
+  testResult &= s->Add(testObject0,"testObject");
+  testResult &= s->Add(testComplex10,"testComplex1");
+  testResult &= s->Add(testComplex20,"testComplex2");
+  
+  // Test single attribute save load
+  testResult &= s->Save("testComplex2","test1","test.xml",true);
+  testResult &= s->Load("testComplex2","test1","test.xml");
+  
+  testResult &= testComplex20.size() == testComplex21.size();
+  for(int i=0;i<testComplex20.size();i++)
+  {
+    testResult &= ((XMLSerializerTest*)testComplex20[i])->testInt == ((XMLSerializerTest*)testComplex21[i])->testInt;
+    testResult &= ((XMLSerializerTest*)testComplex20[i])->testVector.size() == ((XMLSerializerTest*)testComplex21[i])->testVector.size();
+    for(int j=0;j<((XMLSerializerTest*)testComplex20[i])->testVector.size();j++)
+        testResult &= ((XMLSerializerTest*)testComplex20[i])->testVector[j] == ((XMLSerializerTest*)testComplex21[i])->testVector[j];
+  }
+
+  // Test group save load without overriding
+  testResult &= s->Save("test0","test.xml",false);
+  testResult &= s->Load("test0","test.xml");
+  testResult &= s->Load("testComplex2","test1","test.xml");
+
+  testResult &= testChar0 == testChar1;
+  testResult &= strcmp(testCharArray0,testCharArray1) == 0;
+  testResult &= testString0 == testString1;
+  testResult &= testBool0 == testBool1;
+  testResult &= testUnsigned0 == testUnsigned1;
+  testResult &= testInt0 == testInt1;
+  testResult &= testFloat0 == testFloat1;
+  testResult &= testDouble0 == testDouble1;
+
+  // Test full serialization save load
+  testResult &= s->Save("test.xml",true);
+  testResult &= s->Load("test.xml");
+  
+  testResult &= testChar0 == testChar1;
+  testResult &= strcmp(testCharArray0,testCharArray1) == 0;
+  testResult &= testString0 == testString1;
+  testResult &= testBool0 == testBool1;
+  testResult &= testUnsigned0 == testUnsigned1;
+  testResult &= testInt0 == testInt1;
+  testResult &= testFloat0 == testFloat1;
+  testResult &= testDouble0 == testDouble1;
+  for(int i=0;i<testArray0.size();i++)
+    testResult &= testArray0[i] == testArray1[i];
+  testResult &= testPair0.first == testPair1.first;
+  testResult &= testPair0.second == testPair1.second;
+  testResult &= testVector0.size() == testVector1.size();
+  for(int i=0;i<testVector0.size();i++)
+    testResult &= testVector0[i] == testVector1[i];
+  testResult &= (testDenseMatrix0-testDenseMatrix1).sum() == 0;
+  testResult &= (testSparseMatrix0-testSparseMatrix1).norm() == 0;
+  testResult &= testObject0->testInt == testObject1->testInt;
+  testResult &= testObject0->testVector.size() == testObject1->testVector.size();
+  for(int i=0;i<testObject0->testVector.size();i++)
+    testResult &= testObject0->testVector[i] == testObject1->testVector[i];
+  testResult &= testComplex10.size() == testComplex11.size();
+  for(int i=0;i<testComplex10.size();i++)
+  {
+    testResult &= testComplex10[i]->first == testComplex11[0]->first;
+    testResult &= testComplex10[i]->second == testComplex11[0]->second;
+  }
+  testResult &= testComplex20.size() == testComplex21.size();
+  for(int i=0;i<testComplex20.size();i++)
+  {
+    testResult &= ((XMLSerializerTest*)testComplex20[i])->testInt == ((XMLSerializerTest*)testComplex21[i])->testInt;
+    testResult &= ((XMLSerializerTest*)testComplex20[i])->testVector.size() == ((XMLSerializerTest*)testComplex21[i])->testVector.size();
+    for(int j=0;j<((XMLSerializerTest*)testComplex20[i])->testVector.size();j++)
+        testResult &= ((XMLSerializerTest*)testComplex20[i])->testVector[j] == ((XMLSerializerTest*)testComplex21[i])->testVector[j];
+  }
+
+  delete s;
+
+  return testResult;
+}
+
+#ifndef IGL_HEADER_ONLY
+// Explicit template specialization
+
+#endif

+ 380 - 0
include/igl/xml/XMLSerializer.h

@@ -0,0 +1,380 @@
+/* ---------------------------------------------------------------------------
+// XMLSerializer.h
+// Author: Christian Schüller on 08/05/13.
+------------------------------------------------------------------------------
+
+This class allows to save and load a serialization of basic c++ data types like
+char, char*, std::string, bool, uint, int, float, double to and from a xml file.
+Containers like std::vector, std::std::pair, Eigen dense and sparse matrices are supported
+as well as combination of them (like vector<pair<string,bool>> or vector<vector<int>>).
+To serialize an arbitary object use the XMLSerializable interface.
+ 
+The serialized objects are organised in groups in the xml file and have
+their own names which must be unique within one group.
+
+You can find examples how to use it in the test case class XMLSerializerTest.
+
+----------------------------------------------------------------------------*/
+#ifndef XML_SERIALIZER_H
+#define XML_SERIALIZER_H
+
+#include <iostream>
+#include <array>
+#include <vector>
+#include <map>
+
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+
+#include "tinyxml2.h"
+
+namespace igl
+{
+
+  void EncodeXMLElementName(std::string& name);
+  //void DecodeXMLElementName(std::string& name);
+  void ReplaceSubString(std::string& str, const std::string& search, const std::string& replace);
+
+  /**
+     * interface XMLSerializable
+     * Inherit from this interface to have full control over the serialization of you user defined class.
+     */ 
+  class XMLSerializable
+  {
+  public:
+    std::string Name;
+
+    /**
+     * This function gets called if the objects were not found during deserialization.
+     * Initialize your objects as you like. 
+     */ 
+    virtual void Init() = 0;
+    /**
+     * Serialize your stuff within this function.
+     * It contains the current serialization xml file. You can use SaveToXMLDoc or SaveGroupToXMLElement to add your objects.
+     */ 
+    virtual bool Serialize(tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element) = 0;
+
+    /**
+     * Deserialize your stuff within this function.
+     * It contains the current serialization xml file. You can use LoadFromXMLDoc or LoadGroupFromXMLElement to read out your objects.
+     */ 
+    virtual bool Deserialize(tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element) = 0;
+  };
+
+  /**
+     * class XMLSerialization
+     * Inherit from this class to have the easiest way to serialize your user defined class.
+     */
+  class XMLSerialization : public XMLSerializable
+  {
+  public:
+    igl::XMLSerializer* xmlSerializer;
+
+    /**
+     * Default implementation of XMLSerializable interface
+     */
+    virtual void Init();
+    virtual bool Serialize(tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element);
+    virtual bool Deserialize(tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element);
+
+    XMLSerialization(const std::string& name);
+    ~XMLSerialization();
+
+    /**
+     * Following functions can be overwritten to handle the specific events.
+     * Return false to prevent serialization of object.
+     */
+    virtual bool BeforeSerialization();
+    virtual void AfterSerialization();
+    virtual bool BeforeDeserialization();
+    virtual void AfterDeserialization();
+  };
+
+
+  /**
+     * class XMLSerializableObject
+     * internal usage
+     */
+  class XMLSerializableObject : public XMLSerializable
+  {
+  public:
+  
+    XMLSerializableObject(const std::string& name, const std::string& group);
+    virtual ~XMLSerializableObject();
+
+    // set attribute conversion functions
+    void SetAttribute(tinyxml2::XMLElement* element, const char* name, char& dest);  
+    void SetAttribute(tinyxml2::XMLElement* element, const char* name, char*& dest);
+    void SetAttribute(tinyxml2::XMLElement* element, const char* name, std::string& dest);
+    void SetAttribute(tinyxml2::XMLElement* element, const char* name, bool& dest);
+    void SetAttribute(tinyxml2::XMLElement* element, const char* name, unsigned int& dest);
+    void SetAttribute(tinyxml2::XMLElement* element, const char* name, int& dest);
+    void SetAttribute(tinyxml2::XMLElement* element, const char* name, float& dest);
+    void SetAttribute(tinyxml2::XMLElement* element, const char* name, double& dest);
+
+    // get attribute conversion functions
+    void GetAttribute(const char* src, char& dest);
+    void GetAttribute(const char* src, char*& dest);
+    void GetAttribute(const char* src, std::string& dest);
+    void GetAttribute(const char* src, bool& dest);
+    void GetAttribute(const char* src, unsigned int& dest);
+    void GetAttribute(const char* src, int& dest);
+    void GetAttribute(const char* src, float& dest);
+    void GetAttribute(const char* src, double& dest);
+
+    // initialize objects   
+    template<typename T>
+    void Init(T& obj);
+    template<typename T>
+    void Init(T*& obj);
+    template<typename T, int S>
+    void Init(std::array<T,S>& obj);
+    template<typename T0, typename T1>
+    void Init(std::pair<T0,T1>& obj);
+    template<typename T>
+    void Init(std::vector<T>& obj);
+    template<typename T, int R, int C>
+    void Init(Eigen::Matrix<T,R,C>& obj);
+    template<typename T>
+    void Init(Eigen::SparseMatrix<T>& obj);
+
+    // base types and XMLSerializable objects
+    template<typename T>
+    bool Serialize(T& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name);
+    template<typename T>
+    bool Serialize(T*& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name);
+    template<typename T>
+    bool Deserialize(T& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name);
+    template<typename T>
+    bool Deserialize(T*& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name);
+
+    // std::array<T>
+    template<typename T, int S>
+    bool Serialize(std::array<T,S>& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name);
+    template<typename T, int S>
+    bool Serialize(std::array<T,S>*& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name);
+    template<typename T, int S>
+    bool Deserialize(std::array<T,S>& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name);
+    template<typename T, int S>
+    bool Deserialize(std::array<T,S>*& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name);
+
+    // std::pair<T0,T1>
+    template<typename T0, typename T1>
+    bool Serialize(std::pair<T0,T1>& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name);
+    template<typename T0, typename T1>
+    bool Serialize(std::pair<T0,T1>*& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name);
+    template<typename T0, typename T1>
+    bool Deserialize(std::pair<T0,T1>& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name);
+    template<typename T0, typename T1>
+    bool Deserialize(std::pair<T0,T1>*& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name);
+
+    // std::vector<T>
+    template<typename T>
+    bool Serialize(std::vector<T>& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name);
+    template<typename T>
+    bool Serialize(std::vector<T>*& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name);
+    template<typename T>
+    bool Deserialize(std::vector<T>& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name);
+    template<typename T>
+    bool Deserialize(std::vector<T>*& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name);
+   
+    // Eigen dense matrix
+    template<typename T, int R, int C>
+    bool Serialize(Eigen::Matrix<T,R,C>& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name);
+    template<typename T, int R, int C>
+    bool Serialize(Eigen::Matrix<T,R,C>*& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name);
+    template<typename T, int R, int C>
+    bool Deserialize(Eigen::Matrix<T,R,C>& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name);
+    template<typename T, int R, int C>
+    bool Deserialize(Eigen::Matrix<T,R,C>*& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name);
+
+    // Eigen sparse matrix
+    template<typename T>
+    bool Serialize(Eigen::SparseMatrix<T>& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name);
+    template<typename T>
+    bool Serialize(Eigen::SparseMatrix<T>*& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name);
+    template<typename T>
+    bool Deserialize(Eigen::SparseMatrix<T>& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name);
+    template<typename T>
+    bool Deserialize(Eigen::SparseMatrix<T>*& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name);
+
+  private:
+
+    template<typename T>
+    bool setElementAttribute(T& obj, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name);
+    template<typename T>
+    bool getElementAttribute(T& obj, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element, const std::string& name);
+  };
+
+  /**
+     * class XMLSerializableInstance
+     * internal usage
+     */
+  template<typename T>
+  class XMLSerializableInstance : public XMLSerializableObject
+  {
+  public:
+
+    T& Object;
+    T DefaultValue;
+
+    XMLSerializableInstance(T& obj, const std::string& name, const std::string group);
+    XMLSerializableInstance(T& obj, const std::string& name, const std::string group, T defaultValue);
+    ~XMLSerializableInstance();
+
+    // XMLSerializable interface implementation
+    void Init();
+    bool Serialize(tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element);
+    bool Deserialize(tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element);
+  };
+
+  /**
+     * struct XMLSerializerGroup
+     * internal usage
+     */
+  struct XMLSerializerGroup
+  {
+    std::string Name;
+    std::vector<XMLSerializable*>* Objects;
+  };
+
+  /**
+     * class XMLSerializer
+     * This is the core class which takes care of saving and loading of serialization of object structures.
+     */
+  class XMLSerializer
+  {
+  public:
+
+    /**
+     * Serializes an object to a file
+     */ 
+    template<typename T>
+    static bool SaveObject(T& object, const char* filename);
+    template<typename T>
+    static bool SaveObject(T& object, const std::string& objectName, const std::string& groupName, const char* filename, bool overwrite);
+
+    /**
+     * Loads the serialization of an object from a file.
+     */
+    template<typename T>
+    static bool LoadObject(T& object, const char* filename);
+    template<typename T>
+    static bool LoadObject(T& object, const std::string& objectName, const std::string& groupName, const char* filename);
+    
+    /**
+     * Constructor which sets the default group
+     */
+    XMLSerializer(const std::string& defaultGroup);
+    ~XMLSerializer();
+
+    /**
+     * Save the serialization of all groups to file.
+     * Parameter overwrite specifies if file gets overwritten or updated
+     */ 
+    bool Save(const char* filename, bool overwrite);
+    bool Save(const std::string& groupName, const char* filename, bool overwrite);
+    bool Save(const std::string& objectName, const std::string& groupName, const char* filename, bool overwrite);
+
+    /**
+     * Save the serialization of all groups to a XMLDocument instance.
+     */ 
+    bool SaveToXMLDoc(tinyxml2::XMLDocument* doc);
+    bool SaveToXMLDoc(const std::string& groupName, tinyxml2::XMLDocument* doc);
+    bool SaveToXMLDoc(const std::string& objectName, const std::string& groupName, tinyxml2::XMLDocument* doc);
+
+    /**
+     * Save the serialization of a group with a new provided name to given XMLElement instance.
+     */
+    bool SaveGroupToXMLElement(tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name);
+    bool SaveGroupToXMLElement(const std::string& groupName, tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element, const std::string& name);
+
+    /**
+     * Load the serialization from a file.
+     */
+    bool Load(const char* filename);
+    bool Load(const std::string& groupName, const char* filename);
+    bool Load(const std::string& objectName, const std::string& groupName, const char* filename);
+
+    /**
+     * Load the serialization from an XMLDocument instance.
+     */
+    bool LoadFromXMLDoc(tinyxml2::XMLDocument* doc);
+    bool LoadFromXMLDoc(const std::string& groupName, tinyxml2::XMLDocument* doc);
+    bool LoadFromXMLDoc(const std::string& objectName, const std::string& groupName, tinyxml2::XMLDocument* doc);    
+
+    /**
+     * Load the serialization from a XMLElement instance to given group.
+     */
+    bool LoadGroupFromXMLElement(const std::string& groupName, tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element);
+    
+    /**
+     * Set/Get current group. Every object which is added afterwards will be in this group, except it specifies another group.
+     */
+    void SetCurrentGroup(const std::string& group);
+    std::string GetCurrentGroup();
+
+    /**
+     * Add an object to the serializer. Can be simple types like char, char*, string, unsigned int, int, float, double or containers like std::array, std::pair, std::vector.
+     * Also Eigen dense or sparse matrices are supported and all objects of type Serializable* and combinations of thoses types like vector<vector>, vector<pair> or even vector<pair<vector,Serializable*>>>.
+     * Also pointers to those objects can be used (for instance like vector<vector<pair<int,float>*>*>).
+     * char* is also possible as base type and represents a array of chars, but be carefull that the pointer is not just a copy but a valid instance in the current programm scope.
+     */
+    template<typename T>
+    bool Add(T& object, const std::string& name);
+    template<typename T>
+    bool Add(T& object, const std::string& name, T defaultValue);
+
+    // stl containers
+    template<typename T, int S>
+    bool Add(std::array<T,S>& obj, const std::string& name);
+    template<typename T0, typename T1>
+    bool Add(std::pair<T0,T1>& obj, const std::string& name);
+    template<typename T>
+    bool Add(std::vector<T>& obj, const std::string& name);
+    template<typename T, int R, int C>
+    
+    // eigen matrices
+    bool Add(Eigen::Matrix<T,R,C>& obj, const std::string& name);
+    template<typename T>
+    bool Add(Eigen::SparseMatrix<T>& obj, const std::string& name);
+
+  private:
+
+    std::map<std::string,XMLSerializerGroup*>::iterator currentGroup;
+    std::map<std::string,XMLSerializerGroup*> groups;
+  
+    template<typename T>
+    bool add(T& object, const std::string& name);
+    template<typename T>
+    bool add(T& object, const std::string& name, T defaultValue);
+    bool addObjectToGroup(XMLSerializable* object, const std::string& group);  
+    bool addObjectToGroup(XMLSerializable* object, std::map<std::string,XMLSerializerGroup*>::iterator it);
+    std::map<std::string,XMLSerializerGroup*>::iterator setGetGroup(const std::string& group);
+    tinyxml2::XMLDocument* openDoc(const char* filename);
+    tinyxml2::XMLElement* findAddGroup(tinyxml2::XMLDocument* doc, const char* groupName);
+  };
+  
+  /**
+     * class XMLSerializerTest
+     * Used to test the functionality of the library and also shows howto use it.
+     */
+  class XMLSerializerTest : public igl::XMLSerialization
+  {
+  public:
+
+    int testInt;
+    std::vector<float> testVector;
+
+    XMLSerializerTest();
+
+    bool Test();
+  };
+}
+
+#ifdef IGL_HEADER_ONLY
+#include "XMLSerializer.cpp"
+#endif
+
+#endif

+ 2099 - 0
include/igl/xml/tinyxml2.cpp

@@ -0,0 +1,2099 @@
+/*
+Original code by Lee Thomason (www.grinninglizard.com)
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any
+damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any
+purpose, including commercial applications, and to alter it and
+redistribute it freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must
+not claim that you wrote the original software. If you use this
+software in a product, an acknowledgment in the product documentation
+would be appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and
+must not be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source
+distribution.
+*/
+
+#include "tinyxml2.h"
+
+#include <new>		// yes, this one new style header, is in the Android SDK.
+#   ifdef ANDROID_NDK
+#   include <stddef.h>
+#else
+#   include <cstddef>
+#endif
+
+static const char LINE_FEED				= (char)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 CR = CARRIAGE_RETURN;
+static const char SINGLE_QUOTE			= '\'';
+static const char DOUBLE_QUOTE			= '\"';
+
+// Bunch of unicode info at:
+//		http://www.unicode.org/faq/utf_bom.html
+//	ef bb bf (Microsoft "lead bytes") - designates UTF-8
+
+static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
+static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
+static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
+
+
+#define DELETE_NODE( node )	{			\
+        if ( node ) {						\
+            MemPool* pool = node->_memPool;	\
+            node->~XMLNode();				\
+            pool->Free( node );				\
+        }									\
+    }
+#define DELETE_ATTRIBUTE( attrib ) {		\
+        if ( attrib ) {							\
+            MemPool* pool = attrib->_memPool;	\
+            attrib->~XMLAttribute();			\
+            pool->Free( attrib );				\
+        }										\
+    }
+
+namespace tinyxml2
+{
+
+struct Entity {
+    const char* pattern;
+    int length;
+    char value;
+};
+
+static const int NUM_ENTITIES = 5;
+static const Entity entities[NUM_ENTITIES] = {
+    { "quot", 4,	DOUBLE_QUOTE },
+    { "amp", 3,		'&'  },
+    { "apos", 4,	SINGLE_QUOTE },
+    { "lt",	2, 		'<'	 },
+    { "gt",	2,		'>'	 }
+};
+
+
+StrPair::~StrPair()
+{
+    Reset();
+}
+
+
+void StrPair::Reset()
+{
+    if ( _flags & NEEDS_DELETE ) {
+        delete [] _start;
+    }
+    _flags = 0;
+    _start = 0;
+    _end = 0;
+}
+
+
+void StrPair::SetStr( const char* str, int flags )
+{
+    Reset();
+    size_t len = strlen( str );
+    _start = new char[ len+1 ];
+    memcpy( _start, str, len+1 );
+    _end = _start + len;
+    _flags = flags | NEEDS_DELETE;
+}
+
+
+char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
+{
+    TIXMLASSERT( endTag && *endTag );
+
+    char* start = p;	// fixme: hides a member
+    char  endChar = *endTag;
+    size_t length = strlen( endTag );
+
+    // Inner loop of text parsing.
+    while ( *p ) {
+        if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
+            Set( start, p, strFlags );
+            return p + length;
+        }
+        ++p;
+    }
+    return 0;
+}
+
+
+char* StrPair::ParseName( char* p )
+{
+    char* start = p;
+
+    if ( !start || !(*start) ) {
+        return 0;
+    }
+
+    while( *p && ( p == start ? XMLUtil::IsNameStartChar( *p ) : XMLUtil::IsNameChar( *p ) )) {
+        ++p;
+    }
+
+    if ( p > start ) {
+        Set( start, p, 0 );
+        return p;
+    }
+    return 0;
+}
+
+
+void StrPair::CollapseWhitespace()
+{
+    // Trim leading space.
+    _start = XMLUtil::SkipWhiteSpace( _start );
+
+    if ( _start && *_start ) {
+        char* p = _start;	// the read pointer
+        char* q = _start;	// the write pointer
+
+        while( *p ) {
+            if ( XMLUtil::IsWhiteSpace( *p )) {
+                p = XMLUtil::SkipWhiteSpace( p );
+                if ( *p == 0 ) {
+                    break;    // don't write to q; this trims the trailing space.
+                }
+                *q = ' ';
+                ++q;
+            }
+            *q = *p;
+            ++q;
+            ++p;
+        }
+        *q = 0;
+    }
+}
+
+
+const char* StrPair::GetStr()
+{
+    if ( _flags & NEEDS_FLUSH ) {
+        *_end = 0;
+        _flags ^= NEEDS_FLUSH;
+
+        if ( _flags ) {
+            char* p = _start;	// the read pointer
+            char* q = _start;	// the write pointer
+
+            while( p < _end ) {
+                if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
+                    // CR-LF pair becomes LF
+                    // CR alone becomes LF
+                    // LF-CR becomes LF
+                    if ( *(p+1) == LF ) {
+                        p += 2;
+                    }
+                    else {
+                        ++p;
+                    }
+                    *q++ = LF;
+                }
+                else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
+                    if ( *(p+1) == CR ) {
+                        p += 2;
+                    }
+                    else {
+                        ++p;
+                    }
+                    *q++ = LF;
+                }
+                else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
+                    // Entities handled by tinyXML2:
+                    // - special entities in the entity table [in/out]
+                    // - numeric character reference [in]
+                    //   &#20013; or &#x4e2d;
+
+                    if ( *(p+1) == '#' ) {
+                        char buf[10] = { 0 };
+                        int len;
+                        p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
+                        for( int i=0; i<len; ++i ) {
+                            *q++ = buf[i];
+                        }
+                        TIXMLASSERT( q <= p );
+                    }
+                    else {
+                        int i=0;
+                        for(; i<NUM_ENTITIES; ++i ) {
+                            if (    strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
+                                    && *(p+entities[i].length+1) == ';' ) {
+                                // Found an entity convert;
+                                *q = entities[i].value;
+                                ++q;
+                                p += entities[i].length + 2;
+                                break;
+                            }
+                        }
+                        if ( i == NUM_ENTITIES ) {
+                            // fixme: treat as error?
+                            ++p;
+                            ++q;
+                        }
+                    }
+                }
+                else {
+                    *q = *p;
+                    ++p;
+                    ++q;
+                }
+            }
+            *q = 0;
+        }
+        // The loop below has plenty going on, and this
+        // is a less useful mode. Break it out.
+        if ( _flags & COLLAPSE_WHITESPACE ) {
+            CollapseWhitespace();
+        }
+        _flags = (_flags & NEEDS_DELETE);
+    }
+    return _start;
+}
+
+
+
+
+// --------- XMLUtil ----------- //
+
+const char* XMLUtil::ReadBOM( const char* p, bool* bom )
+{
+    *bom = false;
+    const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
+    // Check for BOM:
+    if (    *(pu+0) == TIXML_UTF_LEAD_0
+            && *(pu+1) == TIXML_UTF_LEAD_1
+            && *(pu+2) == TIXML_UTF_LEAD_2 ) {
+        *bom = true;
+        p += 3;
+    }
+    return p;
+}
+
+
+void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
+{
+    const unsigned long BYTE_MASK = 0xBF;
+    const unsigned long BYTE_MARK = 0x80;
+    const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+
+    if (input < 0x80) {
+        *length = 1;
+    }
+    else if ( input < 0x800 ) {
+        *length = 2;
+    }
+    else if ( input < 0x10000 ) {
+        *length = 3;
+    }
+    else if ( input < 0x200000 ) {
+        *length = 4;
+    }
+    else {
+        *length = 0;    // This code won't covert this correctly anyway.
+        return;
+    }
+
+    output += *length;
+
+    // Scary scary fall throughs.
+    switch (*length) {
+        case 4:
+            --output;
+            *output = (char)((input | BYTE_MARK) & BYTE_MASK);
+            input >>= 6;
+        case 3:
+            --output;
+            *output = (char)((input | BYTE_MARK) & BYTE_MASK);
+            input >>= 6;
+        case 2:
+            --output;
+            *output = (char)((input | BYTE_MARK) & BYTE_MASK);
+            input >>= 6;
+        case 1:
+            --output;
+            *output = (char)(input | FIRST_BYTE_MARK[*length]);
+        default:
+            break;
+    }
+}
+
+
+const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
+{
+    // Presume an entity, and pull it out.
+    *length = 0;
+
+    if ( *(p+1) == '#' && *(p+2) ) {
+        unsigned long ucs = 0;
+        ptrdiff_t delta = 0;
+        unsigned mult = 1;
+
+        if ( *(p+2) == 'x' ) {
+            // Hexadecimal.
+            if ( !*(p+3) ) {
+                return 0;
+            }
+
+            const char* q = p+3;
+            q = strchr( q, ';' );
+
+            if ( !q || !*q ) {
+                return 0;
+            }
+
+            delta = q-p;
+            --q;
+
+            while ( *q != 'x' ) {
+                if ( *q >= '0' && *q <= '9' ) {
+                    ucs += mult * (*q - '0');
+                }
+                else if ( *q >= 'a' && *q <= 'f' ) {
+                    ucs += mult * (*q - 'a' + 10);
+                }
+                else if ( *q >= 'A' && *q <= 'F' ) {
+                    ucs += mult * (*q - 'A' + 10 );
+                }
+                else {
+                    return 0;
+                }
+                mult *= 16;
+                --q;
+            }
+        }
+        else {
+            // Decimal.
+            if ( !*(p+2) ) {
+                return 0;
+            }
+
+            const char* q = p+2;
+            q = strchr( q, ';' );
+
+            if ( !q || !*q ) {
+                return 0;
+            }
+
+            delta = q-p;
+            --q;
+
+            while ( *q != '#' ) {
+                if ( *q >= '0' && *q <= '9' ) {
+                    ucs += mult * (*q - '0');
+                }
+                else {
+                    return 0;
+                }
+                mult *= 10;
+                --q;
+            }
+        }
+        // convert the UCS to UTF-8
+        ConvertUTF32ToUTF8( ucs, value, length );
+        return p + delta + 1;
+    }
+    return p+1;
+}
+
+
+void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
+{
+    TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
+}
+
+
+void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
+{
+    TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
+}
+
+
+void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
+{
+    TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
+}
+
+
+void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
+{
+    TIXML_SNPRINTF( buffer, bufferSize, "%f", v );
+}
+
+
+void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
+{
+    TIXML_SNPRINTF( buffer, bufferSize, "%.15f", v );
+}
+
+
+bool XMLUtil::ToInt( const char* str, int* value )
+{
+    if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
+        return true;
+    }
+    return false;
+}
+
+bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
+{
+    if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
+        return true;
+    }
+    return false;
+}
+
+bool XMLUtil::ToBool( const char* str, bool* value )
+{
+    int ival = 0;
+    if ( ToInt( str, &ival )) {
+        *value = (ival==0) ? false : true;
+        return true;
+    }
+    if ( StringEqual( str, "true" ) ) {
+        *value = true;
+        return true;
+    }
+    else if ( StringEqual( str, "false" ) ) {
+        *value = false;
+        return true;
+    }
+    return false;
+}
+
+
+bool XMLUtil::ToFloat( const char* str, float* value )
+{
+    if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
+        return true;
+    }
+    return false;
+}
+
+bool XMLUtil::ToDouble( const char* str, double* value )
+{
+    if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
+        return true;
+    }
+    return false;
+}
+
+
+char* XMLDocument::Identify( char* p, XMLNode** node )
+{
+    XMLNode* returnNode = 0;
+    char* start = p;
+    p = XMLUtil::SkipWhiteSpace( p );
+    if( !p || !*p ) {
+        return p;
+    }
+
+    // What is this thing?
+    // - Elements start with a letter or underscore, but xml is reserved.
+    // - Comments: <!--
+    // - Declaration: <?
+    // - Everything else is unknown to tinyxml.
+    //
+
+    static const char* xmlHeader		= { "<?" };
+    static const char* commentHeader	= { "<!--" };
+    static const char* dtdHeader		= { "<!" };
+    static const char* cdataHeader		= { "<![CDATA[" };
+    static const char* elementHeader	= { "<" };	// and a header for everything else; check last.
+
+    static const int xmlHeaderLen		= 2;
+    static const int commentHeaderLen	= 4;
+    static const int dtdHeaderLen		= 2;
+    static const int cdataHeaderLen		= 9;
+    static const int elementHeaderLen	= 1;
+
+#if defined(_MSC_VER)
+#pragma warning ( push )
+#pragma warning ( disable : 4127 )
+#endif
+    TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) );		// use same memory pool
+    TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) );	// use same memory pool
+#if defined(_MSC_VER)
+#pragma warning (pop)
+#endif
+    if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
+        returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
+        returnNode->_memPool = &_commentPool;
+        p += xmlHeaderLen;
+    }
+    else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
+        returnNode = new (_commentPool.Alloc()) XMLComment( this );
+        returnNode->_memPool = &_commentPool;
+        p += commentHeaderLen;
+    }
+    else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
+        XMLText* text = new (_textPool.Alloc()) XMLText( this );
+        returnNode = text;
+        returnNode->_memPool = &_textPool;
+        p += cdataHeaderLen;
+        text->SetCData( true );
+    }
+    else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
+        returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
+        returnNode->_memPool = &_commentPool;
+        p += dtdHeaderLen;
+    }
+    else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
+        returnNode = new (_elementPool.Alloc()) XMLElement( this );
+        returnNode->_memPool = &_elementPool;
+        p += elementHeaderLen;
+    }
+    else {
+        returnNode = new (_textPool.Alloc()) XMLText( this );
+        returnNode->_memPool = &_textPool;
+        p = start;	// Back it up, all the text counts.
+    }
+
+    *node = returnNode;
+    return p;
+}
+
+
+bool XMLDocument::Accept( XMLVisitor* visitor ) const
+{
+    if ( visitor->VisitEnter( *this ) ) {
+        for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
+            if ( !node->Accept( visitor ) ) {
+                break;
+            }
+        }
+    }
+    return visitor->VisitExit( *this );
+}
+
+
+// --------- XMLNode ----------- //
+
+XMLNode::XMLNode( XMLDocument* doc ) :
+    _document( doc ),
+    _parent( 0 ),
+    _firstChild( 0 ), _lastChild( 0 ),
+    _prev( 0 ), _next( 0 ),
+    _memPool( 0 )
+{
+}
+
+
+XMLNode::~XMLNode()
+{
+    DeleteChildren();
+    if ( _parent ) {
+        _parent->Unlink( this );
+    }
+}
+
+
+void XMLNode::SetValue( const char* str, bool staticMem )
+{
+    if ( staticMem ) {
+        _value.SetInternedStr( str );
+    }
+    else {
+        _value.SetStr( str );
+    }
+}
+
+
+void XMLNode::DeleteChildren()
+{
+    while( _firstChild ) {
+        XMLNode* node = _firstChild;
+        Unlink( node );
+
+        DELETE_NODE( node );
+    }
+    _firstChild = _lastChild = 0;
+}
+
+
+void XMLNode::Unlink( XMLNode* child )
+{
+    TIXMLASSERT( child->_parent == this );
+    if ( child == _firstChild ) {
+        _firstChild = _firstChild->_next;
+    }
+    if ( child == _lastChild ) {
+        _lastChild = _lastChild->_prev;
+    }
+
+    if ( child->_prev ) {
+        child->_prev->_next = child->_next;
+    }
+    if ( child->_next ) {
+        child->_next->_prev = child->_prev;
+    }
+    child->_parent = 0;
+}
+
+
+void XMLNode::DeleteChild( XMLNode* node )
+{
+    TIXMLASSERT( node->_parent == this );
+    DELETE_NODE( node );
+}
+
+
+XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
+{
+    if ( _lastChild ) {
+        TIXMLASSERT( _firstChild );
+        TIXMLASSERT( _lastChild->_next == 0 );
+        _lastChild->_next = addThis;
+        addThis->_prev = _lastChild;
+        _lastChild = addThis;
+
+        addThis->_next = 0;
+    }
+    else {
+        TIXMLASSERT( _firstChild == 0 );
+        _firstChild = _lastChild = addThis;
+
+        addThis->_prev = 0;
+        addThis->_next = 0;
+    }
+    addThis->_parent = this;
+    addThis->_memPool->SetTracked();
+    return addThis;
+}
+
+
+XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
+{
+    if ( _firstChild ) {
+        TIXMLASSERT( _lastChild );
+        TIXMLASSERT( _firstChild->_prev == 0 );
+
+        _firstChild->_prev = addThis;
+        addThis->_next = _firstChild;
+        _firstChild = addThis;
+
+        addThis->_prev = 0;
+    }
+    else {
+        TIXMLASSERT( _lastChild == 0 );
+        _firstChild = _lastChild = addThis;
+
+        addThis->_prev = 0;
+        addThis->_next = 0;
+    }
+    addThis->_parent = this;
+    addThis->_memPool->SetTracked();
+    return addThis;
+}
+
+
+XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
+{
+    TIXMLASSERT( afterThis->_parent == this );
+    if ( afterThis->_parent != this ) {
+        return 0;
+    }
+
+    if ( afterThis->_next == 0 ) {
+        // The last node or the only node.
+        return InsertEndChild( addThis );
+    }
+    addThis->_prev = afterThis;
+    addThis->_next = afterThis->_next;
+    afterThis->_next->_prev = addThis;
+    afterThis->_next = addThis;
+    addThis->_parent = this;
+    addThis->_memPool->SetTracked();
+    return addThis;
+}
+
+
+
+
+const XMLElement* XMLNode::FirstChildElement( const char* value ) const
+{
+    for( XMLNode* node=_firstChild; node; node=node->_next ) {
+        XMLElement* element = node->ToElement();
+        if ( element ) {
+            if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
+                return element;
+            }
+        }
+    }
+    return 0;
+}
+
+
+const XMLElement* XMLNode::LastChildElement( const char* value ) const
+{
+    for( XMLNode* node=_lastChild; node; node=node->_prev ) {
+        XMLElement* element = node->ToElement();
+        if ( element ) {
+            if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
+                return element;
+            }
+        }
+    }
+    return 0;
+}
+
+
+const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
+{
+    for( XMLNode* element=this->_next; element; element = element->_next ) {
+        if (    element->ToElement()
+                && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
+            return element->ToElement();
+        }
+    }
+    return 0;
+}
+
+
+const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
+{
+    for( XMLNode* element=_prev; element; element = element->_prev ) {
+        if (    element->ToElement()
+                && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
+            return element->ToElement();
+        }
+    }
+    return 0;
+}
+
+
+char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
+{
+    // This is a recursive method, but thinking about it "at the current level"
+    // it is a pretty simple flat list:
+    //		<foo/>
+    //		<!-- comment -->
+    //
+    // With a special case:
+    //		<foo>
+    //		</foo>
+    //		<!-- comment -->
+    //
+    // Where the closing element (/foo) *must* be the next thing after the opening
+    // element, and the names must match. BUT the tricky bit is that the closing
+    // element will be read by the child.
+    //
+    // '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 ) {
+        XMLNode* node = 0;
+
+        p = _document->Identify( p, &node );
+        if ( p == 0 || node == 0 ) {
+            break;
+        }
+
+        StrPair endTag;
+        p = node->ParseDeep( p, &endTag );
+        if ( !p ) {
+            DELETE_NODE( node );
+            node = 0;
+            if ( !_document->Error() ) {
+                _document->SetError( XML_ERROR_PARSING, 0, 0 );
+            }
+            break;
+        }
+
+        // We read the end tag. Return it to the parent.
+        if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
+            if ( parentEnd ) {
+                *parentEnd = static_cast<XMLElement*>(node)->_value;
+            }
+			node->_memPool->SetTracked();	// created and then immediately deleted.
+            DELETE_NODE( node );
+            return p;
+        }
+
+        // Handle an end tag returned to this level.
+        // And handle a bunch of annoying errors.
+        XMLElement* ele = node->ToElement();
+        if ( ele ) {
+            if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
+                _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
+                p = 0;
+            }
+            else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
+                _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
+                p = 0;
+            }
+            else if ( !endTag.Empty() ) {
+                if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
+                    _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
+                    p = 0;
+                }
+            }
+        }
+        if ( p == 0 ) {
+            DELETE_NODE( node );
+            node = 0;
+        }
+        if ( node ) {
+            this->InsertEndChild( node );
+        }
+    }
+    return 0;
+}
+
+// --------- XMLText ---------- //
+char* XMLText::ParseDeep( char* p, StrPair* )
+{
+    const char* start = p;
+    if ( this->CData() ) {
+        p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
+        if ( !p ) {
+            _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
+        }
+        return p;
+    }
+    else {
+        int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
+        if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
+            flags |= StrPair::COLLAPSE_WHITESPACE;
+        }
+
+        p = _value.ParseText( p, "<", flags );
+        if ( !p ) {
+            _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
+        }
+        if ( p && *p ) {
+            return p-1;
+        }
+    }
+    return 0;
+}
+
+
+XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
+{
+    if ( !doc ) {
+        doc = _document;
+    }
+    XMLText* text = doc->NewText( Value() );	// fixme: this will always allocate memory. Intern?
+    text->SetCData( this->CData() );
+    return text;
+}
+
+
+bool XMLText::ShallowEqual( const XMLNode* compare ) const
+{
+    return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
+}
+
+
+bool XMLText::Accept( XMLVisitor* visitor ) const
+{
+    return visitor->Visit( *this );
+}
+
+
+// --------- XMLComment ---------- //
+
+XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
+{
+}
+
+
+XMLComment::~XMLComment()
+{
+}
+
+
+char* XMLComment::ParseDeep( char* p, StrPair* )
+{
+    // Comment parses as text.
+    const char* start = p;
+    p = _value.ParseText( p, "-->", StrPair::COMMENT );
+    if ( p == 0 ) {
+        _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
+    }
+    return p;
+}
+
+
+XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
+{
+    if ( !doc ) {
+        doc = _document;
+    }
+    XMLComment* comment = doc->NewComment( Value() );	// fixme: this will always allocate memory. Intern?
+    return comment;
+}
+
+
+bool XMLComment::ShallowEqual( const XMLNode* compare ) const
+{
+    return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() ));
+}
+
+
+bool XMLComment::Accept( XMLVisitor* visitor ) const
+{
+    return visitor->Visit( *this );
+}
+
+
+// --------- XMLDeclaration ---------- //
+
+XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
+{
+}
+
+
+XMLDeclaration::~XMLDeclaration()
+{
+    //printf( "~XMLDeclaration\n" );
+}
+
+
+char* XMLDeclaration::ParseDeep( char* p, StrPair* )
+{
+    // Declaration parses as text.
+    const char* start = p;
+    p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
+    if ( p == 0 ) {
+        _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
+    }
+    return p;
+}
+
+
+XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
+{
+    if ( !doc ) {
+        doc = _document;
+    }
+    XMLDeclaration* dec = doc->NewDeclaration( Value() );	// fixme: this will always allocate memory. Intern?
+    return dec;
+}
+
+
+bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
+{
+    return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() ));
+}
+
+
+
+bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
+{
+    return visitor->Visit( *this );
+}
+
+// --------- XMLUnknown ---------- //
+
+XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
+{
+}
+
+
+XMLUnknown::~XMLUnknown()
+{
+}
+
+
+char* XMLUnknown::ParseDeep( char* p, StrPair* )
+{
+    // Unknown parses as text.
+    const char* start = p;
+
+    p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
+    if ( !p ) {
+        _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
+    }
+    return p;
+}
+
+
+XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
+{
+    if ( !doc ) {
+        doc = _document;
+    }
+    XMLUnknown* text = doc->NewUnknown( Value() );	// fixme: this will always allocate memory. Intern?
+    return text;
+}
+
+
+bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
+{
+    return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() ));
+}
+
+
+bool XMLUnknown::Accept( XMLVisitor* visitor ) const
+{
+    return visitor->Visit( *this );
+}
+
+// --------- XMLAttribute ---------- //
+char* XMLAttribute::ParseDeep( char* p, bool processEntities )
+{
+    // Parse using the name rules: bug fix, was using ParseText before
+    p = _name.ParseName( p );
+    if ( !p || !*p ) {
+        return 0;
+    }
+
+    // Skip white space before =
+    p = XMLUtil::SkipWhiteSpace( p );
+    if ( !p || *p != '=' ) {
+        return 0;
+    }
+
+    ++p;	// move up to opening quote
+    p = XMLUtil::SkipWhiteSpace( p );
+    if ( *p != '\"' && *p != '\'' ) {
+        return 0;
+    }
+
+    char endTag[2] = { *p, 0 };
+    ++p;	// move past opening quote
+
+    p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
+    return p;
+}
+
+
+void XMLAttribute::SetName( const char* n )
+{
+    _name.SetStr( n );
+}
+
+
+XMLError XMLAttribute::QueryIntValue( int* value ) const
+{
+    if ( XMLUtil::ToInt( Value(), value )) {
+        return XML_NO_ERROR;
+    }
+    return XML_WRONG_ATTRIBUTE_TYPE;
+}
+
+
+XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
+{
+    if ( XMLUtil::ToUnsigned( Value(), value )) {
+        return XML_NO_ERROR;
+    }
+    return XML_WRONG_ATTRIBUTE_TYPE;
+}
+
+
+XMLError XMLAttribute::QueryBoolValue( bool* value ) const
+{
+    if ( XMLUtil::ToBool( Value(), value )) {
+        return XML_NO_ERROR;
+    }
+    return XML_WRONG_ATTRIBUTE_TYPE;
+}
+
+
+XMLError XMLAttribute::QueryFloatValue( float* value ) const
+{
+    if ( XMLUtil::ToFloat( Value(), value )) {
+        return XML_NO_ERROR;
+    }
+    return XML_WRONG_ATTRIBUTE_TYPE;
+}
+
+
+XMLError XMLAttribute::QueryDoubleValue( double* value ) const
+{
+    if ( XMLUtil::ToDouble( Value(), value )) {
+        return XML_NO_ERROR;
+    }
+    return XML_WRONG_ATTRIBUTE_TYPE;
+}
+
+
+void XMLAttribute::SetAttribute( const char* v )
+{
+    _value.SetStr( v );
+}
+
+
+void XMLAttribute::SetAttribute( int v )
+{
+    char buf[BUF_SIZE];
+    XMLUtil::ToStr( v, buf, BUF_SIZE );
+    _value.SetStr( buf );
+}
+
+
+void XMLAttribute::SetAttribute( unsigned v )
+{
+    char buf[BUF_SIZE];
+    XMLUtil::ToStr( v, buf, BUF_SIZE );
+    _value.SetStr( buf );
+}
+
+
+void XMLAttribute::SetAttribute( bool v )
+{
+    char buf[BUF_SIZE];
+    XMLUtil::ToStr( v, buf, BUF_SIZE );
+    _value.SetStr( buf );
+}
+
+void XMLAttribute::SetAttribute( double v )
+{
+    char buf[BUF_SIZE];
+    XMLUtil::ToStr( v, buf, BUF_SIZE );
+    _value.SetStr( buf );
+}
+
+void XMLAttribute::SetAttribute( float v )
+{
+    char buf[BUF_SIZE];
+    XMLUtil::ToStr( v, buf, BUF_SIZE );
+    _value.SetStr( buf );
+}
+
+
+// --------- XMLElement ---------- //
+XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
+    _closingType( 0 ),
+    _rootAttribute( 0 )
+{
+}
+
+
+XMLElement::~XMLElement()
+{
+    while( _rootAttribute ) {
+        XMLAttribute* next = _rootAttribute->_next;
+        DELETE_ATTRIBUTE( _rootAttribute );
+        _rootAttribute = next;
+    }
+}
+
+
+XMLAttribute* XMLElement::FindAttribute( const char* name )
+{
+    XMLAttribute* a = 0;
+    for( a=_rootAttribute; a; a = a->_next ) {
+        if ( XMLUtil::StringEqual( a->Name(), name ) ) {
+            return a;
+        }
+    }
+    return 0;
+}
+
+
+const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
+{
+    XMLAttribute* a = 0;
+    for( a=_rootAttribute; a; a = a->_next ) {
+        if ( XMLUtil::StringEqual( a->Name(), name ) ) {
+            return a;
+        }
+    }
+    return 0;
+}
+
+
+const char* XMLElement::Attribute( const char* name, const char* value ) const
+{
+    const XMLAttribute* a = FindAttribute( name );
+    if ( !a ) {
+        return 0;
+    }
+    if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
+        return a->Value();
+    }
+    return 0;
+}
+
+
+const char* XMLElement::GetText() const
+{
+    if ( FirstChild() && FirstChild()->ToText() ) {
+        return FirstChild()->ToText()->Value();
+    }
+    return 0;
+}
+
+
+XMLError XMLElement::QueryIntText( int* ival ) const
+{
+    if ( FirstChild() && FirstChild()->ToText() ) {
+        const char* t = FirstChild()->ToText()->Value();
+        if ( XMLUtil::ToInt( t, ival ) ) {
+            return XML_SUCCESS;
+        }
+        return XML_CAN_NOT_CONVERT_TEXT;
+    }
+    return XML_NO_TEXT_NODE;
+}
+
+
+XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
+{
+    if ( FirstChild() && FirstChild()->ToText() ) {
+        const char* t = FirstChild()->ToText()->Value();
+        if ( XMLUtil::ToUnsigned( 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() ) {
+        const char* t = FirstChild()->ToText()->Value();
+        if ( XMLUtil::ToBool( t, bval ) ) {
+            return XML_SUCCESS;
+        }
+        return XML_CAN_NOT_CONVERT_TEXT;
+    }
+    return XML_NO_TEXT_NODE;
+}
+
+
+XMLError XMLElement::QueryDoubleText( double* dval ) const
+{
+    if ( FirstChild() && FirstChild()->ToText() ) {
+        const char* t = FirstChild()->ToText()->Value();
+        if ( XMLUtil::ToDouble( t, dval ) ) {
+            return XML_SUCCESS;
+        }
+        return XML_CAN_NOT_CONVERT_TEXT;
+    }
+    return XML_NO_TEXT_NODE;
+}
+
+
+XMLError XMLElement::QueryFloatText( float* fval ) const
+{
+    if ( FirstChild() && FirstChild()->ToText() ) {
+        const char* t = FirstChild()->ToText()->Value();
+        if ( XMLUtil::ToFloat( t, fval ) ) {
+            return XML_SUCCESS;
+        }
+        return XML_CAN_NOT_CONVERT_TEXT;
+    }
+    return XML_NO_TEXT_NODE;
+}
+
+
+
+XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
+{
+    XMLAttribute* last = 0;
+    XMLAttribute* attrib = 0;
+    for( attrib = _rootAttribute;
+            attrib;
+            last = attrib, attrib = attrib->_next ) {
+        if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
+            break;
+        }
+    }
+    if ( !attrib ) {
+        attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
+        attrib->_memPool = &_document->_attributePool;
+        if ( last ) {
+            last->_next = attrib;
+        }
+        else {
+            _rootAttribute = attrib;
+        }
+        attrib->SetName( name );
+        attrib->_memPool->SetTracked(); // always created and linked.
+    }
+    return attrib;
+}
+
+
+void XMLElement::DeleteAttribute( const char* name )
+{
+    XMLAttribute* prev = 0;
+    for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
+        if ( XMLUtil::StringEqual( name, a->Name() ) ) {
+            if ( prev ) {
+                prev->_next = a->_next;
+            }
+            else {
+                _rootAttribute = a->_next;
+            }
+            DELETE_ATTRIBUTE( a );
+            break;
+        }
+        prev = a;
+    }
+}
+
+
+char* XMLElement::ParseAttributes( char* p )
+{
+    const char* start = p;
+    XMLAttribute* prevAttribute = 0;
+
+    // Read the attributes.
+    while( p ) {
+        p = XMLUtil::SkipWhiteSpace( p );
+        if ( !p || !(*p) ) {
+            _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
+            return 0;
+        }
+
+        // attribute.
+        if (XMLUtil::IsNameStartChar( *p ) ) {
+            XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
+            attrib->_memPool = &_document->_attributePool;
+			attrib->_memPool->SetTracked();
+
+            p = attrib->ParseDeep( p, _document->ProcessEntities() );
+            if ( !p || Attribute( attrib->Name() ) ) {
+                DELETE_ATTRIBUTE( attrib );
+                _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
+                return 0;
+            }
+            // There is a minor bug here: if the attribute in the source xml
+            // document is duplicated, it will not be detected and the
+            // attribute will be doubly added. However, tracking the 'prevAttribute'
+            // avoids re-scanning the attribute list. Preferring performance for
+            // now, may reconsider in the future.
+            if ( prevAttribute ) {
+                prevAttribute->_next = attrib;
+            }
+            else {
+                _rootAttribute = attrib;
+            }
+            prevAttribute = attrib;
+        }
+        // end of the tag
+        else if ( *p == '/' && *(p+1) == '>' ) {
+            _closingType = CLOSED;
+            return p+2;	// done; sealed element.
+        }
+        // end of the tag
+        else if ( *p == '>' ) {
+            ++p;
+            break;
+        }
+        else {
+            _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
+            return 0;
+        }
+    }
+    return p;
+}
+
+
+//
+//	<ele></ele>
+//	<ele>foo<b>bar</b></ele>
+//
+char* XMLElement::ParseDeep( char* p, StrPair* strPair )
+{
+    // Read the element name.
+    p = XMLUtil::SkipWhiteSpace( p );
+    if ( !p ) {
+        return 0;
+    }
+
+    // The closing element is the </element> form. It is
+    // parsed just like a regular element then deleted from
+    // the DOM.
+    if ( *p == '/' ) {
+        _closingType = CLOSING;
+        ++p;
+    }
+
+    p = _value.ParseName( p );
+    if ( _value.Empty() ) {
+        return 0;
+    }
+
+    p = ParseAttributes( p );
+    if ( !p || !*p || _closingType ) {
+        return p;
+    }
+
+    p = XMLNode::ParseDeep( p, strPair );
+    return p;
+}
+
+
+
+XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
+{
+    if ( !doc ) {
+        doc = _document;
+    }
+    XMLElement* element = doc->NewElement( Value() );					// fixme: this will always allocate memory. Intern?
+    for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
+        element->SetAttribute( a->Name(), a->Value() );					// fixme: this will always allocate memory. Intern?
+    }
+    return element;
+}
+
+
+bool XMLElement::ShallowEqual( const XMLNode* compare ) const
+{
+    const XMLElement* other = compare->ToElement();
+    if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
+
+        const XMLAttribute* a=FirstAttribute();
+        const XMLAttribute* b=other->FirstAttribute();
+
+        while ( a && b ) {
+            if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
+                return false;
+            }
+            a = a->Next();
+            b = b->Next();
+        }
+        if ( a || b ) {
+            // different count
+            return false;
+        }
+        return true;
+    }
+    return false;
+}
+
+
+bool XMLElement::Accept( XMLVisitor* visitor ) const
+{
+    if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
+        for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
+            if ( !node->Accept( visitor ) ) {
+                break;
+            }
+        }
+    }
+    return visitor->VisitExit( *this );
+}
+
+
+// --------- XMLDocument ----------- //
+XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
+    XMLNode( 0 ),
+    _writeBOM( false ),
+    _processEntities( processEntities ),
+    _errorID( XML_NO_ERROR ),
+    _whitespace( whitespace ),
+    _errorStr1( 0 ),
+    _errorStr2( 0 ),
+    _charBuffer( 0 )
+{
+    _document = this;	// avoid warning about 'this' in initializer list
+}
+
+
+XMLDocument::~XMLDocument()
+{
+    DeleteChildren();
+    delete [] _charBuffer;
+
+#if 0
+    _textPool.Trace( "text" );
+    _elementPool.Trace( "element" );
+    _commentPool.Trace( "comment" );
+    _attributePool.Trace( "attribute" );
+#endif
+
+#ifdef DEBUG
+	if ( Error() == false ) {
+		TIXMLASSERT( _elementPool.CurrentAllocs()   == _elementPool.Untracked() );
+		TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
+		TIXMLASSERT( _textPool.CurrentAllocs()      == _textPool.Untracked() );
+		TIXMLASSERT( _commentPool.CurrentAllocs()   == _commentPool.Untracked() );
+	}
+#endif
+}
+
+
+void XMLDocument::Clear()
+{
+    DeleteChildren();
+
+    _errorID = XML_NO_ERROR;
+    _errorStr1 = 0;
+    _errorStr2 = 0;
+
+    delete [] _charBuffer;
+    _charBuffer = 0;
+}
+
+
+XMLElement* XMLDocument::NewElement( const char* name )
+{
+    XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
+    ele->_memPool = &_elementPool;
+    ele->SetName( name );
+    return ele;
+}
+
+
+XMLComment* XMLDocument::NewComment( const char* str )
+{
+    XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
+    comment->_memPool = &_commentPool;
+    comment->SetValue( str );
+    return comment;
+}
+
+
+XMLText* XMLDocument::NewText( const char* str )
+{
+    XMLText* text = new (_textPool.Alloc()) XMLText( this );
+    text->_memPool = &_textPool;
+    text->SetValue( str );
+    return text;
+}
+
+
+XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
+{
+    XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
+    dec->_memPool = &_commentPool;
+    dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
+    return dec;
+}
+
+
+XMLUnknown* XMLDocument::NewUnknown( const char* str )
+{
+    XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
+    unk->_memPool = &_commentPool;
+    unk->SetValue( str );
+    return unk;
+}
+
+
+XMLError XMLDocument::LoadFile( const char* filename )
+{
+    Clear();
+    FILE* fp = 0;
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
+    errno_t err = fopen_s(&fp, filename, "rb" );
+    if ( !fp || err) {
+#else
+    fp = fopen( filename, "rb" );
+    if ( !fp) {
+#endif
+        SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
+        return _errorID;
+    }
+    LoadFile( fp );
+    fclose( fp );
+    return _errorID;
+}
+
+
+XMLError XMLDocument::LoadFile( FILE* fp )
+{
+    Clear();
+
+    fseek( fp, 0, SEEK_END );
+    size_t size = ftell( fp );
+    fseek( fp, 0, SEEK_SET );
+
+    if ( size == 0 ) {
+        SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
+        return _errorID;
+    }
+
+    _charBuffer = new char[size+1];
+    size_t read = fread( _charBuffer, 1, size, fp );
+    if ( read != size ) {
+        SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
+        return _errorID;
+    }
+
+    _charBuffer[size] = 0;
+
+    const char* p = _charBuffer;
+    p = XMLUtil::SkipWhiteSpace( p );
+    p = XMLUtil::ReadBOM( p, &_writeBOM );
+    if ( !p || !*p ) {
+        SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
+        return _errorID;
+    }
+
+    ParseDeep( _charBuffer + (p-_charBuffer), 0 );
+    return _errorID;
+}
+
+
+XMLError XMLDocument::SaveFile( const char* filename, bool compact )
+{
+    FILE* fp = 0;
+#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
+    errno_t err = fopen_s(&fp, filename, "w" );
+    if ( !fp || err) {
+#else
+    fp = fopen( filename, "w" );
+    if ( !fp) {
+#endif
+        SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
+        return _errorID;
+    }
+    SaveFile(fp, compact);
+    fclose( fp );
+    return _errorID;
+}
+
+
+XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
+{
+    XMLPrinter stream( fp, compact );
+    Print( &stream );
+    return _errorID;
+}
+
+
+XMLError XMLDocument::Parse( const char* p, size_t len )
+{
+	const char* start = p;
+    Clear();
+
+    if ( !p || !*p ) {
+        SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
+        return _errorID;
+    }
+    if ( len == (size_t)(-1) ) {
+        len = strlen( p );
+    }
+    _charBuffer = new char[ len+1 ];
+    memcpy( _charBuffer, p, len );
+    _charBuffer[len] = 0;
+
+    p = XMLUtil::SkipWhiteSpace( p );
+    p = XMLUtil::ReadBOM( p, &_writeBOM );
+    if ( !p || !*p ) {
+        SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
+        return _errorID;
+    }
+
+    ptrdiff_t delta = p - start;	// skip initial whitespace, BOM, etc.
+    ParseDeep( _charBuffer+delta, 0 );
+    return _errorID;
+}
+
+
+void XMLDocument::Print( XMLPrinter* streamer )
+{
+    XMLPrinter stdStreamer( stdout );
+    if ( !streamer ) {
+        streamer = &stdStreamer;
+    }
+    Accept( streamer );
+}
+
+
+void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
+{
+    _errorID = error;
+    _errorStr1 = str1;
+    _errorStr2 = str2;
+}
+
+
+void XMLDocument::PrintError() const
+{
+    if ( _errorID ) {
+        static const int LEN = 20;
+        char buf1[LEN] = { 0 };
+        char buf2[LEN] = { 0 };
+
+        if ( _errorStr1 ) {
+            TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
+        }
+        if ( _errorStr2 ) {
+            TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
+        }
+
+        printf( "XMLDocument error id=%d str1=%s str2=%s\n",
+                _errorID, buf1, buf2 );
+    }
+}
+
+
+XMLPrinter::XMLPrinter( FILE* file, bool compact ) :
+    _elementJustOpened( false ),
+    _firstElement( true ),
+    _fp( file ),
+    _depth( 0 ),
+    _textDepth( -1 ),
+    _processEntities( true ),
+    _compactMode( compact )
+{
+    for( int i=0; i<ENTITY_RANGE; ++i ) {
+        _entityFlag[i] = false;
+        _restrictedEntityFlag[i] = false;
+    }
+    for( int i=0; i<NUM_ENTITIES; ++i ) {
+        TIXMLASSERT( entities[i].value < ENTITY_RANGE );
+        if ( entities[i].value < ENTITY_RANGE ) {
+            _entityFlag[ (int)entities[i].value ] = true;
+        }
+    }
+    _restrictedEntityFlag[(int)'&'] = true;
+    _restrictedEntityFlag[(int)'<'] = true;
+    _restrictedEntityFlag[(int)'>'] = true;	// not required, but consistency is nice
+    _buffer.Push( 0 );
+}
+
+
+void XMLPrinter::Print( const char* format, ... )
+{
+    va_list     va;
+    va_start( va, format );
+
+    if ( _fp ) {
+        vfprintf( _fp, format, va );
+    }
+    else {
+        // This seems brutally complex. Haven't figured out a better
+        // way on windows.
+#ifdef _MSC_VER
+        int len = -1;
+        int expand = 1000;
+        while ( len < 0 ) {
+            len = vsnprintf_s( _accumulator.Mem(), _accumulator.Capacity(), _TRUNCATE, format, va );
+            if ( len < 0 ) {
+                expand *= 3/2;
+                _accumulator.PushArr( expand );
+            }
+        }
+        char* p = _buffer.PushArr( len ) - 1;
+        memcpy( p, _accumulator.Mem(), len+1 );
+#else
+        int len = vsnprintf( 0, 0, format, va );
+        // Close out and re-start the va-args
+        va_end( va );
+        va_start( va, format );
+        char* p = _buffer.PushArr( len ) - 1;
+        vsnprintf( p, len+1, format, va );
+#endif
+    }
+    va_end( va );
+}
+
+
+void XMLPrinter::PrintSpace( int depth )
+{
+    for( int i=0; i<depth; ++i ) {
+        Print( "    " );
+    }
+}
+
+
+void XMLPrinter::PrintString( const char* p, bool restricted )
+{
+    // Look for runs of bytes between entities to print.
+    const char* q = p;
+    const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
+
+    if ( _processEntities ) {
+        while ( *q ) {
+            // Remember, char is sometimes signed. (How many times has that bitten me?)
+            if ( *q > 0 && *q < ENTITY_RANGE ) {
+                // Check for entities. If one is found, flush
+                // the stream up until the entity, write the
+                // entity, and keep looking.
+                if ( flag[(unsigned)(*q)] ) {
+                    while ( p < q ) {
+                        Print( "%c", *p );
+                        ++p;
+                    }
+                    for( int i=0; i<NUM_ENTITIES; ++i ) {
+                        if ( entities[i].value == *q ) {
+                            Print( "&%s;", entities[i].pattern );
+                            break;
+                        }
+                    }
+                    ++p;
+                }
+            }
+            ++q;
+        }
+    }
+    // Flush the remaining string. This will be the entire
+    // string if an entity wasn't found.
+    if ( !_processEntities || (q-p > 0) ) {
+        Print( "%s", p );
+    }
+}
+
+
+void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
+{
+    static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
+    if ( writeBOM ) {
+        Print( "%s", bom );
+    }
+    if ( writeDec ) {
+        PushDeclaration( "xml version=\"1.0\"" );
+    }
+}
+
+
+void XMLPrinter::OpenElement( const char* name )
+{
+    if ( _elementJustOpened ) {
+        SealElement();
+    }
+    _stack.Push( name );
+
+    if ( _textDepth < 0 && !_firstElement && !_compactMode ) {
+        Print( "\n" );
+        PrintSpace( _depth );
+    }
+
+    Print( "<%s", name );
+    _elementJustOpened = true;
+    _firstElement = false;
+    ++_depth;
+}
+
+
+void XMLPrinter::PushAttribute( const char* name, const char* value )
+{
+    TIXMLASSERT( _elementJustOpened );
+    Print( " %s=\"", name );
+    PrintString( value, false );
+    Print( "\"" );
+}
+
+
+void XMLPrinter::PushAttribute( const char* name, int v )
+{
+    char buf[BUF_SIZE];
+    XMLUtil::ToStr( v, buf, BUF_SIZE );
+    PushAttribute( name, buf );
+}
+
+
+void XMLPrinter::PushAttribute( const char* name, unsigned 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];
+    XMLUtil::ToStr( v, buf, BUF_SIZE );
+    PushAttribute( name, buf );
+}
+
+
+void XMLPrinter::PushAttribute( const char* name, double v )
+{
+    char buf[BUF_SIZE];
+    XMLUtil::ToStr( v, buf, BUF_SIZE );
+    PushAttribute( name, buf );
+}
+
+
+void XMLPrinter::CloseElement()
+{
+    --_depth;
+    const char* name = _stack.Pop();
+
+    if ( _elementJustOpened ) {
+        Print( "/>" );
+    }
+    else {
+        if ( _textDepth < 0 && !_compactMode) {
+            Print( "\n" );
+            PrintSpace( _depth );
+        }
+        Print( "</%s>", name );
+    }
+
+    if ( _textDepth == _depth ) {
+        _textDepth = -1;
+    }
+    if ( _depth == 0 && !_compactMode) {
+        Print( "\n" );
+    }
+    _elementJustOpened = false;
+}
+
+
+void XMLPrinter::SealElement()
+{
+    _elementJustOpened = false;
+    Print( ">" );
+}
+
+
+void XMLPrinter::PushText( const char* text, bool cdata )
+{
+    _textDepth = _depth-1;
+
+    if ( _elementJustOpened ) {
+        SealElement();
+    }
+    if ( cdata ) {
+        Print( "<![CDATA[" );
+        Print( "%s", text );
+        Print( "]]>" );
+    }
+    else {
+        PrintString( text, true );
+    }
+}
+
+void XMLPrinter::PushText( int value )
+{
+    char buf[BUF_SIZE];
+    XMLUtil::ToStr( value, buf, BUF_SIZE );
+    PushText( buf, false );
+}
+
+
+void XMLPrinter::PushText( unsigned value )
+{
+    char buf[BUF_SIZE];
+    XMLUtil::ToStr( value, buf, BUF_SIZE );
+    PushText( buf, false );
+}
+
+
+void XMLPrinter::PushText( bool value )
+{
+    char buf[BUF_SIZE];
+    XMLUtil::ToStr( value, buf, BUF_SIZE );
+    PushText( buf, false );
+}
+
+
+void XMLPrinter::PushText( float value )
+{
+    char buf[BUF_SIZE];
+    XMLUtil::ToStr( value, buf, BUF_SIZE );
+    PushText( buf, false );
+}
+
+
+void XMLPrinter::PushText( double value )
+{
+    char buf[BUF_SIZE];
+    XMLUtil::ToStr( value, buf, BUF_SIZE );
+    PushText( buf, false );
+}
+
+
+void XMLPrinter::PushComment( const char* comment )
+{
+    if ( _elementJustOpened ) {
+        SealElement();
+    }
+    if ( _textDepth < 0 && !_firstElement && !_compactMode) {
+        Print( "\n" );
+        PrintSpace( _depth );
+    }
+    _firstElement = false;
+    Print( "<!--%s-->", comment );
+}
+
+
+void XMLPrinter::PushDeclaration( const char* value )
+{
+    if ( _elementJustOpened ) {
+        SealElement();
+    }
+    if ( _textDepth < 0 && !_firstElement && !_compactMode) {
+        Print( "\n" );
+        PrintSpace( _depth );
+    }
+    _firstElement = false;
+    Print( "<?%s?>", value );
+}
+
+
+void XMLPrinter::PushUnknown( const char* value )
+{
+    if ( _elementJustOpened ) {
+        SealElement();
+    }
+    if ( _textDepth < 0 && !_firstElement && !_compactMode) {
+        Print( "\n" );
+        PrintSpace( _depth );
+    }
+    _firstElement = false;
+    Print( "<!%s>", value );
+}
+
+
+bool XMLPrinter::VisitEnter( const XMLDocument& doc )
+{
+    _processEntities = doc.ProcessEntities();
+    if ( doc.HasBOM() ) {
+        PushHeader( true, false );
+    }
+    return true;
+}
+
+
+bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
+{
+    OpenElement( element.Name() );
+    while ( attribute ) {
+        PushAttribute( attribute->Name(), attribute->Value() );
+        attribute = attribute->Next();
+    }
+    return true;
+}
+
+
+bool XMLPrinter::VisitExit( const XMLElement& )
+{
+    CloseElement();
+    return true;
+}
+
+
+bool XMLPrinter::Visit( const XMLText& text )
+{
+    PushText( text.Value(), text.CData() );
+    return true;
+}
+
+
+bool XMLPrinter::Visit( const XMLComment& comment )
+{
+    PushComment( comment.Value() );
+    return true;
+}
+
+bool XMLPrinter::Visit( const XMLDeclaration& declaration )
+{
+    PushDeclaration( declaration.Value() );
+    return true;
+}
+
+
+bool XMLPrinter::Visit( const XMLUnknown& unknown )
+{
+    PushUnknown( unknown.Value() );
+    return true;
+}
+
+}   // namespace tinyxml2
+

+ 1973 - 0
include/igl/xml/tinyxml2.h

@@ -0,0 +1,1973 @@
+/*
+Original code by Lee Thomason (www.grinninglizard.com)
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any
+damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any
+purpose, including commercial applications, and to alter it and
+redistribute it freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must
+not claim that you wrote the original software. If you use this
+software in a product, an acknowledgment in the product documentation
+would be appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and
+must not be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source
+distribution.
+*/
+
+#ifndef TINYXML2_INCLUDED
+#define TINYXML2_INCLUDED
+
+#if defined(ANDROID_NDK) || defined(__BORLANDC__)
+#   include <ctype.h>
+#   include <limits.h>
+#   include <stdio.h>
+#   include <stdlib.h>
+#   include <string.h>
+#   include <stdarg.h>
+#else
+#   include <cctype>
+#   include <climits>
+#   include <cstdio>
+#   include <cstdlib>
+#   include <cstring>
+#   include <cstdarg>
+#endif
+
+/*
+   TODO: intern strings instead of allocation.
+*/
+/*
+	gcc:
+        g++ -Wall -DDEBUG tinyxml2.cpp xmltest.cpp -o gccxmltest.exe
+
+    Formatting, Artistic Style:
+        AStyle.exe --style=1tbs --indent-switches --break-closing-brackets --indent-preprocessor tinyxml2.cpp tinyxml2.h
+*/
+
+#if defined( _DEBUG ) || defined( DEBUG ) || defined (__DEBUG__)
+#   ifndef DEBUG
+#       define DEBUG
+#   endif
+#endif
+
+
+#if defined(DEBUG)
+#   if defined(_MSC_VER)
+#       define TIXMLASSERT( x )           if ( !(x)) { __debugbreak(); } //if ( !(x)) WinDebugBreak()
+#   elif defined (ANDROID_NDK)
+#       include <android/log.h>
+#       define TIXMLASSERT( x )           if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); }
+#   else
+#       include <assert.h>
+#       define TIXMLASSERT                assert
+#   endif
+#   else
+#       define TIXMLASSERT( x )           {}
+#endif
+
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
+// Microsoft visual studio, version 2005 and higher.
+/*int _snprintf_s(
+   char *buffer,
+   size_t sizeOfBuffer,
+   size_t count,
+   const char *format [,
+	  argument] ...
+);*/
+inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
+{
+    va_list va;
+    va_start( va, format );
+    int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
+    va_end( va );
+    return result;
+}
+#define TIXML_SSCANF   sscanf_s
+#else
+// GCC version 3 and higher
+//#warning( "Using sn* functions." )
+#define TIXML_SNPRINTF snprintf
+#define TIXML_SSCANF   sscanf
+#endif
+
+static const int TIXML2_MAJOR_VERSION = 1;
+static const int TIXML2_MINOR_VERSION = 0;
+static const int TIXML2_PATCH_VERSION = 11;
+
+namespace tinyxml2
+{
+class XMLDocument;
+class XMLElement;
+class XMLAttribute;
+class XMLComment;
+class XMLNode;
+class XMLText;
+class XMLDeclaration;
+class XMLUnknown;
+
+class XMLPrinter;
+
+/*
+	A class that wraps strings. Normally stores the start and end
+	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[]
+*/
+class StrPair
+{
+public:
+    enum {
+        NEEDS_ENTITY_PROCESSING			= 0x01,
+        NEEDS_NEWLINE_NORMALIZATION		= 0x02,
+        COLLAPSE_WHITESPACE	                = 0x04,
+
+        TEXT_ELEMENT		            	= NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
+        TEXT_ELEMENT_LEAVE_ENTITIES		= NEEDS_NEWLINE_NORMALIZATION,
+        ATTRIBUTE_NAME		            	= 0,
+        ATTRIBUTE_VALUE		            	= NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
+        ATTRIBUTE_VALUE_LEAVE_ENTITIES  	= NEEDS_NEWLINE_NORMALIZATION,
+        COMMENT				        = NEEDS_NEWLINE_NORMALIZATION
+    };
+
+    StrPair() : _flags( 0 ), _start( 0 ), _end( 0 ) {}
+    ~StrPair();
+
+    void Set( char* start, char* end, int flags ) {
+        Reset();
+        _start  = start;
+        _end    = end;
+        _flags  = flags | NEEDS_FLUSH;
+    }
+
+    const char* GetStr();
+
+    bool Empty() const {
+        return _start == _end;
+    }
+
+    void SetInternedStr( const char* str ) {
+        Reset();
+        _start = const_cast<char*>(str);
+    }
+
+    void SetStr( const char* str, int flags=0 );
+
+    char* ParseText( char* in, const char* endTag, int strFlags );
+    char* ParseName( char* in );
+
+private:
+    void Reset();
+    void CollapseWhitespace();
+
+    enum {
+        NEEDS_FLUSH = 0x100,
+        NEEDS_DELETE = 0x200
+    };
+
+    // After parsing, if *_end != 0, it can be set to zero.
+    int     _flags;
+    char*   _start;
+    char*   _end;
+};
+
+
+/*
+	A dynamic array of Plain Old Data. Doesn't support constructors, etc.
+	Has a small initial memory pool, so that low or no usage will not
+	cause a call to new/delete
+*/
+template <class T, int INIT>
+class DynArray
+{
+public:
+    DynArray< T, INIT >() {
+        _mem = _pool;
+        _allocated = INIT;
+        _size = 0;
+    }
+
+    ~DynArray() {
+        if ( _mem != _pool ) {
+            delete [] _mem;
+        }
+    }
+
+    void Push( T t ) {
+        EnsureCapacity( _size+1 );
+        _mem[_size++] = t;
+    }
+
+    T* PushArr( int count ) {
+        EnsureCapacity( _size+count );
+        T* ret = &_mem[_size];
+        _size += count;
+        return ret;
+    }
+
+    T Pop() {
+        return _mem[--_size];
+    }
+
+    void PopArr( int count ) {
+        TIXMLASSERT( _size >= count );
+        _size -= count;
+    }
+
+    bool Empty() const					{
+        return _size == 0;
+    }
+
+    T& operator[](int i)				{
+        TIXMLASSERT( i>= 0 && i < _size );
+        return _mem[i];
+    }
+
+    const T& operator[](int i) const	{
+        TIXMLASSERT( i>= 0 && i < _size );
+        return _mem[i];
+    }
+
+    int Size() const					{
+        return _size;
+    }
+
+    int Capacity() const				{
+        return _allocated;
+    }
+
+    const T* Mem() const				{
+        return _mem;
+    }
+
+    T* Mem()							{
+        return _mem;
+    }
+
+private:
+    void EnsureCapacity( int cap ) {
+        if ( cap > _allocated ) {
+            int newAllocated = cap * 2;
+            T* newMem = new T[newAllocated];
+            memcpy( newMem, _mem, sizeof(T)*_size );	// warning: not using constructors, only works for PODs
+            if ( _mem != _pool ) {
+                delete [] _mem;
+            }
+            _mem = newMem;
+            _allocated = newAllocated;
+        }
+    }
+
+    T*  _mem;
+    T   _pool[INIT];
+    int _allocated;		// objects allocated
+    int _size;			// number objects in use
+};
+
+
+/*
+	Parent virtual class of a pool for fast allocation
+	and deallocation of objects.
+*/
+class MemPool
+{
+public:
+    MemPool() {}
+    virtual ~MemPool() {}
+
+    virtual int ItemSize() const = 0;
+    virtual void* Alloc() = 0;
+    virtual void Free( void* ) = 0;
+    virtual void SetTracked() = 0;
+};
+
+
+/*
+	Template child class to create pools of the correct type.
+*/
+template< int SIZE >
+class MemPoolT : public MemPool
+{
+public:
+    MemPoolT() : _root(0), _currentAllocs(0), _nAllocs(0), _maxAllocs(0), _nUntracked(0)	{}
+    ~MemPoolT() {
+        // Delete the blocks.
+        for( int i=0; i<_blockPtrs.Size(); ++i ) {
+            delete _blockPtrs[i];
+        }
+    }
+
+    virtual int ItemSize() const	{
+        return SIZE;
+    }
+    int CurrentAllocs() const		{
+        return _currentAllocs;
+    }
+
+    virtual void* Alloc() {
+        if ( !_root ) {
+            // Need a new block.
+            Block* block = new Block();
+            _blockPtrs.Push( block );
+
+            for( int i=0; i<COUNT-1; ++i ) {
+                block->chunk[i].next = &block->chunk[i+1];
+            }
+            block->chunk[COUNT-1].next = 0;
+            _root = block->chunk;
+        }
+        void* result = _root;
+        _root = _root->next;
+
+        ++_currentAllocs;
+        if ( _currentAllocs > _maxAllocs ) {
+            _maxAllocs = _currentAllocs;
+        }
+        _nAllocs++;
+        _nUntracked++;
+        return result;
+    }
+    virtual void Free( void* mem ) {
+        if ( !mem ) {
+            return;
+        }
+        --_currentAllocs;
+        Chunk* chunk = (Chunk*)mem;
+#ifdef DEBUG
+        memset( chunk, 0xfe, sizeof(Chunk) );
+#endif
+        chunk->next = _root;
+        _root = chunk;
+    }
+    void Trace( const char* name ) {
+        printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n",
+                name, _maxAllocs, _maxAllocs*SIZE/1024, _currentAllocs, SIZE, _nAllocs, _blockPtrs.Size() );
+    }
+
+    void SetTracked() {
+        _nUntracked--;
+    }
+
+    int Untracked() const {
+        return _nUntracked;
+    }
+
+	// This number is perf sensitive. 4k seems like a good tradeoff on my machine.
+	// The test file is large, 170k.
+	// Release:		VS2010 gcc(no opt)
+	//		1k:		4000
+	//		2k:		4000
+	//		4k:		3900	21000
+	//		16k:	5200
+	//		32k:	4300
+	//		64k:	4000	21000
+    enum { COUNT = (4*1024)/SIZE }; // Some compilers do not accept to use COUNT in private part if COUNT is private
+
+private:
+    union Chunk {
+        Chunk*  next;
+        char    mem[SIZE];
+    };
+    struct Block {
+        Chunk chunk[COUNT];
+    };
+    DynArray< Block*, 10 > _blockPtrs;
+    Chunk* _root;
+
+    int _currentAllocs;
+    int _nAllocs;
+    int _maxAllocs;
+    int _nUntracked;
+};
+
+
+
+/**
+	Implements the interface to the "Visitor pattern" (see the Accept() method.)
+	If you call the Accept() method, it requires being passed a XMLVisitor
+	class to handle callbacks. For nodes that contain other nodes (Document, Element)
+	you will get called with a VisitEnter/VisitExit pair. Nodes that are always leafs
+	are simply called with Visit().
+
+	If you return 'true' from a Visit method, recursive parsing will continue. If you return
+	false, <b>no children of this node or its siblings</b> will be visited.
+
+	All flavors of Visit methods have a default implementation that returns 'true' (continue
+	visiting). You need to only override methods that are interesting to you.
+
+	Generally Accept() is called on the TiXmlDocument, although all nodes support visiting.
+
+	You should never change the document from a callback.
+
+	@sa XMLNode::Accept()
+*/
+class XMLVisitor
+{
+public:
+    virtual ~XMLVisitor() {}
+
+    /// Visit a document.
+    virtual bool VisitEnter( const XMLDocument& /*doc*/ )			{
+        return true;
+    }
+    /// Visit a document.
+    virtual bool VisitExit( const XMLDocument& /*doc*/ )			{
+        return true;
+    }
+
+    /// Visit an element.
+    virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ )	{
+        return true;
+    }
+    /// Visit an element.
+    virtual bool VisitExit( const XMLElement& /*element*/ )			{
+        return true;
+    }
+
+    /// Visit a declaration.
+    virtual bool Visit( const XMLDeclaration& /*declaration*/ )		{
+        return true;
+    }
+    /// Visit a text node.
+    virtual bool Visit( const XMLText& /*text*/ )					{
+        return true;
+    }
+    /// Visit a comment node.
+    virtual bool Visit( const XMLComment& /*comment*/ )				{
+        return true;
+    }
+    /// Visit an unknown node.
+    virtual bool Visit( const XMLUnknown& /*unknown*/ )				{
+        return true;
+    }
+};
+
+
+/*
+	Utility functionality.
+*/
+class XMLUtil
+{
+public:
+    // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't
+    // correct, but simple, and usually works.
+    static const char* SkipWhiteSpace( const char* p )	{
+        while( !IsUTF8Continuation(*p) && isspace( *reinterpret_cast<const unsigned char*>(p) ) ) {
+            ++p;
+        }
+        return p;
+    }
+    static char* SkipWhiteSpace( char* p )				{
+        while( !IsUTF8Continuation(*p) && isspace( *reinterpret_cast<unsigned char*>(p) ) )		{
+            ++p;
+        }
+        return p;
+    }
+    static bool IsWhiteSpace( char p )					{
+        return !IsUTF8Continuation(p) && isspace( static_cast<unsigned char>(p) );
+    }
+    
+    inline static bool IsNameStartChar( unsigned char ch ) {
+        return ( ( ch < 128 ) ? isalpha( ch ) : 1 )
+               || ch == ':'
+               || ch == '_';
+    }
+    
+    inline static bool IsNameChar( unsigned char ch ) {
+        return IsNameStartChar( ch )
+               || isdigit( ch )
+               || ch == '.'
+               || ch == '-';
+    }
+
+    inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX )  {
+        int n = 0;
+        if ( p == q ) {
+            return true;
+        }
+        while( *p && *q && *p == *q && n<nChar ) {
+            ++p;
+            ++q;
+            ++n;
+        }
+        if ( (n == nChar) || ( *p == 0 && *q == 0 ) ) {
+            return true;
+        }
+        return false;
+    }
+    
+    inline static int IsUTF8Continuation( const char p ) {
+        return p & 0x80;
+    }
+
+    static const char* ReadBOM( const char* p, bool* hasBOM );
+    // p is the starting location,
+    // the UTF-8 value of the entity will be placed in value, and length filled in.
+    static const char* GetCharacterRef( const char* p, char* value, int* length );
+    static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length );
+
+    // converts primitive types to strings
+    static void ToStr( int v, char* buffer, int bufferSize );
+    static void ToStr( unsigned v, char* buffer, int bufferSize );
+    static void ToStr( bool v, char* buffer, int bufferSize );
+    static void ToStr( float v, char* buffer, int bufferSize );
+    static void ToStr( double v, char* buffer, int bufferSize );
+
+    // converts strings to primitive types
+    static bool	ToInt( const char* str, int* value );
+    static bool ToUnsigned( const char* str, unsigned* value );
+    static bool	ToBool( const char* str, bool* value );
+    static bool	ToFloat( const char* str, float* value );
+    static bool ToDouble( const char* str, double* value );
+};
+
+
+/** XMLNode is a base class for every object that is in the
+	XML Document Object Model (DOM), except XMLAttributes.
+	Nodes have siblings, a parent, and children which can
+	be navigated. A node is always in a XMLDocument.
+	The type of a XMLNode can be queried, and it can
+	be cast to its more defined type.
+
+	A XMLDocument allocates memory for all its Nodes.
+	When the XMLDocument gets deleted, all its Nodes
+	will also be deleted.
+
+	@verbatim
+	A Document can contain:	Element	(container or leaf)
+							Comment (leaf)
+							Unknown (leaf)
+							Declaration( leaf )
+
+	An Element can contain:	Element (container or leaf)
+							Text	(leaf)
+							Attributes (not on tree)
+							Comment (leaf)
+							Unknown (leaf)
+
+	@endverbatim
+*/
+class XMLNode
+{
+    friend class XMLDocument;
+    friend class XMLElement;
+public:
+
+    /// Get the XMLDocument that owns this XMLNode.
+    const XMLDocument* GetDocument() const	{
+        return _document;
+    }
+    /// Get the XMLDocument that owns this XMLNode.
+    XMLDocument* GetDocument()				{
+        return _document;
+    }
+
+    /// Safely cast to an Element, or null.
+    virtual XMLElement*		ToElement()		{
+        return 0;
+    }
+    /// Safely cast to Text, or null.
+    virtual XMLText*		ToText()		{
+        return 0;
+    }
+    /// Safely cast to a Comment, or null.
+    virtual XMLComment*		ToComment()		{
+        return 0;
+    }
+    /// Safely cast to a Document, or null.
+    virtual XMLDocument*	ToDocument()	{
+        return 0;
+    }
+    /// Safely cast to a Declaration, or null.
+    virtual XMLDeclaration*	ToDeclaration()	{
+        return 0;
+    }
+    /// Safely cast to an Unknown, or null.
+    virtual XMLUnknown*		ToUnknown()		{
+        return 0;
+    }
+
+    virtual const XMLElement*		ToElement() const		{
+        return 0;
+    }
+    virtual const XMLText*			ToText() const			{
+        return 0;
+    }
+    virtual const XMLComment*		ToComment() const		{
+        return 0;
+    }
+    virtual const XMLDocument*		ToDocument() const		{
+        return 0;
+    }
+    virtual const XMLDeclaration*	ToDeclaration() const	{
+        return 0;
+    }
+    virtual const XMLUnknown*		ToUnknown() const		{
+        return 0;
+    }
+
+    /** The meaning of 'value' changes for the specific type.
+    	@verbatim
+    	Document:	empty
+    	Element:	name of the element
+    	Comment:	the comment text
+    	Unknown:	the tag contents
+    	Text:		the text string
+    	@endverbatim
+    */
+    const char* Value() const			{
+        return _value.GetStr();
+    }
+
+    /** Set the Value of an XML node.
+    	@sa Value()
+    */
+    void SetValue( const char* val, bool staticMem=false );
+
+    /// Get the parent of this node on the DOM.
+    const XMLNode*	Parent() const			{
+        return _parent;
+    }
+
+    XMLNode* Parent()						{
+        return _parent;
+    }
+
+    /// Returns true if this node has no children.
+    bool NoChildren() const					{
+        return !_firstChild;
+    }
+
+    /// Get the first child node, or null if none exists.
+    const XMLNode*  FirstChild() const		{
+        return _firstChild;
+    }
+
+    XMLNode*		FirstChild()			{
+        return _firstChild;
+    }
+
+    /** Get the first child element, or optionally the first child
+        element with the specified name.
+    */
+    const XMLElement* FirstChildElement( const char* value=0 ) const;
+
+    XMLElement* FirstChildElement( const char* value=0 )	{
+        return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->FirstChildElement( value ));
+    }
+
+    /// Get the last child node, or null if none exists.
+    const XMLNode*	LastChild() const						{
+        return _lastChild;
+    }
+
+    XMLNode*		LastChild()								{
+        return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->LastChild() );
+    }
+
+    /** Get the last child element or optionally the last child
+        element with the specified name.
+    */
+    const XMLElement* LastChildElement( const char* value=0 ) const;
+
+    XMLElement* LastChildElement( const char* value=0 )	{
+        return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->LastChildElement(value) );
+    }
+
+    /// Get the previous (left) sibling node of this node.
+    const XMLNode*	PreviousSibling() const					{
+        return _prev;
+    }
+
+    XMLNode*	PreviousSibling()							{
+        return _prev;
+    }
+
+    /// Get the previous (left) sibling element of this node, with an optionally supplied name.
+    const XMLElement*	PreviousSiblingElement( const char* value=0 ) const ;
+
+    XMLElement*	PreviousSiblingElement( const char* value=0 ) {
+        return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement( value ) );
+    }
+
+    /// Get the next (right) sibling node of this node.
+    const XMLNode*	NextSibling() const						{
+        return _next;
+    }
+
+    XMLNode*	NextSibling()								{
+        return _next;
+    }
+
+    /// Get the next (right) sibling element of this node, with an optionally supplied name.
+    const XMLElement*	NextSiblingElement( const char* value=0 ) const;
+
+    XMLElement*	NextSiblingElement( const char* value=0 )	{
+        return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->NextSiblingElement( value ) );
+    }
+
+    /**
+    	Add a child node as the last (right) child.
+    */
+    XMLNode* InsertEndChild( XMLNode* addThis );
+
+    XMLNode* LinkEndChild( XMLNode* addThis )	{
+        return InsertEndChild( addThis );
+    }
+    /**
+    	Add a child node as the first (left) child.
+    */
+    XMLNode* InsertFirstChild( XMLNode* addThis );
+    /**
+    	Add a node after the specified child node.
+    */
+    XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis );
+
+    /**
+    	Delete all the children of this node.
+    */
+    void DeleteChildren();
+
+    /**
+    	Delete a child of this node.
+    */
+    void DeleteChild( XMLNode* node );
+
+    /**
+    	Make a copy of this node, but not its children.
+    	You may pass in a Document pointer that will be
+    	the owner of the new Node. If the 'document' is
+    	null, then the node returned will be allocated
+    	from the current Document. (this->GetDocument())
+
+    	Note: if called on a XMLDocument, this will return null.
+    */
+    virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0;
+
+    /**
+    	Test if 2 nodes are the same, but don't test children.
+    	The 2 nodes do not need to be in the same Document.
+
+    	Note: if called on a XMLDocument, this will return false.
+    */
+    virtual bool ShallowEqual( const XMLNode* compare ) const = 0;
+
+    /** Accept a hierarchical visit of the nodes in the TinyXML DOM. Every node in the
+    	XML tree will be conditionally visited and the host will be called back
+    	via the TiXmlVisitor interface.
+
+    	This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse
+    	the XML for the callbacks, so the performance of TinyXML is unchanged by using this
+    	interface versus any other.)
+
+    	The interface has been based on ideas from:
+
+    	- http://www.saxproject.org/
+    	- http://c2.com/cgi/wiki?HierarchicalVisitorPattern
+
+    	Which are both good references for "visiting".
+
+    	An example of using Accept():
+    	@verbatim
+    	TiXmlPrinter printer;
+    	tinyxmlDoc.Accept( &printer );
+    	const char* xmlcstr = printer.CStr();
+    	@endverbatim
+    */
+    virtual bool Accept( XMLVisitor* visitor ) const = 0;
+
+    // internal
+    virtual char* ParseDeep( char*, StrPair* );
+
+protected:
+    XMLNode( XMLDocument* );
+    virtual ~XMLNode();
+    XMLNode( const XMLNode& );	// not supported
+    XMLNode& operator=( const XMLNode& );	// not supported
+
+    XMLDocument*	_document;
+    XMLNode*		_parent;
+    mutable StrPair	_value;
+
+    XMLNode*		_firstChild;
+    XMLNode*		_lastChild;
+
+    XMLNode*		_prev;
+    XMLNode*		_next;
+
+private:
+    MemPool*		_memPool;
+    void Unlink( XMLNode* child );
+};
+
+
+/** XML text.
+
+	Note that a text node can have child element nodes, for example:
+	@verbatim
+	<root>This is <b>bold</b></root>
+	@endverbatim
+
+	A text node can have 2 ways to output the next. "normal" output
+	and CDATA. It will default to the mode it was parsed from the XML file and
+	you generally want to leave it alone, but you can change the output mode with
+	SetCDATA() and query it with CDATA().
+*/
+class XMLText : public XMLNode
+{
+    friend class XMLBase;
+    friend class XMLDocument;
+public:
+    virtual bool Accept( XMLVisitor* visitor ) const;
+
+    virtual XMLText* ToText()			{
+        return this;
+    }
+    virtual const XMLText* ToText() const	{
+        return this;
+    }
+
+    /// Declare whether this should be CDATA or standard text.
+    void SetCData( bool isCData )			{
+        _isCData = isCData;
+    }
+    /// Returns true if this is a CDATA text element.
+    bool CData() const						{
+        return _isCData;
+    }
+
+    char* ParseDeep( char*, StrPair* endTag );
+    virtual XMLNode* ShallowClone( XMLDocument* document ) const;
+    virtual bool ShallowEqual( const XMLNode* compare ) const;
+
+protected:
+    XMLText( XMLDocument* doc )	: XMLNode( doc ), _isCData( false )	{}
+    virtual ~XMLText()												{}
+    XMLText( const XMLText& );	// not supported
+    XMLText& operator=( const XMLText& );	// not supported
+
+private:
+    bool _isCData;
+};
+
+
+/** An XML Comment. */
+class XMLComment : public XMLNode
+{
+    friend class XMLDocument;
+public:
+    virtual XMLComment*	ToComment()					{
+        return this;
+    }
+    virtual const XMLComment* ToComment() const		{
+        return this;
+    }
+
+    virtual bool Accept( XMLVisitor* visitor ) const;
+
+    char* ParseDeep( char*, StrPair* endTag );
+    virtual XMLNode* ShallowClone( XMLDocument* document ) const;
+    virtual bool ShallowEqual( const XMLNode* compare ) const;
+
+protected:
+    XMLComment( XMLDocument* doc );
+    virtual ~XMLComment();
+    XMLComment( const XMLComment& );	// not supported
+    XMLComment& operator=( const XMLComment& );	// not supported
+
+private:
+};
+
+
+/** In correct XML the declaration is the first entry in the file.
+	@verbatim
+		<?xml version="1.0" standalone="yes"?>
+	@endverbatim
+
+	TinyXML2 will happily read or write files without a declaration,
+	however.
+
+	The text of the declaration isn't interpreted. It is parsed
+	and written as a string.
+*/
+class XMLDeclaration : public XMLNode
+{
+    friend class XMLDocument;
+public:
+    virtual XMLDeclaration*	ToDeclaration()					{
+        return this;
+    }
+    virtual const XMLDeclaration* ToDeclaration() const		{
+        return this;
+    }
+
+    virtual bool Accept( XMLVisitor* visitor ) const;
+
+    char* ParseDeep( char*, StrPair* endTag );
+    virtual XMLNode* ShallowClone( XMLDocument* document ) const;
+    virtual bool ShallowEqual( const XMLNode* compare ) const;
+
+protected:
+    XMLDeclaration( XMLDocument* doc );
+    virtual ~XMLDeclaration();
+    XMLDeclaration( const XMLDeclaration& );	// not supported
+    XMLDeclaration& operator=( const XMLDeclaration& );	// not supported
+};
+
+
+/** Any tag that tinyXml doesn't recognize is saved as an
+	unknown. It is a tag of text, but should not be modified.
+	It will be written back to the XML, unchanged, when the file
+	is saved.
+
+	DTD tags get thrown into TiXmlUnknowns.
+*/
+class XMLUnknown : public XMLNode
+{
+    friend class XMLDocument;
+public:
+    virtual XMLUnknown*	ToUnknown()					{
+        return this;
+    }
+    virtual const XMLUnknown* ToUnknown() const		{
+        return this;
+    }
+
+    virtual bool Accept( XMLVisitor* visitor ) const;
+
+    char* ParseDeep( char*, StrPair* endTag );
+    virtual XMLNode* ShallowClone( XMLDocument* document ) const;
+    virtual bool ShallowEqual( const XMLNode* compare ) const;
+
+protected:
+    XMLUnknown( XMLDocument* doc );
+    virtual ~XMLUnknown();
+    XMLUnknown( const XMLUnknown& );	// not supported
+    XMLUnknown& operator=( const XMLUnknown& );	// not supported
+};
+
+
+enum XMLError {
+    XML_NO_ERROR = 0,
+    XML_SUCCESS = 0,
+
+    XML_NO_ATTRIBUTE,
+    XML_WRONG_ATTRIBUTE_TYPE,
+
+    XML_ERROR_FILE_NOT_FOUND,
+    XML_ERROR_FILE_COULD_NOT_BE_OPENED,
+    XML_ERROR_FILE_READ_ERROR,
+    XML_ERROR_ELEMENT_MISMATCH,
+    XML_ERROR_PARSING_ELEMENT,
+    XML_ERROR_PARSING_ATTRIBUTE,
+    XML_ERROR_IDENTIFYING_TAG,
+    XML_ERROR_PARSING_TEXT,
+    XML_ERROR_PARSING_CDATA,
+    XML_ERROR_PARSING_COMMENT,
+    XML_ERROR_PARSING_DECLARATION,
+    XML_ERROR_PARSING_UNKNOWN,
+    XML_ERROR_EMPTY_DOCUMENT,
+    XML_ERROR_MISMATCHED_ELEMENT,
+    XML_ERROR_PARSING,
+
+    XML_CAN_NOT_CONVERT_TEXT,
+    XML_NO_TEXT_NODE
+};
+
+
+/** An attribute is a name-value pair. Elements have an arbitrary
+	number of attributes, each with a unique name.
+
+	@note The attributes are not XMLNodes. You may only query the
+	Next() attribute in a list.
+*/
+class XMLAttribute
+{
+    friend class XMLElement;
+public:
+    /// The name of the attribute.
+    const char* Name() const {
+        return _name.GetStr();
+    }
+    /// The value of the attribute.
+    const char* Value() const {
+        return _value.GetStr();
+    }
+    /// The next attribute in the list.
+    const XMLAttribute* Next() const {
+        return _next;
+    }
+
+    /** IntAttribute interprets the attribute as an integer, and returns the value.
+        If the value isn't an integer, 0 will be returned. There is no error checking;
+    	use QueryIntAttribute() if you need error checking.
+    */
+    int		 IntValue() const				{
+        int i=0;
+        QueryIntValue( &i );
+        return i;
+    }
+    /// Query as an unsigned integer. See IntAttribute()
+    unsigned UnsignedValue() const			{
+        unsigned i=0;
+        QueryUnsignedValue( &i );
+        return i;
+    }
+    /// Query as a boolean. See IntAttribute()
+    bool	 BoolValue() const				{
+        bool b=false;
+        QueryBoolValue( &b );
+        return b;
+    }
+    /// Query as a double. See IntAttribute()
+    double 	 DoubleValue() const			{
+        double d=0;
+        QueryDoubleValue( &d );
+        return d;
+    }
+    /// Query as a float. See IntAttribute()
+    float	 FloatValue() const				{
+        float f=0;
+        QueryFloatValue( &f );
+        return f;
+    }
+
+    /** QueryIntAttribute interprets the attribute as an integer, and returns the value
+    	in the provided parameter. The function will return XML_NO_ERROR on success,
+    	and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful.
+    */
+    XMLError QueryIntValue( int* value ) const;
+    /// See QueryIntAttribute
+    XMLError QueryUnsignedValue( unsigned int* value ) const;
+    /// See QueryIntAttribute
+    XMLError QueryBoolValue( bool* value ) const;
+    /// See QueryIntAttribute
+    XMLError QueryDoubleValue( double* value ) const;
+    /// See QueryIntAttribute
+    XMLError QueryFloatValue( float* value ) const;
+
+    /// Set the attribute to a string value.
+    void SetAttribute( const char* value );
+    /// Set the attribute to value.
+    void SetAttribute( int value );
+    /// Set the attribute to value.
+    void SetAttribute( unsigned value );
+    /// Set the attribute to value.
+    void SetAttribute( bool value );
+    /// Set the attribute to value.
+    void SetAttribute( double value );
+    /// Set the attribute to value.
+    void SetAttribute( float value );
+
+private:
+    enum { BUF_SIZE = 200 };
+
+    XMLAttribute() : _next( 0 ), _memPool( 0 ) {}
+    virtual ~XMLAttribute()	{}
+
+    XMLAttribute( const XMLAttribute& );	// not supported
+    void operator=( const XMLAttribute& );	// not supported
+    void SetName( const char* name );
+
+    char* ParseDeep( char* p, bool processEntities );
+
+    mutable StrPair _name;
+    mutable StrPair _value;
+    XMLAttribute*   _next;
+    MemPool*        _memPool;
+};
+
+
+/** The element is a container class. It has a value, the element name,
+	and can contain other elements, text, comments, and unknowns.
+	Elements also contain an arbitrary number of attributes.
+*/
+class XMLElement : public XMLNode
+{
+    friend class XMLBase;
+    friend class XMLDocument;
+public:
+    /// Get the name of an element (which is the Value() of the node.)
+    const char* Name() const		{
+        return Value();
+    }
+    /// Set the name of the element.
+    void SetName( const char* str, bool staticMem=false )	{
+        SetValue( str, staticMem );
+    }
+
+    virtual XMLElement* ToElement()				{
+        return this;
+    }
+    virtual const XMLElement* ToElement() const {
+        return this;
+    }
+    virtual bool Accept( XMLVisitor* visitor ) const;
+
+    /** Given an attribute name, Attribute() returns the value
+    	for the attribute of that name, or null if none
+    	exists. For example:
+
+    	@verbatim
+    	const char* value = ele->Attribute( "foo" );
+    	@endverbatim
+
+    	The 'value' parameter is normally null. However, if specified,
+    	the attribute will only be returned if the 'name' and 'value'
+    	match. This allow you to write code:
+
+    	@verbatim
+    	if ( ele->Attribute( "foo", "bar" ) ) callFooIsBar();
+    	@endverbatim
+
+    	rather than:
+    	@verbatim
+    	if ( ele->Attribute( "foo" ) ) {
+    		if ( strcmp( ele->Attribute( "foo" ), "bar" ) == 0 ) callFooIsBar();
+    	}
+    	@endverbatim
+    */
+    const char* Attribute( const char* name, const char* value=0 ) const;
+
+    /** Given an attribute name, IntAttribute() returns the value
+    	of the attribute interpreted as an integer. 0 will be
+    	returned if there is an error. For a method with error
+    	checking, see QueryIntAttribute()
+    */
+    int		 IntAttribute( const char* name ) const		{
+        int i=0;
+        QueryIntAttribute( name, &i );
+        return i;
+    }
+    /// See IntAttribute()
+    unsigned UnsignedAttribute( const char* name ) const {
+        unsigned i=0;
+        QueryUnsignedAttribute( name, &i );
+        return i;
+    }
+    /// See IntAttribute()
+    bool	 BoolAttribute( const char* name ) const	{
+        bool b=false;
+        QueryBoolAttribute( name, &b );
+        return b;
+    }
+    /// See IntAttribute()
+    double 	 DoubleAttribute( const char* name ) const	{
+        double d=0;
+        QueryDoubleAttribute( name, &d );
+        return d;
+    }
+    /// See IntAttribute()
+    float	 FloatAttribute( const char* name ) const	{
+        float f=0;
+        QueryFloatAttribute( name, &f );
+        return f;
+    }
+
+    /** Given an attribute name, QueryIntAttribute() returns
+    	XML_NO_ERROR, XML_WRONG_ATTRIBUTE_TYPE if the conversion
+    	can't be performed, or XML_NO_ATTRIBUTE if the attribute
+    	doesn't exist. If successful, the result of the conversion
+    	will be written to 'value'. If not successful, nothing will
+    	be written to 'value'. This allows you to provide default
+    	value:
+
+    	@verbatim
+    	int value = 10;
+    	QueryIntAttribute( "foo", &value );		// if "foo" isn't found, value will still be 10
+    	@endverbatim
+    */
+    XMLError QueryIntAttribute( const char* name, int* value ) const				{
+        const XMLAttribute* a = FindAttribute( name );
+        if ( !a ) {
+            return XML_NO_ATTRIBUTE;
+        }
+        return a->QueryIntValue( value );
+    }
+    /// See QueryIntAttribute()
+    XMLError QueryUnsignedAttribute( const char* name, unsigned int* value ) const	{
+        const XMLAttribute* a = FindAttribute( name );
+        if ( !a ) {
+            return XML_NO_ATTRIBUTE;
+        }
+        return a->QueryUnsignedValue( value );
+    }
+    /// See QueryIntAttribute()
+    XMLError QueryBoolAttribute( const char* name, bool* value ) const				{
+        const XMLAttribute* a = FindAttribute( name );
+        if ( !a ) {
+            return XML_NO_ATTRIBUTE;
+        }
+        return a->QueryBoolValue( value );
+    }
+    /// See QueryIntAttribute()
+    XMLError QueryDoubleAttribute( const char* name, double* value ) const			{
+        const XMLAttribute* a = FindAttribute( name );
+        if ( !a ) {
+            return XML_NO_ATTRIBUTE;
+        }
+        return a->QueryDoubleValue( value );
+    }
+    /// See QueryIntAttribute()
+    XMLError QueryFloatAttribute( const char* name, float* value ) const			{
+        const XMLAttribute* a = FindAttribute( name );
+        if ( !a ) {
+            return XML_NO_ATTRIBUTE;
+        }
+        return a->QueryFloatValue( value );
+    }
+
+	
+    /** Given an attribute name, QueryAttribute() returns
+    	XML_NO_ERROR, XML_WRONG_ATTRIBUTE_TYPE if the conversion
+    	can't be performed, or XML_NO_ATTRIBUTE if the attribute
+    	doesn't exist. It is overloaded for the primitive types,
+		and is a generally more convenient replacement of
+		QueryIntAttribute() and related functions.
+		
+		If successful, the result of the conversion
+    	will be written to 'value'. If not successful, nothing will
+    	be written to 'value'. This allows you to provide default
+    	value:
+
+    	@verbatim
+    	int value = 10;
+    	QueryAttribute( "foo", &value );		// if "foo" isn't found, value will still be 10
+    	@endverbatim
+    */
+	int QueryAttribute( const char* name, int* value ) const {
+		return QueryIntAttribute( name, value );
+	}
+
+	int QueryAttribute( const char* name, unsigned int* value ) const {
+		return QueryUnsignedAttribute( name, value );
+	}
+
+	int QueryAttribute( const char* name, bool* value ) const {
+		return QueryBoolAttribute( name, value );
+	}
+
+	int QueryAttribute( const char* name, double* value ) const {
+		return QueryDoubleAttribute( name, value );
+	}
+
+	int QueryAttribute( const char* name, float* value ) const {
+		return QueryFloatAttribute( name, value );
+	}
+
+	/// Sets the named attribute to value.
+    void SetAttribute( const char* name, const char* value )	{
+        XMLAttribute* a = FindOrCreateAttribute( name );
+        a->SetAttribute( value );
+    }
+    /// Sets the named attribute to value.
+    void SetAttribute( const char* name, int value )			{
+        XMLAttribute* a = FindOrCreateAttribute( name );
+        a->SetAttribute( value );
+    }
+    /// Sets the named attribute to value.
+    void SetAttribute( const char* name, unsigned 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 );
+        a->SetAttribute( value );
+    }
+	/// Sets the named attribute to value.
+    void SetAttribute( const char* name, float value )		{
+        XMLAttribute* a = FindOrCreateAttribute( name );
+        a->SetAttribute( value );
+    }
+    /// Sets the named attribute to value.
+    void SetAttribute( const char* name, double value )		{
+        XMLAttribute* a = FindOrCreateAttribute( name );
+        a->SetAttribute( value );
+    }
+
+    /**
+    	Delete an attribute.
+    */
+    void DeleteAttribute( const char* name );
+
+    /// Return the first attribute in the list.
+    const XMLAttribute* FirstAttribute() const {
+        return _rootAttribute;
+    }
+    /// Query a specific attribute in the list.
+    const XMLAttribute* FindAttribute( const char* name ) const;
+
+    /** Convenience function for easy access to the text inside an element. Although easy
+    	and concise, GetText() is limited compared to getting the TiXmlText child
+    	and accessing it directly.
+
+    	If the first child of 'this' is a TiXmlText, the GetText()
+    	returns the character string of the Text node, else null is returned.
+
+    	This is a convenient method for getting the text of simple contained text:
+    	@verbatim
+    	<foo>This is text</foo>
+    		const char* str = fooElement->GetText();
+    	@endverbatim
+
+    	'str' will be a pointer to "This is text".
+
+    	Note that this function can be misleading. If the element foo was created from
+    	this XML:
+    	@verbatim
+    		<foo><b>This is text</b></foo>
+    	@endverbatim
+
+    	then the value of str would be null. The first child node isn't a text node, it is
+    	another element. From this XML:
+    	@verbatim
+    		<foo>This is <b>text</b></foo>
+    	@endverbatim
+    	GetText() will return "This is ".
+    */
+    const char* GetText() const;
+
+    /**
+    	Convenience method to query the value of a child text node. This is probably best
+    	shown by example. Given you have a document is this form:
+    	@verbatim
+    		<point>
+    			<x>1</x>
+    			<y>1.4</y>
+    		</point>
+    	@endverbatim
+
+    	The QueryIntText() and similar functions provide a safe and easier way to get to the
+    	"value" of x and y.
+
+    	@verbatim
+    		int x = 0;
+    		float y = 0;	// types of x and y are contrived for example
+    		const XMLElement* xElement = pointElement->FirstChildElement( "x" );
+    		const XMLElement* yElement = pointElement->FirstChildElement( "y" );
+    		xElement->QueryIntText( &x );
+    		yElement->QueryFloatText( &y );
+    	@endverbatim
+
+    	@returns XML_SUCCESS (0) on success, XML_CAN_NOT_CONVERT_TEXT if the text cannot be converted
+    			 to the requested type, and XML_NO_TEXT_NODE if there is no child text to query.
+
+    */
+    XMLError QueryIntText( int* ival ) const;
+    /// See QueryIntText()
+    XMLError QueryUnsignedText( unsigned* uval ) const;
+    /// See QueryIntText()
+    XMLError QueryBoolText( bool* bval ) const;
+    /// See QueryIntText()
+    XMLError QueryDoubleText( double* dval ) const;
+    /// See QueryIntText()
+    XMLError QueryFloatText( float* fval ) const;
+
+    // internal:
+    enum {
+        OPEN,		// <foo>
+        CLOSED,		// <foo/>
+        CLOSING		// </foo>
+    };
+    int ClosingType() const {
+        return _closingType;
+    }
+    char* ParseDeep( char* p, StrPair* endTag );
+    virtual XMLNode* ShallowClone( XMLDocument* document ) const;
+    virtual bool ShallowEqual( const XMLNode* compare ) const;
+
+private:
+    XMLElement( XMLDocument* doc );
+    virtual ~XMLElement();
+    XMLElement( const XMLElement& );	// not supported
+    void operator=( const XMLElement& );	// not supported
+
+    XMLAttribute* FindAttribute( const char* name );
+    XMLAttribute* FindOrCreateAttribute( const char* name );
+    //void LinkAttribute( XMLAttribute* attrib );
+    char* ParseAttributes( char* p );
+
+    int _closingType;
+    // The attribute list is ordered; there is no 'lastAttribute'
+    // because the list needs to be scanned for dupes before adding
+    // a new attribute.
+    XMLAttribute* _rootAttribute;
+};
+
+
+enum Whitespace {
+    PRESERVE_WHITESPACE,
+    COLLAPSE_WHITESPACE
+};
+
+
+/** A Document binds together all the functionality.
+	It can be saved, loaded, and printed to the screen.
+	All Nodes are connected and allocated to a Document.
+	If the Document is deleted, all its Nodes are also deleted.
+*/
+class XMLDocument : public XMLNode
+{
+    friend class XMLElement;
+public:
+    /// constructor
+    XMLDocument( bool processEntities = true, Whitespace = PRESERVE_WHITESPACE );
+    ~XMLDocument();
+
+    virtual XMLDocument* ToDocument()				{
+        return this;
+    }
+    virtual const XMLDocument* ToDocument() const	{
+        return this;
+    }
+
+    /**
+    	Parse an XML file from a character string.
+    	Returns XML_NO_ERROR (0) on success, or
+    	an errorID.
+
+    	You may optionally pass in the 'nBytes', which is
+    	the number of bytes which will be parsed. If not
+    	specified, TinyXML will assume 'xml' points to a
+    	null terminated string.
+    */
+    XMLError Parse( const char* xml, size_t nBytes=(size_t)(-1) );
+
+    /**
+    	Load an XML file from disk.
+    	Returns XML_NO_ERROR (0) on success, or
+    	an errorID.
+    */
+    XMLError LoadFile( const char* filename );
+
+    /**
+    	Load an XML file from disk. You are responsible
+    	for providing and closing the FILE*.
+
+    	Returns XML_NO_ERROR (0) on success, or
+    	an errorID.
+    */
+    XMLError LoadFile( FILE* );
+
+    /**
+    	Save the XML file to disk.
+    	Returns XML_NO_ERROR (0) on success, or
+    	an errorID.
+    */
+    XMLError SaveFile( const char* filename, bool compact = false );
+
+    /**
+    	Save the XML file to disk. You are responsible
+    	for providing and closing the FILE*.
+
+    	Returns XML_NO_ERROR (0) on success, or
+    	an errorID.
+    */
+    XMLError SaveFile( FILE* fp, bool compact = false );
+
+    bool ProcessEntities() const		{
+        return _processEntities;
+    }
+    Whitespace WhitespaceMode() const	{
+        return _whitespace;
+    }
+
+    /**
+    	Returns true if this document has a leading Byte Order Mark of UTF8.
+    */
+    bool HasBOM() const {
+        return _writeBOM;
+    }
+    /** Sets whether to write the BOM when writing the file.
+    */
+    void SetBOM( bool useBOM ) {
+        _writeBOM = useBOM;
+    }
+
+    /** Return the root element of DOM. Equivalent to FirstChildElement().
+        To get the first node, use FirstChild().
+    */
+    XMLElement* RootElement()				{
+        return FirstChildElement();
+    }
+    const XMLElement* RootElement() const	{
+        return FirstChildElement();
+    }
+
+    /** Print the Document. If the Printer is not provided, it will
+        print to stdout. If you provide Printer, this can print to a file:
+    	@verbatim
+    	XMLPrinter printer( fp );
+    	doc.Print( &printer );
+    	@endverbatim
+
+    	Or you can use a printer to print to memory:
+    	@verbatim
+    	XMLPrinter printer;
+    	doc->Print( &printer );
+    	// printer.CStr() has a const char* to the XML
+    	@endverbatim
+    */
+    void Print( XMLPrinter* streamer=0 );
+    virtual bool Accept( XMLVisitor* visitor ) const;
+
+    /**
+    	Create a new Element associated with
+    	this Document. The memory for the Element
+    	is managed by the Document.
+    */
+    XMLElement* NewElement( const char* name );
+    /**
+    	Create a new Comment associated with
+    	this Document. The memory for the Comment
+    	is managed by the Document.
+    */
+    XMLComment* NewComment( const char* comment );
+    /**
+    	Create a new Text associated with
+    	this Document. The memory for the Text
+    	is managed by the Document.
+    */
+    XMLText* NewText( const char* text );
+    /**
+    	Create a new Declaration associated with
+    	this Document. The memory for the object
+    	is managed by the Document.
+
+    	If the 'text' param is null, the standard
+    	declaration is used.:
+    	@verbatim
+    		<?xml version="1.0" encoding="UTF-8"?>
+    	@endverbatim
+    */
+    XMLDeclaration* NewDeclaration( const char* text=0 );
+    /**
+    	Create a new Unknown associated with
+    	this Document. The memory for the object
+    	is managed by the Document.
+    */
+    XMLUnknown* NewUnknown( const char* text );
+
+    /**
+    	Delete a node associated with this document.
+    	It will be unlinked from the DOM.
+    */
+    void DeleteNode( XMLNode* node )	{
+        node->_parent->DeleteChild( node );
+    }
+
+    void SetError( XMLError error, const char* str1, const char* str2 );
+
+    /// Return true if there was an error parsing the document.
+    bool Error() const {
+        return _errorID != XML_NO_ERROR;
+    }
+    /// Return the errorID.
+    XMLError  ErrorID() const {
+        return _errorID;
+    }
+    /// Return a possibly helpful diagnostic location or string.
+    const char* GetErrorStr1() const {
+        return _errorStr1;
+    }
+    /// Return a possibly helpful secondary diagnostic location or string.
+    const char* GetErrorStr2() const {
+        return _errorStr2;
+    }
+    /// If there is an error, print it to stdout.
+    void PrintError() const;
+    
+    /// Clear the document, resetting it to the initial state.
+    void Clear();
+
+    // internal
+    char* Identify( char* p, XMLNode** node );
+
+    virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const	{
+        return 0;
+    }
+    virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const	{
+        return false;
+    }
+
+private:
+    XMLDocument( const XMLDocument& );	// not supported
+    void operator=( const XMLDocument& );	// not supported
+
+    bool        _writeBOM;
+    bool        _processEntities;
+    XMLError    _errorID;
+    Whitespace  _whitespace;
+    const char* _errorStr1;
+    const char* _errorStr2;
+    char*       _charBuffer;
+
+    MemPoolT< sizeof(XMLElement) >	 _elementPool;
+    MemPoolT< sizeof(XMLAttribute) > _attributePool;
+    MemPoolT< sizeof(XMLText) >		 _textPool;
+    MemPoolT< sizeof(XMLComment) >	 _commentPool;
+};
+
+
+/**
+	A XMLHandle is a class that wraps a node pointer with null checks; this is
+	an incredibly useful thing. Note that XMLHandle is not part of the TinyXML
+	DOM structure. It is a separate utility class.
+
+	Take an example:
+	@verbatim
+	<Document>
+		<Element attributeA = "valueA">
+			<Child attributeB = "value1" />
+			<Child attributeB = "value2" />
+		</Element>
+	</Document>
+	@endverbatim
+
+	Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very
+	easy to write a *lot* of code that looks like:
+
+	@verbatim
+	XMLElement* root = document.FirstChildElement( "Document" );
+	if ( root )
+	{
+		XMLElement* element = root->FirstChildElement( "Element" );
+		if ( element )
+		{
+			XMLElement* child = element->FirstChildElement( "Child" );
+			if ( child )
+			{
+				XMLElement* child2 = child->NextSiblingElement( "Child" );
+				if ( child2 )
+				{
+					// Finally do something useful.
+	@endverbatim
+
+	And that doesn't even cover "else" cases. XMLHandle addresses the verbosity
+	of such code. A XMLHandle checks for null pointers so it is perfectly safe
+	and correct to use:
+
+	@verbatim
+	XMLHandle docHandle( &document );
+	XMLElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild().NextSibling().ToElement();
+	if ( child2 )
+	{
+		// do something useful
+	@endverbatim
+
+	Which is MUCH more concise and useful.
+
+	It is also safe to copy handles - internally they are nothing more than node pointers.
+	@verbatim
+	XMLHandle handleCopy = handle;
+	@endverbatim
+
+	See also XMLConstHandle, which is the same as XMLHandle, but operates on const objects.
+*/
+class 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;
+    }
+    /// Create a handle from a node.
+    XMLHandle( XMLNode& node )												{
+        _node = &node;
+    }
+    /// Copy constructor
+    XMLHandle( const XMLHandle& ref )										{
+        _node = ref._node;
+    }
+    /// Assignment
+    XMLHandle& operator=( const XMLHandle& ref )							{
+        _node = ref._node;
+        return *this;
+    }
+
+    /// Get the first child of this handle.
+    XMLHandle FirstChild() 													{
+        return XMLHandle( _node ? _node->FirstChild() : 0 );
+    }
+    /// Get the first child element of this handle.
+    XMLHandle FirstChildElement( const char* value=0 )						{
+        return XMLHandle( _node ? _node->FirstChildElement( value ) : 0 );
+    }
+    /// Get the last child of this handle.
+    XMLHandle LastChild()													{
+        return XMLHandle( _node ? _node->LastChild() : 0 );
+    }
+    /// Get the last child element of this handle.
+    XMLHandle LastChildElement( const char* _value=0 )						{
+        return XMLHandle( _node ? _node->LastChildElement( _value ) : 0 );
+    }
+    /// Get the previous sibling of this handle.
+    XMLHandle PreviousSibling()												{
+        return XMLHandle( _node ? _node->PreviousSibling() : 0 );
+    }
+    /// Get the previous sibling element of this handle.
+    XMLHandle PreviousSiblingElement( const char* _value=0 )				{
+        return XMLHandle( _node ? _node->PreviousSiblingElement( _value ) : 0 );
+    }
+    /// Get the next sibling of this handle.
+    XMLHandle NextSibling()													{
+        return XMLHandle( _node ? _node->NextSibling() : 0 );
+    }
+    /// Get the next sibling element of this handle.
+    XMLHandle NextSiblingElement( const char* _value=0 )					{
+        return XMLHandle( _node ? _node->NextSiblingElement( _value ) : 0 );
+    }
+
+    /// Safe cast to XMLNode. This can return null.
+    XMLNode* ToNode()							{
+        return _node;
+    }
+    /// Safe cast to XMLElement. This can return null.
+    XMLElement* ToElement() 					{
+        return ( ( _node && _node->ToElement() ) ? _node->ToElement() : 0 );
+    }
+    /// Safe cast to XMLText. This can return null.
+    XMLText* ToText() 							{
+        return ( ( _node && _node->ToText() ) ? _node->ToText() : 0 );
+    }
+    /// Safe cast to XMLUnknown. This can return null.
+    XMLUnknown* ToUnknown() 					{
+        return ( ( _node && _node->ToUnknown() ) ? _node->ToUnknown() : 0 );
+    }
+    /// Safe cast to XMLDeclaration. This can return null.
+    XMLDeclaration* ToDeclaration() 			{
+        return ( ( _node && _node->ToDeclaration() ) ? _node->ToDeclaration() : 0 );
+    }
+
+private:
+    XMLNode* _node;
+};
+
+
+/**
+	A variant of the XMLHandle class for working with const XMLNodes and Documents. It is the
+	same in all regards, except for the 'const' qualifiers. See XMLHandle for API.
+*/
+class XMLConstHandle
+{
+public:
+    XMLConstHandle( const XMLNode* node )											{
+        _node = node;
+    }
+    XMLConstHandle( const XMLNode& node )											{
+        _node = &node;
+    }
+    XMLConstHandle( const XMLConstHandle& ref )										{
+        _node = ref._node;
+    }
+
+    XMLConstHandle& operator=( const XMLConstHandle& ref )							{
+        _node = ref._node;
+        return *this;
+    }
+
+    const XMLConstHandle FirstChild() const											{
+        return XMLConstHandle( _node ? _node->FirstChild() : 0 );
+    }
+    const XMLConstHandle FirstChildElement( const char* value=0 ) const				{
+        return XMLConstHandle( _node ? _node->FirstChildElement( value ) : 0 );
+    }
+    const XMLConstHandle LastChild()	const										{
+        return XMLConstHandle( _node ? _node->LastChild() : 0 );
+    }
+    const XMLConstHandle LastChildElement( const char* _value=0 ) const				{
+        return XMLConstHandle( _node ? _node->LastChildElement( _value ) : 0 );
+    }
+    const XMLConstHandle PreviousSibling() const									{
+        return XMLConstHandle( _node ? _node->PreviousSibling() : 0 );
+    }
+    const XMLConstHandle PreviousSiblingElement( const char* _value=0 ) const		{
+        return XMLConstHandle( _node ? _node->PreviousSiblingElement( _value ) : 0 );
+    }
+    const XMLConstHandle NextSibling() const										{
+        return XMLConstHandle( _node ? _node->NextSibling() : 0 );
+    }
+    const XMLConstHandle NextSiblingElement( const char* _value=0 ) const			{
+        return XMLConstHandle( _node ? _node->NextSiblingElement( _value ) : 0 );
+    }
+
+
+    const XMLNode* ToNode() const				{
+        return _node;
+    }
+    const XMLElement* ToElement() const			{
+        return ( ( _node && _node->ToElement() ) ? _node->ToElement() : 0 );
+    }
+    const XMLText* ToText() const				{
+        return ( ( _node && _node->ToText() ) ? _node->ToText() : 0 );
+    }
+    const XMLUnknown* ToUnknown() const			{
+        return ( ( _node && _node->ToUnknown() ) ? _node->ToUnknown() : 0 );
+    }
+    const XMLDeclaration* ToDeclaration() const	{
+        return ( ( _node && _node->ToDeclaration() ) ? _node->ToDeclaration() : 0 );
+    }
+
+private:
+    const XMLNode* _node;
+};
+
+
+/**
+	Printing functionality. The XMLPrinter gives you more
+	options than the XMLDocument::Print() method.
+
+	It can:
+	-# Print to memory.
+	-# Print to a file you provide.
+	-# Print XML without a XMLDocument.
+
+	Print to Memory
+
+	@verbatim
+	XMLPrinter printer;
+	doc->Print( &printer );
+	SomeFunction( printer.CStr() );
+	@endverbatim
+
+	Print to a File
+
+	You provide the file pointer.
+	@verbatim
+	XMLPrinter printer( fp );
+	doc.Print( &printer );
+	@endverbatim
+
+	Print without a XMLDocument
+
+	When loading, an XML parser is very useful. However, sometimes
+	when saving, it just gets in the way. The code is often set up
+	for streaming, and constructing the DOM is just overhead.
+
+	The Printer supports the streaming case. The following code
+	prints out a trivially simple XML file without ever creating
+	an XML document.
+
+	@verbatim
+	XMLPrinter printer( fp );
+	printer.OpenElement( "foo" );
+	printer.PushAttribute( "foo", "bar" );
+	printer.CloseElement();
+	@endverbatim
+*/
+class XMLPrinter : public XMLVisitor
+{
+public:
+    /** 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 );
+    ~XMLPrinter()	{}
+
+    /** If streaming, write the BOM and declaration. */
+    void PushHeader( bool writeBOM, bool writeDeclaration );
+    /** If streaming, start writing an element.
+        The element must be closed with CloseElement()
+    */
+    void OpenElement( const char* name );
+    /// If streaming, add an attribute to an open element.
+    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, bool value );
+    void PushAttribute( const char* name, double value );
+    /// If streaming, close the Element.
+    void CloseElement();
+
+    /// Add a text node.
+    void PushText( const char* text, bool cdata=false );
+    /// Add a text node from an integer.
+    void PushText( int value );
+    /// Add a text node from an unsigned.
+    void PushText( unsigned value );
+    /// Add a text node from a bool.
+    void PushText( bool value );
+    /// Add a text node from a float.
+    void PushText( float value );
+    /// Add a text node from a double.
+    void PushText( double value );
+
+    /// Add a comment
+    void PushComment( const char* comment );
+
+    void PushDeclaration( const char* value );
+    void PushUnknown( const char* value );
+
+    virtual bool VisitEnter( const XMLDocument& /*doc*/ );
+    virtual bool VisitExit( const XMLDocument& /*doc*/ )			{
+        return true;
+    }
+
+    virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute );
+    virtual bool VisitExit( const XMLElement& element );
+
+    virtual bool Visit( const XMLText& text );
+    virtual bool Visit( const XMLComment& comment );
+    virtual bool Visit( const XMLDeclaration& declaration );
+    virtual bool Visit( const XMLUnknown& unknown );
+
+    /**
+    	If in print to memory mode, return a pointer to
+    	the XML file in memory.
+    */
+    const char* CStr() const {
+        return _buffer.Mem();
+    }
+    /**
+    	If in print to memory mode, return the size
+    	of the XML file in memory. (Note the size returned
+    	includes the terminating null.)
+    */
+    int CStrSize() const {
+        return _buffer.Size();
+    }
+
+private:
+    void SealElement();
+    void PrintSpace( int depth );
+    void PrintString( const char*, bool restrictedEntitySet );	// prints out, after detecting entities.
+    void Print( const char* format, ... );
+
+    bool _elementJustOpened;
+    bool _firstElement;
+    FILE* _fp;
+    int _depth;
+    int _textDepth;
+    bool _processEntities;
+    bool _compactMode;
+
+    enum {
+        ENTITY_RANGE = 64,
+        BUF_SIZE = 200
+    };
+    bool _entityFlag[ENTITY_RANGE];
+    bool _restrictedEntityFlag[ENTITY_RANGE];
+
+    DynArray< const char*, 10 > _stack;
+    DynArray< char, 20 > _buffer;
+#ifdef _MSC_VER
+    DynArray< char, 20 > _accumulator;
+#endif
+};
+
+
+}	// tinyxml2
+
+
+#endif // TINYXML2_INCLUDED