]> Creatis software - cpPlugins.git/commitdiff
XML IO added. Workspace singleton added to simplify pipeline definition and execution.
authorLeonardo Florez-Valencia <florez-l@javeriana.edu.co>
Fri, 27 Nov 2015 23:01:59 +0000 (18:01 -0500)
committerLeonardo Florez-Valencia <florez-l@javeriana.edu.co>
Fri, 27 Nov 2015 23:01:59 +0000 (18:01 -0500)
18 files changed:
appli/examples/CMakeLists.txt
appli/examples/example_WorkspaceSandBox.cxx [new file with mode: 0644]
data/workspace_00.xml [new file with mode: 0644]
lib/cpPlugins/Interface/CMakeLists.txt
lib/cpPlugins/Interface/ProcessObject.cxx
lib/cpPlugins/Interface/Workspace.cxx [new file with mode: 0644]
lib/cpPlugins/Interface/Workspace.h [new file with mode: 0644]
lib/cpPlugins/Interface/WorkspaceIO.cxx [new file with mode: 0644]
lib/third_party/CMakeLists.txt
lib/third_party/tinyxml/CMakeLists.txt [new file with mode: 0644]
lib/third_party/tinyxml/changes.txt [new file with mode: 0644]
lib/third_party/tinyxml/readme.txt [new file with mode: 0644]
lib/third_party/tinyxml/tinystr.cpp [new file with mode: 0644]
lib/third_party/tinyxml/tinystr.h [new file with mode: 0644]
lib/third_party/tinyxml/tinyxml.cpp [new file with mode: 0644]
lib/third_party/tinyxml/tinyxml.h [new file with mode: 0644]
lib/third_party/tinyxml/tinyxmlerror.cpp [new file with mode: 0644]
lib/third_party/tinyxml/tinyxmlparser.cpp [new file with mode: 0644]

index 3292dd83d08ff0a8a1e4819fe401a0b83bd479a7..9938095c1f875fb542428356ca3240383905e8fc 100644 (file)
@@ -17,6 +17,7 @@ SET(
   example_TestParameters
   example_LoadPlugins
   example_LoadPluginsFromPath
+  example_WorkspaceSandBox
   )
 
 FOREACH(prog ${EXAMPLES_PROGRAMS_ONLY_INTERFACE}) 
diff --git a/appli/examples/example_WorkspaceSandBox.cxx b/appli/examples/example_WorkspaceSandBox.cxx
new file mode 100644 (file)
index 0000000..3cff6eb
--- /dev/null
@@ -0,0 +1,35 @@
+#include <cstdlib>
+#include <iostream>
+#include <cpPlugins/Interface/Workspace.h>
+
+#include <tinyxml/tinyxml.h>
+
+int main( int argc, char* argv[] )
+{
+  if( argc < 2 )
+  {
+    std::cerr
+      << "Usage: " << argv[ 0 ] << " filename" << std::endl;
+    return( 1 );
+  }
+  std::string filename = argv[ 1 ];
+
+  // Load workspace
+  cpPlugins::Interface::Workspace ws;
+  std::string err = ws.LoadWorkspace( filename );
+  if( err != "" )
+    std::cout
+      << "Errors caught while loading workspace: "
+      << std::endl << err << std::endl;
+
+  err = ws.Execute( );
+  if( err != "" )
+  {
+    std::cerr << "Error caught: " << std::endl << err << std::endl;
+    return( 1 );
+
+  } // fi
+  return( 0 );
+}
+
+// eof - $RCSfile$
diff --git a/data/workspace_00.xml b/data/workspace_00.xml
new file mode 100644 (file)
index 0000000..7f85219
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" ?>
+<cpPlugins_Workspace>
+  <plugins_dir path="/home/leonardo/devel/cpPlugins/build" recursive="0"/>
+  <filter class="cpPlugins::IO::ImageReader" name="reader">
+    <parameter name="FileNames" type="StringList">
+      <item value="test.mhd" />
+    </parameter>
+    <parameter name="VectorType" type="Bool" value="0"/>
+  </filter>
+  <filter class="cpPlugins::IO::ImageWriter" name="writer">
+    <parameter name="FileName" type="String" value="new_test.mhd"/>
+  </filter>
+  <connection>
+    <origin filter="reader" name="Output"/>
+    <destination filter="writer" name="Input"/>
+  </connection>
+</cpPlugins_Workspace>
index 406f86fc6994824e6b980d463955562d93ef4bb4..ae572ccf77f142e5accb72bf24e20f307c4182b2 100644 (file)
@@ -80,6 +80,7 @@ GENERATE_EXPORT_HEADER(
   )
 TARGET_LINK_LIBRARIES(
   ${LIBRARY_NAME}
+  cpPlugins_tinyxml
   cpPlugins_Pluma
   ${QT_LIBRARIES}
   ${ITK_LIBRARIES}
index 7552e5e1dea890027ee644926240d7ccb66a7cb3..efd2bca6fcf5da5311f17568155a1c0507c82953 100644 (file)
@@ -78,10 +78,15 @@ Update( )
   _TDataContainer::iterator i = this->m_Inputs.begin( );
   for( ; i != this->m_Inputs.end( ) && r == ""; ++i )
   {
-    Self* src = dynamic_cast< Self* >( i->second->GetSource( ) );
-    if( src != NULL )
-      r = src->Update( );
-
+    if( i->second.IsNotNull( ) )
+    {
+      Self* src = dynamic_cast< Self* >( i->second->GetSource( ) );
+      if( src != NULL )
+        r = src->Update( );
+    }
+    else
+      r = "cpPlugins::Interface::ProcessObject: No input connected.";
+    
   } // rof
 
   // Current update
diff --git a/lib/cpPlugins/Interface/Workspace.cxx b/lib/cpPlugins/Interface/Workspace.cxx
new file mode 100644 (file)
index 0000000..9e8d4e1
--- /dev/null
@@ -0,0 +1,262 @@
+#include <cpPlugins/Interface/Workspace.h>
+
+// -------------------------------------------------------------------------
+cpPlugins::Interface::Workspace::
+Workspace( )
+  : m_LastLoadedPlugin( "" )
+{
+}
+
+// -------------------------------------------------------------------------
+cpPlugins::Interface::Workspace::
+~Workspace( )
+{
+}
+
+// -------------------------------------------------------------------------
+bool cpPlugins::Interface::Workspace::
+LoadPluginsPath( const std::string& path, bool r )
+{
+  // Load all plugins from given folder
+  std::list< std::string > files =
+    this->m_Interface.LoadFromFolder( path, r );
+
+  // Update a simple track
+  bool ret = false;
+  if( files.size( ) > 0 )
+  {
+    for( auto fIt = files.begin( ); fIt != files.end( ); ++fIt )
+    {
+      this->m_LoadedPlugins.insert( *fIt );
+      this->m_LastLoadedPlugin = *fIt;
+
+    } // rof
+    this->_UpdateLoadedPluginsInformation( );
+    ret = true;
+
+  } // fi
+  return( ret );
+}
+
+// -------------------------------------------------------------------------
+bool cpPlugins::Interface::Workspace::
+LoadPlugins( const std::string& fname )
+{
+  // Is it already loaded?
+  bool ret = true;
+  if( this->m_LoadedPlugins.find( fname ) == this->m_LoadedPlugins.end( ) )
+  {
+    // Was it succesfully loaded?
+    ret = this->m_Interface.Load( fname );
+
+    // Update a simple track
+    if( ret )
+    {
+      this->m_LoadedPlugins.insert( fname );
+      this->m_LastLoadedPlugin = fname;
+      this->_UpdateLoadedPluginsInformation( );
+
+    } // fi
+
+  } // fi
+  return( ret );
+}
+
+// -------------------------------------------------------------------------
+const cpPlugins::Interface::Workspace::
+TStringContainer& cpPlugins::Interface::Workspace::
+GetLoadedPlugins( ) const
+{
+  return( this->m_LoadedPlugins );
+}
+
+// -------------------------------------------------------------------------
+void cpPlugins::Interface::Workspace::
+GetLoadedPluginCategories( TStringContainer& categories ) const
+{
+  categories.clear( );
+  auto fIt = this->m_LoadedFilters.begin( );
+  for( ; fIt != this->m_LoadedFilters.end( ); ++fIt )
+    categories.insert( fIt->first );
+}
+
+// -------------------------------------------------------------------------
+void cpPlugins::Interface::Workspace::
+GetLoadedPluginFilters( TStringContainer& filters ) const
+{
+  filters.clear( );
+  auto pIt = this->m_LoadedFilters.begin( );
+  for( ; pIt != this->m_LoadedFilters.end( ); ++pIt )
+    for( auto fIt = pIt->second.begin( ); fIt != pIt->second.end( ); ++fIt )
+      filters.insert( *fIt );
+}
+
+// -------------------------------------------------------------------------
+const cpPlugins::Interface::Workspace::
+TStringContainer& cpPlugins::Interface::Workspace::
+GetLoadedPluginFilters( const std::string& category ) const
+{
+  static const TStringContainer EMPTY;
+  auto pIt = this->m_LoadedFilters.find( category );
+  if( pIt != this->m_LoadedFilters.end( ) )
+    return( pIt->second );
+  else
+    return( EMPTY );
+}
+
+// -------------------------------------------------------------------------
+bool cpPlugins::Interface::Workspace::
+CreateFilter( const std::string& filter, const std::string& name )
+{
+  // Get or create new filter from name
+  auto vIt = this->m_Vertices.find( name );
+  if( vIt == this->m_Vertices.end( ) )
+  {
+    TFilter::Pointer o = this->m_Interface.CreateObject( filter );
+    if( o.IsNotNull( ) )
+    {
+      o->SetName( name );
+      this->m_Vertices[ name ] = o;
+      return( true );
+    }
+    else
+      return( false );
+  }
+  else
+    return( true );
+}
+
+// -------------------------------------------------------------------------
+bool cpPlugins::Interface::Workspace::
+Connect(
+  const std::string& orig_filter, const std::string& dest_filter,
+  const std::string& output_name, const std::string& input_name
+  )
+{
+  // Get filters
+  auto oIt = this->m_Vertices.find( orig_filter );
+  if( oIt == this->m_Vertices.end( ) )
+    return( false );
+  auto dIt = this->m_Vertices.find( dest_filter );
+  if( dIt == this->m_Vertices.end( ) )
+    return( false );
+  TFilter* orig = dynamic_cast< TFilter* >( oIt->second.GetPointer( ) );
+  TFilter* dest = dynamic_cast< TFilter* >( dIt->second.GetPointer( ) );
+  if( orig == NULL || dest == NULL )
+    return( false );
+
+  // Real connection
+  dest->SetInput( input_name, orig->GetOutput< TData >( output_name ) );
+  this->m_AdjMatrix[ orig_filter ][ dest_filter ].push_back(
+    TConnection( output_name, input_name )
+    );
+  return( false );
+}
+
+// -------------------------------------------------------------------------
+cpPlugins::Interface::Workspace::
+TParameters* cpPlugins::Interface::Workspace::
+GetParameters( const std::string& name )
+{
+  auto vIt = this->m_Vertices.find( name );
+  if( vIt != this->m_Vertices.end( ) )
+  {
+    TFilter* f = dynamic_cast< TFilter* >( vIt->second.GetPointer( ) );
+    if( f != NULL )
+      return( f->GetParameters( ) );
+    else
+      return( NULL );
+  }
+  else
+    return( NULL );
+}
+
+// -------------------------------------------------------------------------
+const cpPlugins::Interface::Workspace::
+TParameters* cpPlugins::Interface::Workspace::
+GetParameters( const std::string& name ) const
+{
+  auto vIt = this->m_Vertices.find( name );
+  if( vIt != this->m_Vertices.end( ) )
+  {
+    const TFilter* f =
+      dynamic_cast< const TFilter* >( vIt->second.GetPointer( ) );
+    if( f != NULL )
+      return( f->GetParameters( ) );
+    else
+      return( NULL );
+  }
+  else
+    return( NULL );
+}
+
+// -------------------------------------------------------------------------
+bool cpPlugins::Interface::Workspace::
+Reduce( const std::string& name )
+{
+}
+
+// -------------------------------------------------------------------------
+std::string cpPlugins::Interface::Workspace::
+Execute( )
+{
+  // Find sinks
+  std::set< std::string > sinks;
+  auto vIt = this->m_Vertices.begin( );
+  for( ; vIt != this->m_Vertices.end( ); ++vIt )
+    sinks.insert( vIt->first );
+  auto mIt = this->m_AdjMatrix.begin( );
+  for( ; mIt != this->m_AdjMatrix.end( ); ++mIt )
+    sinks.erase( mIt->first );
+
+  // Update sinks
+  std::string err = "";
+  for( auto sIt = sinks.begin( ); sIt != sinks.end( ); ++sIt )
+  {
+    std::string lerr = this->Execute( *sIt );
+    if( lerr != "" )
+      err += lerr + std::string( "\n" );
+
+  } // rof
+  return( err );
+}
+
+// -------------------------------------------------------------------------
+std::string cpPlugins::Interface::Workspace::
+Execute( const std::string& name )
+{
+  // Get filter
+  auto vIt = this->m_Vertices.find( name );
+  if( vIt == this->m_Vertices.end( ) )
+    return(
+      std::string( "cpPlugins::Interface::Workspace: No filter \"" ) +
+      name + std::string( "\"" )
+      );
+  TFilter* f = dynamic_cast< TFilter* >( vIt->second.GetPointer( ) );
+  if( f == NULL )
+    return(
+      std::string( "cpPlugins::Interface::Workspace: Vertex \"" ) +
+      name + std::string( "\" is not a filter." )
+      );
+
+  // Execute and return
+  return( f->Update( ) );
+}
+
+// -------------------------------------------------------------------------
+void cpPlugins::Interface::Workspace::
+_UpdateLoadedPluginsInformation( )
+{
+  this->m_LoadedFilters.clear( );
+  const TInterface::TClasses& cls = this->m_Interface.GetClasses( );
+  for( auto i = cls.begin( ); i != cls.end( ); ++i )
+  {
+    TFilter::Pointer o = this->m_Interface.CreateObject( i->first );
+    std::string name = o->GetClassName( );
+    std::string category = o->GetClassCategory( );
+    this->m_LoadedFilters[ category ].insert( name );
+
+  } // rof
+}
+
+// eof - $RCSfile$
diff --git a/lib/cpPlugins/Interface/Workspace.h b/lib/cpPlugins/Interface/Workspace.h
new file mode 100644 (file)
index 0000000..863d84e
--- /dev/null
@@ -0,0 +1,93 @@
+#ifndef __CPPLUGINS__INTERFACE__WORKSPACE__H__
+#define __CPPLUGINS__INTERFACE__WORKSPACE__H__
+
+#include <cpPlugins/Interface/Interface.h>
+#include <cpPlugins/Interface/DataObject.h>
+#include <cpPlugins/Interface/ProcessObject.h>
+
+#include <map>
+#include <set>
+#include <string>
+
+namespace cpPlugins
+{
+  namespace Interface
+  {
+    /**
+     */
+    class cpPlugins_Interface_EXPORT Workspace
+    {
+    public:
+      typedef cpPlugins::Interface::Interface     TInterface;
+      typedef cpPlugins::Interface::Object        TObject;
+      typedef cpPlugins::Interface::ProcessObject TFilter;
+      typedef cpPlugins::Interface::DataObject    TData;
+      typedef TFilter::TParameters                TParameters;
+
+      // Various types
+      typedef std::set< std::string > TStringContainer;
+
+      // Graph types
+      typedef std::map< std::string, TObject::Pointer > TVertices;
+      typedef std::pair< std::string, std::string >     TConnection;
+      typedef std::vector< TConnection >                TConnections;
+      typedef std::map< std::string, TConnections >     TAdjMatrixRow;
+      typedef std::map< std::string, TAdjMatrixRow >    TAdjMatrix;
+
+    public:
+      Workspace( );
+      virtual ~Workspace( );
+
+      // Plugins management
+      bool LoadPluginsPath( const std::string& path, bool r = false );
+      bool LoadPlugins( const std::string& fname );
+      const TStringContainer& GetLoadedPlugins( ) const;
+      void GetLoadedPluginCategories( TStringContainer& categories ) const;
+      void GetLoadedPluginFilters( TStringContainer& filters ) const;
+      const TStringContainer& GetLoadedPluginFilters(
+        const std::string& category
+        ) const;
+
+      // Workspace IO
+      std::string LoadWorkspace( const std::string& fname );
+      std::string SaveWorkspace( const std::string& fname ) const;
+
+      // Graph management
+      bool CreateFilter( const std::string& filter, const std::string& name );
+      bool Connect(
+        const std::string& orig_filter, const std::string& dest_filter,
+        const std::string& output_name,
+        const std::string& input_name
+        );
+      TParameters* GetParameters( const std::string& name );
+      const TParameters* GetParameters( const std::string& name ) const;
+
+      // Graph reduction
+      bool Reduce( const std::string& name );
+
+      // Pipeline execution
+      std::string Execute( );
+      std::string Execute( const std::string& name );
+
+    protected:
+      void _UpdateLoadedPluginsInformation( );
+
+    protected:
+      // Plugins interface
+      TInterface       m_Interface;
+      std::string      m_LastLoadedPlugin;
+      TStringContainer m_LoadedPlugins;
+      std::map< std::string, TStringContainer > m_LoadedFilters;
+
+      // Processing graph
+      TVertices  m_Vertices;
+      TAdjMatrix m_AdjMatrix;
+    };
+
+  } // ecapseman
+
+} // ecapseman
+
+#endif // __CPPLUGINS__INTERFACE__WORKSPACE__H__
+
+// eof - $RCSfile$
diff --git a/lib/cpPlugins/Interface/WorkspaceIO.cxx b/lib/cpPlugins/Interface/WorkspaceIO.cxx
new file mode 100644 (file)
index 0000000..0651011
--- /dev/null
@@ -0,0 +1,239 @@
+#include <cpPlugins/Interface/Workspace.h>
+#include <third_party/tinyxml/tinyxml.h>
+
+// -------------------------------------------------------------------------
+std::string cpPlugins::Interface::Workspace::
+LoadWorkspace( const std::string& fname )
+{
+  TiXmlDocument* doc = new TiXmlDocument( fname.c_str( ) );
+  doc->LoadFile( );
+  TiXmlElement* root = doc->RootElement( );
+  if( std::string( root->Value( ) ) != "cpPlugins_Workspace" )
+    return( "cpPlugins::Interface::Workspace: No valid workspace" );
+  std::stringstream err;
+
+  // Read plugins files
+  TiXmlElement* plugins = root->FirstChildElement( "plugins" );
+  while( plugins != NULL )
+  {
+    const char* value = plugins->Attribute( "filename" );
+    if( value != NULL )
+    {
+      if( !( this->LoadPlugins( value ) ) )
+        err << "no valid plugins file \"" << value << "\"" << std::endl;
+
+    } // fi
+    plugins = plugins->NextSiblingElement( "plugins" );
+
+  } // elihw
+
+  // Read plugins paths
+  plugins = root->FirstChildElement( "plugins_dir" );
+  while( plugins != NULL )
+  {
+    const char* value = plugins->Attribute( "path" );
+    if( value != NULL )
+    {
+      int recursive;
+      if( plugins->QueryIntAttribute( "recursive", &recursive ) != TIXML_SUCCESS )
+        recursive = 0;
+      if( !( this->LoadPluginsPath( value, recursive == 1 ) ) )
+        err << "No valid plugins path \"" << value << "\"" << std::endl;
+
+    } // fi
+    plugins = plugins->NextSiblingElement( "plugins_dir" );
+
+  } // elihw
+
+  // Read filters
+  TiXmlElement* filter = root->FirstChildElement( "filter" );
+  while( filter != NULL )
+  {
+    const char* class_value = filter->Attribute( "class" );
+    const char* name_value = filter->Attribute( "name" );
+    if( class_value != NULL && name_value != NULL )
+    {
+      if( this->CreateFilter( class_value, name_value ) )
+      {
+        // Read parameters
+        TParameters* parameters = this->GetParameters( name_value );
+        TiXmlElement* param = filter->FirstChildElement( "parameter" );
+        while( param != NULL )
+        {
+          const char* param_name = param->Attribute( "name" );
+          const char* param_type = param->Attribute( "type" );
+          if( param_name != NULL && param_type != NULL )
+          {
+            std::string param_type_str( param_type );
+            const char* value = param->Attribute( "value" );
+            if( value != NULL )
+            {
+              std::istringstream value_str( value );
+              if( param_type_str == "String" )
+                parameters->SetString( param_name, value );
+              else if( param_type_str == "Bool" )
+                parameters->SetBool( param_name, value[ 0 ] != '0' );
+              else if( param_type_str == "Int" )
+              {
+                TParameters::TInt v;
+                value_str >> v;
+                parameters->SetInt( param_name, v );
+              }
+              else if( param_type_str == "Uint" )
+              {
+                TParameters::TUint v;
+                value_str >> v;
+                parameters->SetUint( param_name, v );
+              }
+              else if( param_type_str == "Real" )
+              {
+                TParameters::TReal v;
+                value_str >> v;
+                parameters->SetReal( param_name, v );
+              }
+              /* TODO
+                 else if( param_type_str == "Index" )
+                 else if( param_type_str == "Point" )
+                 else if( param_type_str == "Vector" )
+              */
+            }
+            else
+            {
+              if( param_type_str == "StringList" )
+              {
+                TiXmlElement* item = param->FirstChildElement( "item" );
+                while( item != NULL )
+                {
+                  value = item->Attribute( "value" );
+                  if( value != NULL )
+                    parameters->AddToStringList( param_name, value );
+                  item = item->NextSiblingElement( "item" );
+
+                } // elihw
+              }
+              else if( param_type_str == "BoolList" )
+              {
+                TiXmlElement* item = param->FirstChildElement( "item" );
+                while( item != NULL )
+                {
+                  value = item->Attribute( "value" );
+                  if( value != NULL )
+                    parameters->AddToBoolList( param_name, value[ 0 ] != '0' );
+                  item = item->NextSiblingElement( "item" );
+
+                } // elihw
+              }
+              else if( param_type_str == "IntList" )
+              {
+                TiXmlElement* item = param->FirstChildElement( "item" );
+                while( item != NULL )
+                {
+                  value = item->Attribute( "value" );
+                  if( value != NULL )
+                  {
+                    std::istringstream value_str( value );
+                    TParameters::TInt v;
+                    value_str >> v;
+                    parameters->AddToIntList( param_name, v );
+
+                  } // fi
+                  item = item->NextSiblingElement( "item" );
+
+                } // elihw
+              }
+              else if( param_type_str == "UintList" )
+              {
+                TiXmlElement* item = param->FirstChildElement( "item" );
+                while( item != NULL )
+                {
+                  value = item->Attribute( "value" );
+                  if( value != NULL )
+                  {
+                    std::istringstream value_str( value );
+                    TParameters::TUint v;
+                    value_str >> v;
+                    parameters->AddToUintList( param_name, v );
+
+                  } // fi
+                  item = item->NextSiblingElement( "item" );
+
+                } // elihw
+              }
+              else if( param_type_str == "RealList" )
+              {
+                TiXmlElement* item = param->FirstChildElement( "item" );
+                while( item != NULL )
+                {
+                  value = item->Attribute( "value" );
+                  if( value != NULL )
+                  {
+                    std::istringstream value_str( value );
+                    TParameters::TReal v;
+                    value_str >> v;
+                    parameters->AddToRealList( param_name, v );
+
+                  } // fi
+                  item = item->NextSiblingElement( "item" );
+
+                } // elihw
+              }
+              /* TODO
+                 else if( param_type_str == "IndexList" )
+                 else if( param_type_str == "PointList" )
+                 else if( param_type_str == "VectorList" )
+                 else if( param_type_str == "Choices" );
+              */
+            } // fi
+
+          } // fi
+          param = param->NextSiblingElement( "parameter" );
+
+        } // elihw
+      }
+      else
+        err
+          << "No valid class \"" << class_value << "\" with name \""
+          << name_value << "\"" << std::endl;
+    }
+    else
+      err << "Incomplete data." << std::endl;
+    filter = filter->NextSiblingElement( "filter" );
+
+  } // elihw
+
+  // Read filters
+  TiXmlElement* connection = root->FirstChildElement( "connection" );
+  while( connection != NULL )
+  {
+    TiXmlElement* orig = connection->FirstChildElement( "origin" );
+    TiXmlElement* dest = connection->FirstChildElement( "destination" );
+    if( orig != NULL && dest != NULL )
+    {
+      const char* orig_filter = orig->Attribute( "filter" );
+      const char* dest_filter = dest->Attribute( "filter" );
+      const char* orig_name = orig->Attribute( "name" );
+      const char* dest_name = dest->Attribute( "name" );
+      if(
+        orig_filter != NULL && dest_filter != NULL &&
+        orig_name != NULL && dest_name != NULL
+        )
+        this->Connect( orig_filter, dest_filter, orig_name, dest_name );
+
+    } // fi
+    connection = connection->NextSiblingElement( "connection" );
+
+  } // elihw
+
+  // Finish and return
+  delete doc;
+  return( err.str( ) );
+}
+
+// -------------------------------------------------------------------------
+std::string cpPlugins::Interface::Workspace::
+SaveWorkspace( const std::string& fname ) const
+{
+  return( "" );
+}
+
+// eof - $RCSfile$
index af1194bf6509c1e48f15f82a7ae9c2324cf632df..c69ba0d9c08d3aee3d996a83232abac022caee93 100644 (file)
@@ -1,4 +1,5 @@
 SUBDIRS(
+  tinyxml
   Pluma
   )
 
diff --git a/lib/third_party/tinyxml/CMakeLists.txt b/lib/third_party/tinyxml/CMakeLists.txt
new file mode 100644 (file)
index 0000000..badc638
--- /dev/null
@@ -0,0 +1,26 @@
+SET(tinyxml_LIBRARY_NAME cpPlugins_tinyxml)
+
+## ===============
+## = Source code =
+## ===============
+
+FILE(GLOB tinyxml_HEADERS "*.h")
+FILE(GLOB tinyxml_SOURCES "*.cpp")
+
+## =====================
+## = Compilation rules =
+## =====================
+
+ADD_LIBRARY(
+  ${tinyxml_LIBRARY_NAME}
+  SHARED
+  ${tinyxml_SOURCES}
+  )
+GENERATE_EXPORT_HEADER(
+  ${tinyxml_LIBRARY_NAME}
+  BASE_NAME ${tinyxml_LIBRARY_NAME}
+  EXPORT_MACRO_NAME ${tinyxml_LIBRARY_NAME}_EXPORT
+  EXPORT_FILE_NAME ${PROJECT_BINARY_DIR}/lib/third_party/tinyxml/${tinyxml_LIBRARY_NAME}_Export.h
+  STATIC_DEFINE ${tinyxml_LIBRARY_NAME}_BUILT_AS_STATIC
+  )
+## eof - $RCSfile$
diff --git a/lib/third_party/tinyxml/changes.txt b/lib/third_party/tinyxml/changes.txt
new file mode 100644 (file)
index 0000000..1ea21ad
--- /dev/null
@@ -0,0 +1,290 @@
+Changes in version 1.0.1:
+- Fixed comment tags which were outputing as '<?--' instead of 
+  the correct '<!--'.
+- Implemented the Next and Prev methods of the TiXmlAttribute class.
+- Renamed 'LastAttribtute' to 'LastAttribute'
+- Fixed bad pointer to 'isspace' that could occur while parsing text.
+- Errors finding beginning and end of tags no longer throw it into an
+  infinite loop. (Hopefully.)
+
+Changes in version 1.0.2
+- Minor documentation fixes.
+
+Changes in version 1.0.3
+- After nodes are added to a document, they return a pointer
+  to the new node instead of a bool for success.
+- Elements can be constructed with a value, which is the
+  element name. Every element must have a value or it will be
+  invalid, but the code changes to enforce this are not fully
+  in place.
+
+Changes in version 1.1.0
+- Added the    TiXmlAttributeSet class to pull the attributes into
+  a seperate container.
+- Moved the doubly liked list out of XmlBase. Now XmlBase only
+  requires the Print() function and defines some utility functions.
+- Moved errors into a seperate file. (With the idea of internationalization
+  to the other latin-1 languages.)
+- Added the "NodeType"
+- Fixed white space parsing in text to conform with the standard. 
+  Basically, all white space becomes just one space.
+- Added the TiXmlDeclaration class to read xml declarations.
+
+Changes in version 1.2.0
+- Removed the factory. The factory was not really in the spirit 
+  of small and simple, confused the code, and was of limited value.
+- Added FirstChildElement and NextSiblingElement, because they
+  are such common functions.
+- Re-wrote the example to test and demonstrate more functionality.
+
+Changes in version 1.2.1
+- Fixed a bug where comments couldn't be inside elements.
+- Loading now clears out existing XML rather than appending.
+- Added the "Clear" method on a node to delete all its children.
+
+Changes in version 1.2.2
+- Fixed TiXmlAttribute::Previous actually returning "next." Thanks
+  to Rickard Troedsson for the bug fix.
+
+Changes in version 1.2.3
+- Added the TIXML prefix to the error strings to resolve conflicts
+  with #defines in OS headers. Thanks to Steve Lhomme.
+- Fixed a delete buf that should be a delete [] buf. 
+  Thanks to Ephi Sinowitz.
+
+Changes in version 1.2.4
+- ReplaceChild() was almost guarenteed to fail. Should be fixed,
+  thanks to Joe Smith. Joe also pointed out that the Print() functions
+  should take stream references: I agree, and would like to overload
+  the Print() method to take either format, but I don't want to do 
+  this in a dot release.
+- Some compilers seem to need an extra <ctype.h> include. Thanks
+  to Steve Lhomme for that.
+
+Changes in version 2.0.0 BETA
+- Made the ToXXX() casts safe if 'this' is null. 
+  When "LoadFile" is called with a filename, the value will correctly get set.
+  Thanks to Brian Yoder.
+- Fixed bug where isalpha() and isalnum() would get called with a negative value for 
+  high ascii numbers. Thanks to Alesky Aksenov.
+- Fixed some errors codes that were not getting set.
+- Made methods "const" that were not.
+- Added a switch to enable or disable the ignoring of white space. ( TiXmlDocument::SetIgnoreWhiteSpace() )
+- Greater standardization and code re-use in the parser.
+- Added a stream out operator.
+- Added a stream in operator.
+- Entity support, of predefined entites. &#x entities are untouched by input or output.
+- Improved text out formatting.
+- Fixed ReplaceChild bug, thanks to Tao Chen.
+
+Changes in version 2.0.1
+- Fixed hanging on loading a 0 length file. Thanks to Jeff Scozzafava.
+- Fixed crashing on InsertBeforeChild and InsertAfterChild. Also possibility of bad links being
+  created by same function. Thanks to Frank De prins.
+- Added missing licence text. Thanks to Lars Willemsens.
+- Added <ctype.h> include, at the suggestion of Steve Walters.
+
+Changes in version 2.1.0
+- Yves Berquin brings us the STL switch. The forum on SourceForge, and various emails to
+  me, have long debated all out STL vs. no STL at all. And now you can have it both ways.
+  TinyXml will compile either way.
+
+Changes in version 2.1.1
+- Compilation warnings.
+
+Changes in version 2.1.2
+- Uneeded code is not compiled in the STL case.
+- Changed headers so that STL can be turned on or off in tinyxml.h
+
+Changes in version 2.1.3
+- Fixed non-const reference in API; now uses a pointer.
+- Copy constructor of TiXmlString not checking for assignment to self.
+- Nimrod Cohen found a truly evil bug in the STL implementation that occurs
+  when a string is converted to a c_str and then assigned to self. Search for
+  STL_STRING_BUG for a full description. I'm asserting this is a Microsoft STL
+  bug, since &string and string.c_str() should never be the same. Nevertheless,
+  the code works around it.
+- Urivan Saaib pointed out a compiler conflict, where the C headers define
+  the isblank macro, which was wiping out the TiXmlString::isblank() method.
+  The method was unused and has been removed.
+
+Changes in version 2.1.4
+- Reworked the entity code. Entities were not correctly surving round trip input and output.
+  Will now automatically create entities for high ascii in output.
+
+Changes in version 2.1.5
+- Bug fix by kylotan : infinite loop on some input (tinyxmlparser.cpp rev 1.27)
+- Contributed by Ivica Aracic (bytelord) : 1 new VC++ project to compile versions as static libraries (tinyxml_lib.dsp), 
+  and an example usage in xmltest.dsp
+  (Patch request ID 678605)
+- A suggestion by Ronald Fenner Jr (dormlock) to add #include <istream> and <ostream> for Apple's Project Builder 
+  (Patch request ID 697642)
+- A patch from ohommes that allows to parse correctly dots in element names and attribute names
+  (Patch request 602600 and kylotan 701728)
+- A patch from  hermitgeek ( James ) and wasteland for improper error reporting
+- Reviewed by Lee, with the following changes:
+       - Got sick of fighting the STL/non-STL thing in the windows build. Broke
+         them out as seperate projects.
+       - I have too long not included the dsw. Added.
+       - TinyXmlText had a protected Print. Odd.
+       - Made LinkEndChild public, with docs and appropriate warnings.
+       - Updated the docs.
+
+2.2.0
+- Fixed an uninitialized pointer in the TiXmlAttributes
+- Fixed STL compilation problem in MinGW (and gcc 3?) - thanks Brian Yoder for finding this one
+- Fixed a syntax error in TiXmlDeclaration - thanks Brian Yoder
+- Fletcher Dunn proposed and submitted new error handling that tracked the row and column. Lee
+  modified it to not have performance impact.
+- General cleanup suggestions from Fletcher Dunn.
+- In error handling, general errors will no longer clear the error state of specific ones.
+- Fix error in documentation : comments starting with "<?--" instead of "<!--" (thanks ion_pulse)
+- Added the TiXmlHandle. An easy, safe way to browse XML DOMs with less code.
+- Added QueryAttribute calls which have better error messaging. (Proposed by Fletcher Dunn)
+- Nodes and attributes can now print themselves to strings. (Yves suggestion)
+- Fixed bug where entities with one character would confuse parser. (Thanks Roman)
+
+2.2.1
+- Additional testing (no more bugs found to be fixed in this release)
+- Significant performance improvement to the cursor code.
+
+2.3.0
+- User Data are now defined in TiXmlBase instead of TiXmlNode
+- Character Entities are now UCS-2
+- Character Entities can be decimal or hexadecimal
+- UTF-8 conversion.
+- Fixed many, many bugs.
+
+2.3.1
+- Fixed bug in handling nulls embedded in the input.
+- Make UTF-8 parser tolerant of bad text encoding.
+- Added encoding detection. 
+- Many fixes and input from John-Philip Leonard Johansson (JP) and Ellers, 
+  including UTF-8 feedback, bug reports, and patches. Thanks!
+- Added version # constants - a suggestion from JP and Ellers.
+- [ 979180 ] Missing ; in entity reference, fix from Rob Laveaux.
+- Copy constructors and assignment have been a long time coming. Thanks to
+  Fokke and JP.
+
+2.3.2
+- Made the IsAlpha and IsAlphaNum much more tolerant of non-UTF-8 encodings. Thanks
+  Volker Boerchers for finding the issue.
+- Ran the program though the magnificent Valgrind - http://valgrind.kde.org - to check
+  for memory errors. Fixed some minor issues.
+
+2.3.3
+- Fixed crash when test program was run from incorrect directory.
+- Fixed bug 1070717 - empty document not returned correctly - thanks Katsuhisa Yuasa.
+- Bug 1079301 resolved - deprecated stdlib calls. Thanks Adrian Boeing.
+- Bug 1035218 fixed - documentation errors. Xunji Luo
+- Other bug fixes have accumulated and been fixed on the way as well; my apologies to
+  authors not credited!
+- Big fix / addition is to correctly return const values. TinyXml could basically
+  remove const in a method like this: TiXmlElement* Foo() const, where the returned element
+  was a pointer to internal data. That is now: const TiXmlElement* Foo() const and
+  TiXmlElement* Foo().
+
+2.3.4
+- Fixed additional const errors, thanks Kent Gibson.
+- Correctly re-enable warnings after tinyxml header. Thanks Cory Nelson.
+- Variety of type cleanup and warning fixes. Thanks Warren Stevens.
+- Cleaned up unneeded constructor calls in TinyString - thanks to Geoff Carlton and
+  the discussion group on sourceforge.
+
+2.4.0
+- Improved string class, thanks Tyge Lovset (whose name gets mangled in English - sorry)
+- Type cast compiler warning, thanks Rob van den Bogaard
+- Added GetText() convenience function. Thanks Ilya Parniuk & Andrew Ellers for input.
+- Many thanks to marlonism for finding an infinite loop in bad xml.
+- A patch to cleanup warnings from Robert Gebis.
+- Added ValueStr() to get the value of a node as a string.
+- TiXmlText can now parse and output as CDATA
+- Additional string improvement from James (z2895)
+- Removed extraneous 'const', thanks David Aldrich
+- First pass at switching to the "safe" stdlib functions. Many people have suggested and
+  pushed on this, but Warren Stevens put together the first proposal.
+- TinyXml now will do EOL normalization before parsing, consistent with the W3C XML spec.
+- Documents loaded with the UTF-8 BOM will now save with the UTF-8 BOM. Good suggestion 
+  from 'instructor_'
+- Ellers submitted his very popular tutorials, which have been added to the distribution.
+
+2.4.1
+- Fixed CDATA output formatting
+- Fixed memory allocators in TinyString to work with overloaded new/delete
+
+2.4.2
+- solosnake pointed out that TIXML_LOG causes problems on an XBOX. The definition in the header
+  was superflous and was moved inside of DEBUG_PARSING
+
+2.4.3
+- Fixed a test bug that caused a crash in 'xmltest'. TinyXML was fine, but it isn't good
+  to ship with a broken test suite.
+- Started converting some functions to not cast between std::string and const char* 
+  quite as often.
+- Added FILE* versions of the document loads - good suggestion from Wade Brainerd
+- Empty documents might not always return the errors they should. [1398915] Thanks to igor v.
+- Added some asserts for multiply adding a node, regardng bug [1391937] suggested by Paco Arjonilla.
+
+2.4.4
+- Bug find thanks to andre-gross found a memory leak that occured when a document failed to load.
+- Bug find (and good analysis) by VirtualJim who found a case where attribute parsing 
+  should be throwing an error and wasn't.
+- Steve Hyatt suggested the QueryValueAttribute method, which is now implemented.
+- DavidA identified a chunk of dead code.
+- Andrew Baxter sent in some compiler warnings that were good clean up points.
+
+2.5
+- Added the Visit() API. Many thanks to both Andrew Ellerton and John-Philip for all their
+  work, code, suggestion, and just general pushing that it should be done.
+- Removed existing streaming code and use TiXmlPrinter instead.
+- [ tinyxml-Bugs-1527079 ] Compile error in tinystr.cpp fixed, thanks to Paul Suggs
+- [ tinyxml-Bugs-1522890 ] SaveFile has no error checks fixed, thanks to Ivan Dobrokotov
+- Ivan Dobrokotov also reported redundant memory allocation in the Attribute() method, which
+  upon investigation was a mess. The attribute should now be fixed for both const char* and 
+  std::string, and the return types match the input parameters.
+- Feature [ 1511105 ] Make TiXmlComment constructor accept a string / char*, implemented.
+  Thanks to Karl Itschen for the feedback.
+- [ 1480108 ] Stream parsing fails when CDATA contains tags was found by Tobias Grimm, who also
+  submitted a test case and patch. A significant bug in CDATA streaming (operator>>) has now
+  been fixed.
+
+2.5.2
+- Lieven, and others, pointed out a missing const-cast that upset the Open Watcom compiler.
+  Should now be fixed.
+- ErrorRow and ErrorCol should have been const, and weren't. Fixed thanks to Dmitry Polutov.
+
+2.5.3
+- zloe_zlo identified a missing string specialization for QueryValueAttribute() [ 1695429 ]. Worked
+  on this bug, but not sure how to fix it in a safe, cross-compiler way.
+- increased warning level to 4 and turned on detect 64 bit portability issues for VC2005.
+  May address [ 1677737 ] VS2005: /Wp64 warnings
+- grosheck identified several problems with the Document copy. Many thanks for [ 1660367 ]
+- Nice catch, and suggested fix, be Gilad Novik on the Printer dropping entities.
+  "[ 1600650 ] Bug when printing xml text" is now fixed.
+- A subtle fix from Nicos Gollan in the tinystring initializer: 
+  [ 1581449 ] Fix initialiser of TiXmlString::nullrep_
+- Great catch, although there isn't a submitter for the bug. [ 1475201 ] TinyXML parses entities in comments. 
+  Comments should not, in fact, parse entities. Fixed the code path and added tests.
+- We were not catching all the returns from ftell. Thanks to Bernard for catching that.
+  
+2.5.4
+- A TiXMLDocument can't be a sub-node. Block this from happening in the 'replace'. Thanks Noam.
+- [ 1714831 ] TiXmlBase::location is not copied by copy-ctors, fix reported and suggested by Nicola Civran.
+- Fixed possible memory overrun in the comment reading code - thanks gcarlton77
+
+2.5.5
+- Alex van der Wal spotted incorrect types (lf) being used in print and scan. robertnestor pointed out some problems with the simple solution. Types updated.
+- Johannes Hillert pointed out some bug typos.
+- Christian Mueller identified inconsistent error handling with Attributes.
+- olivier barthelemy also reported a problem with double truncation, also related to the %lf issue.
+- zaelsius came up with a great (and simple) suggestion to fix QueryValueAttribute truncating strings.
+- added some null pointer checks suggested by hansenk
+- Sami Väisänen found a (rare) buffer overrun that could occur in parsing.
+- vi tri filed a bug that led to a refactoring of the attribute setting mess (as well as adding a missing SetDoubleAttribute() )
+- removed TIXML_ERROR_OUT_OF_MEMORY. TinyXML does not systematically address OOO, and the notion it does is misleading.
+- vanneto, keithmarshall, others all reported the warning from IsWhiteSpace() usage. Cleaned this up - many thanks to everyone who reported this one.
+- tibur found a bug in end tag parsing
+
+
+
+
diff --git a/lib/third_party/tinyxml/readme.txt b/lib/third_party/tinyxml/readme.txt
new file mode 100644 (file)
index 0000000..89d9e8d
--- /dev/null
@@ -0,0 +1,530 @@
+/** @mainpage
+
+<h1> TinyXML </h1>
+
+TinyXML is a simple, small, C++ XML parser that can be easily 
+integrated into other programs.
+
+<h2> What it does. </h2>
+       
+In brief, TinyXML parses an XML document, and builds from that a 
+Document Object Model (DOM) that can be read, modified, and saved.
+
+XML stands for "eXtensible Markup Language." It allows you to create 
+your own document markups. Where HTML does a very good job of marking 
+documents for browsers, XML allows you to define any kind of document 
+markup, for example a document that describes a "to do" list for an 
+organizer application. XML is a very structured and convenient format.
+All those random file formats created to store application data can 
+all be replaced with XML. One parser for everything.
+
+The best place for the complete, correct, and quite frankly hard to
+read spec is at <a href="http://www.w3.org/TR/2004/REC-xml-20040204/">
+http://www.w3.org/TR/2004/REC-xml-20040204/</a>. An intro to XML
+(that I really like) can be found at 
+<a href="http://skew.org/xml/tutorial/">http://skew.org/xml/tutorial</a>.
+
+There are different ways to access and interact with XML data.
+TinyXML uses a Document Object Model (DOM), meaning the XML data is parsed
+into a C++ objects that can be browsed and manipulated, and then 
+written to disk or another output stream. You can also construct an XML document 
+from scratch with C++ objects and write this to disk or another output
+stream.
+
+TinyXML is designed to be easy and fast to learn. It is two headers 
+and four cpp files. Simply add these to your project and off you go. 
+There is an example file - xmltest.cpp - to get you started. 
+
+TinyXML is released under the ZLib license, 
+so you can use it in open source or commercial code. The details
+of the license are at the top of every source file.
+
+TinyXML attempts to be a flexible parser, but with truly correct and
+compliant XML output. TinyXML should compile on any reasonably C++
+compliant system. It does not rely on exceptions or RTTI. It can be 
+compiled with or without STL support. TinyXML fully supports
+the UTF-8 encoding, and the first 64k character entities.
+
+
+<h2> What it doesn't do. </h2>
+
+TinyXML doesn't parse or use DTDs (Document Type Definitions) or XSLs
+(eXtensible Stylesheet Language.) There are other parsers out there 
+(check out www.sourceforge.org, search for XML) that are much more fully
+featured. But they are also much bigger, take longer to set up in
+your project, have a higher learning curve, and often have a more
+restrictive license. If you are working with browsers or have more
+complete XML needs, TinyXML is not the parser for you.
+
+The following DTD syntax will not parse at this time in TinyXML:
+
+@verbatim
+       <!DOCTYPE Archiv [
+        <!ELEMENT Comment (#PCDATA)>
+       ]>
+@endverbatim
+
+because TinyXML sees this as a !DOCTYPE node with an illegally 
+embedded !ELEMENT node. This may be addressed in the future.
+
+<h2> Tutorials. </h2>
+
+For the impatient, here is a tutorial to get you going. A great way to get started, 
+but it is worth your time to read this (very short) manual completely.
+
+- @subpage tutorial0
+
+<h2> Code Status.  </h2>
+
+TinyXML is mature, tested code. It is very stable. If you find
+bugs, please file a bug report on the sourceforge web site
+(www.sourceforge.net/projects/tinyxml). We'll get them straightened 
+out as soon as possible.
+
+There are some areas of improvement; please check sourceforge if you are
+interested in working on TinyXML.
+
+<h2> Related Projects </h2>
+
+TinyXML projects you may find useful! (Descriptions provided by the projects.)
+
+<ul>
+<li> <b>TinyXPath</b> (http://tinyxpath.sourceforge.net). TinyXPath is a small footprint 
+     XPath syntax decoder, written in C++.</li>
+<li> <b>TinyXML++</b> (http://code.google.com/p/ticpp/). TinyXML++ is a completely new 
+     interface to TinyXML that uses MANY of the C++ strengths. Templates, 
+        exceptions, and much better error handling.</li>
+</ul>
+
+<h2> Features </h2>
+
+<h3> Using STL </h3>
+
+TinyXML can be compiled to use or not use STL. When using STL, TinyXML
+uses the std::string class, and fully supports std::istream, std::ostream,
+operator<<, and operator>>. Many API methods have both 'const char*' and
+'const std::string&' forms.
+
+When STL support is compiled out, no STL files are included whatsoever. All
+the string classes are implemented by TinyXML itself. API methods
+all use the 'const char*' form for input.
+
+Use the compile time #define:
+
+       TIXML_USE_STL
+
+to compile one version or the other. This can be passed by the compiler,
+or set as the first line of "tinyxml.h".
+
+Note: If compiling the test code in Linux, setting the environment
+variable TINYXML_USE_STL=YES/NO will control STL compilation. In the
+Windows project file, STL and non STL targets are provided. In your project,
+It's probably easiest to add the line "#define TIXML_USE_STL" as the first
+line of tinyxml.h.
+
+<h3> UTF-8 </h3>
+
+TinyXML supports UTF-8 allowing to manipulate XML files in any language. TinyXML
+also supports "legacy mode" - the encoding used before UTF-8 support and
+probably best described as "extended ascii".
+
+Normally, TinyXML will try to detect the correct encoding and use it. However,
+by setting the value of TIXML_DEFAULT_ENCODING in the header file, TinyXML
+can be forced to always use one encoding.
+
+TinyXML will assume Legacy Mode until one of the following occurs:
+<ol>
+       <li> If the non-standard but common "UTF-8 lead bytes" (0xef 0xbb 0xbf)
+                begin the file or data stream, TinyXML will read it as UTF-8. </li>
+       <li> If the declaration tag is read, and it has an encoding="UTF-8", then
+                TinyXML will read it as UTF-8. </li>
+       <li> If the declaration tag is read, and it has no encoding specified, then TinyXML will 
+                read it as UTF-8. </li>
+       <li> If the declaration tag is read, and it has an encoding="something else", then TinyXML 
+                will read it as Legacy Mode. In legacy mode, TinyXML will work as it did before. It's 
+                not clear what that mode does exactly, but old content should keep working.</li>
+       <li> Until one of the above criteria is met, TinyXML runs in Legacy Mode.</li>
+</ol>
+
+What happens if the encoding is incorrectly set or detected? TinyXML will try
+to read and pass through text seen as improperly encoded. You may get some strange results or 
+mangled characters. You may want to force TinyXML to the correct mode.
+
+You may force TinyXML to Legacy Mode by using LoadFile( TIXML_ENCODING_LEGACY ) or
+LoadFile( filename, TIXML_ENCODING_LEGACY ). You may force it to use legacy mode all
+the time by setting TIXML_DEFAULT_ENCODING = TIXML_ENCODING_LEGACY. Likewise, you may 
+force it to TIXML_ENCODING_UTF8 with the same technique.
+
+For English users, using English XML, UTF-8 is the same as low-ASCII. You
+don't need to be aware of UTF-8 or change your code in any way. You can think
+of UTF-8 as a "superset" of ASCII.
+
+UTF-8 is not a double byte format - but it is a standard encoding of Unicode!
+TinyXML does not use or directly support wchar, TCHAR, or Microsoft's _UNICODE at this time. 
+It is common to see the term "Unicode" improperly refer to UTF-16, a wide byte encoding
+of unicode. This is a source of confusion.
+
+For "high-ascii" languages - everything not English, pretty much - TinyXML can
+handle all languages, at the same time, as long as the XML is encoded
+in UTF-8. That can be a little tricky, older programs and operating systems
+tend to use the "default" or "traditional" code page. Many apps (and almost all
+modern ones) can output UTF-8, but older or stubborn (or just broken) ones
+still output text in the default code page. 
+
+For example, Japanese systems traditionally use SHIFT-JIS encoding. 
+Text encoded as SHIFT-JIS can not be read by TinyXML. 
+A good text editor can import SHIFT-JIS and then save as UTF-8.
+
+The <a href="http://skew.org/xml/tutorial/">Skew.org link</a> does a great
+job covering the encoding issue.
+
+The test file "utf8test.xml" is an XML containing English, Spanish, Russian,
+and Simplified Chinese. (Hopefully they are translated correctly). The file
+"utf8test.gif" is a screen capture of the XML file, rendered in IE. Note that
+if you don't have the correct fonts (Simplified Chinese or Russian) on your
+system, you won't see output that matches the GIF file even if you can parse
+it correctly. Also note that (at least on my Windows machine) console output
+is in a Western code page, so that Print() or printf() cannot correctly display
+the file. This is not a bug in TinyXML - just an OS issue. No data is lost or 
+destroyed by TinyXML. The console just doesn't render UTF-8.
+
+
+<h3> Entities </h3>
+TinyXML recognizes the pre-defined "character entities", meaning special
+characters. Namely:
+
+@verbatim
+       &amp;   &
+       &lt;    <
+       &gt;    >
+       &quot;  "
+       &apos;  '
+@endverbatim
+
+These are recognized when the XML document is read, and translated to there
+UTF-8 equivalents. For instance, text with the XML of:
+
+@verbatim
+       Far &amp; Away
+@endverbatim
+
+will have the Value() of "Far & Away" when queried from the TiXmlText object,
+and will be written back to the XML stream/file as an ampersand. Older versions
+of TinyXML "preserved" character entities, but the newer versions will translate
+them into characters.
+
+Additionally, any character can be specified by its Unicode code point:
+The syntax "&#xA0;" or "&#160;" are both to the non-breaking space characher.
+
+<h3> Printing </h3>
+TinyXML can print output in several different ways that all have strengths and limitations.
+
+- Print( FILE* ). Output to a std-C stream, which includes all C files as well as stdout.
+       - "Pretty prints", but you don't have control over printing options.
+       - The output is streamed directly to the FILE object, so there is no memory overhead
+         in the TinyXML code.
+       - used by Print() and SaveFile()
+
+- operator<<. Output to a c++ stream.
+       - Integrates with standart C++ iostreams.
+       - Outputs in "network printing" mode without line breaks. Good for network transmission
+         and moving XML between C++ objects, but hard for a human to read.
+
+- TiXmlPrinter. Output to a std::string or memory buffer.
+       - API is less concise
+       - Future printing options will be put here.
+       - Printing may change slightly in future versions as it is refined and expanded.
+
+<h3> Streams </h3>
+With TIXML_USE_STL on TinyXML supports C++ streams (operator <<,>>) streams as well
+as C (FILE*) streams. There are some differences that you may need to be aware of.
+
+C style output:
+       - based on FILE*
+       - the Print() and SaveFile() methods
+
+       Generates formatted output, with plenty of white space, intended to be as 
+       human-readable as possible. They are very fast, and tolerant of ill formed 
+       XML documents. For example, an XML document that contains 2 root elements 
+       and 2 declarations, will still print.
+
+C style input:
+       - based on FILE*
+       - the Parse() and LoadFile() methods
+
+       A fast, tolerant read. Use whenever you don't need the C++ streams.
+
+C++ style output:
+       - based on std::ostream
+       - operator<<
+
+       Generates condensed output, intended for network transmission rather than
+       readability. Depending on your system's implementation of the ostream class,
+       these may be somewhat slower. (Or may not.) Not tolerant of ill formed XML:
+       a document should contain the correct one root element. Additional root level
+       elements will not be streamed out.
+
+C++ style input:
+       - based on std::istream
+       - operator>>
+
+       Reads XML from a stream, making it useful for network transmission. The tricky
+       part is knowing when the XML document is complete, since there will almost
+       certainly be other data in the stream. TinyXML will assume the XML data is
+       complete after it reads the root element. Put another way, documents that
+       are ill-constructed with more than one root element will not read correctly.
+       Also note that operator>> is somewhat slower than Parse, due to both 
+       implementation of the STL and limitations of TinyXML.
+
+<h3> White space </h3>
+The world simply does not agree on whether white space should be kept, or condensed.
+For example, pretend the '_' is a space, and look at "Hello____world". HTML, and 
+at least some XML parsers, will interpret this as "Hello_world". They condense white
+space. Some XML parsers do not, and will leave it as "Hello____world". (Remember
+to keep pretending the _ is a space.) Others suggest that __Hello___world__ should become
+Hello___world.
+
+It's an issue that hasn't been resolved to my satisfaction. TinyXML supports the
+first 2 approaches. Call TiXmlBase::SetCondenseWhiteSpace( bool ) to set the desired behavior.
+The default is to condense white space.
+
+If you change the default, you should call TiXmlBase::SetCondenseWhiteSpace( bool )
+before making any calls to Parse XML data, and I don't recommend changing it after
+it has been set.
+
+
+<h3> Handles </h3>
+
+Where browsing an XML document in a robust way, it is important to check
+for null returns from method calls. An error safe implementation can
+generate a lot of code like:
+
+@verbatim
+TiXmlElement* root = document.FirstChildElement( "Document" );
+if ( root )
+{
+       TiXmlElement* element = root->FirstChildElement( "Element" );
+       if ( element )
+       {
+               TiXmlElement* child = element->FirstChildElement( "Child" );
+               if ( child )
+               {
+                       TiXmlElement* child2 = child->NextSiblingElement( "Child" );
+                       if ( child2 )
+                       {
+                               // Finally do something useful.
+@endverbatim
+
+Handles have been introduced to clean this up. Using the TiXmlHandle class,
+the previous code reduces to:
+
+@verbatim
+TiXmlHandle docHandle( &document );
+TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).ToElement();
+if ( child2 )
+{
+       // do something useful
+@endverbatim
+
+Which is much easier to deal with. See TiXmlHandle for more information.
+
+
+<h3> Row and Column tracking </h3>
+Being able to track nodes and attributes back to their origin location
+in source files can be very important for some applications. Additionally,
+knowing where parsing errors occured in the original source can be very
+time saving.
+
+TinyXML can tracks the row and column origin of all nodes and attributes
+in a text file. The TiXmlBase::Row() and TiXmlBase::Column() methods return
+the origin of the node in the source text. The correct tabs can be 
+configured in TiXmlDocument::SetTabSize().
+
+
+<h2> Using and Installing </h2>
+
+To Compile and Run xmltest:
+
+A Linux Makefile and a Windows Visual C++ .dsw file is provided. 
+Simply compile and run. It will write the file demotest.xml to your 
+disk and generate output on the screen. It also tests walking the
+DOM by printing out the number of nodes found using different 
+techniques.
+
+The Linux makefile is very generic and runs on many systems - it 
+is currently tested on mingw and
+MacOSX. You do not need to run 'make depend'. The dependecies have been
+hard coded.
+
+<h3>Windows project file for VC6</h3>
+<ul>
+<li>tinyxml:           tinyxml library, non-STL </li>
+<li>tinyxmlSTL:                tinyxml library, STL </li>
+<li>tinyXmlTest:       test app, non-STL </li>
+<li>tinyXmlTestSTL: test app, STL </li>
+</ul>
+
+<h3>Makefile</h3>
+At the top of the makefile you can set:
+
+PROFILE, DEBUG, and TINYXML_USE_STL. Details (such that they are) are in
+the makefile.
+
+In the tinyxml directory, type "make clean" then "make". The executable
+file 'xmltest' will be created.
+
+
+
+<h3>To Use in an Application:</h3>
+
+Add tinyxml.cpp, tinyxml.h, tinyxmlerror.cpp, tinyxmlparser.cpp, tinystr.cpp, and tinystr.h to your
+project or make file. That's it! It should compile on any reasonably
+compliant C++ system. You do not need to enable exceptions or
+RTTI for TinyXML.
+
+
+<h2> How TinyXML works.  </h2>
+
+An example is probably the best way to go. Take:
+@verbatim
+       <?xml version="1.0" standalone=no>
+       <!-- Our to do list data -->
+       <ToDo>
+               <Item priority="1"> Go to the <bold>Toy store!</bold></Item>
+               <Item priority="2"> Do bills</Item>
+       </ToDo>
+@endverbatim
+
+Its not much of a To Do list, but it will do. To read this file 
+(say "demo.xml") you would create a document, and parse it in:
+@verbatim
+       TiXmlDocument doc( "demo.xml" );
+       doc.LoadFile();
+@endverbatim
+
+And its ready to go. Now lets look at some lines and how they 
+relate to the DOM.
+
+@verbatim
+<?xml version="1.0" standalone=no>
+@endverbatim
+
+       The first line is a declaration, and gets turned into the
+       TiXmlDeclaration class. It will be the first child of the
+       document node.
+       
+       This is the only directive/special tag parsed by TinyXML.
+       Generally directive tags are stored in TiXmlUnknown so the 
+       commands wont be lost when it is saved back to disk.
+
+@verbatim
+<!-- Our to do list data -->
+@endverbatim
+
+       A comment. Will become a TiXmlComment object.
+
+@verbatim
+<ToDo>
+@endverbatim
+
+       The "ToDo" tag defines a TiXmlElement object. This one does not have 
+       any attributes, but does contain 2 other elements.
+
+@verbatim
+<Item priority="1"> 
+@endverbatim
+
+       Creates another TiXmlElement which is a child of the "ToDo" element. 
+       This element has 1 attribute, with the name "priority" and the value 
+       "1".
+
+@verbatim
+Go to the
+@endverbatim 
+
+       A TiXmlText. This is a leaf node and cannot contain other nodes. 
+       It is a child of the "Item" TiXmlElement.
+
+@verbatim
+<bold>
+@endverbatim
+
+       
+       Another TiXmlElement, this one a child of the "Item" element.
+
+Etc.
+
+Looking at the entire object tree, you end up with:
+@verbatim
+TiXmlDocument                                  "demo.xml"
+       TiXmlDeclaration                        "version='1.0'" "standalone=no"
+       TiXmlComment                            " Our to do list data"
+       TiXmlElement                            "ToDo"
+               TiXmlElement                    "Item" Attribtutes: priority = 1
+                       TiXmlText                       "Go to the "
+                       TiXmlElement            "bold"
+                               TiXmlText               "Toy store!"
+               TiXmlElement                    "Item" Attributes: priority=2
+                       TiXmlText                       "Do bills"
+@endverbatim
+
+<h2> Documentation </h2>
+
+The documentation is build with Doxygen, using the 'dox' 
+configuration file.
+
+<h2> License </h2>
+
+TinyXML is released under the zlib license:
+
+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.
+
+<h2> References  </h2>
+
+The World Wide Web Consortium is the definitive standard body for 
+XML, and their web pages contain huge amounts of information. 
+
+The definitive spec: <a href="http://www.w3.org/TR/2004/REC-xml-20040204/">
+http://www.w3.org/TR/2004/REC-xml-20040204/</a>
+
+I also recommend "XML Pocket Reference" by Robert Eckstein and published by 
+OReilly...the book that got the whole thing started.
+
+<h2> Contributors, Contacts, and a Brief History </h2>
+
+Thanks very much to everyone who sends suggestions, bugs, ideas, and 
+encouragement. It all helps, and makes this project fun. A special thanks
+to the contributors on the web pages that keep it lively.
+
+So many people have sent in bugs and ideas, that rather than list here 
+we try to give credit due in the "changes.txt" file.
+
+TinyXML was originally written by Lee Thomason. (Often the "I" still
+in the documentation.) Lee reviews changes and releases new versions,
+with the help of Yves Berquin, Andrew Ellerton, and the tinyXml community.
+
+We appreciate your suggestions, and would love to know if you 
+use TinyXML. Hopefully you will enjoy it and find it useful. 
+Please post questions, comments, file bugs, or contact us at:
+
+www.sourceforge.net/projects/tinyxml
+
+Lee Thomason, Yves Berquin, Andrew Ellerton
+*/
diff --git a/lib/third_party/tinyxml/tinystr.cpp b/lib/third_party/tinyxml/tinystr.cpp
new file mode 100644 (file)
index 0000000..35be574
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+  www.sourceforge.net/projects/tinyxml
+  Original file by Yves Berquin.
+
+  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.
+*/
+
+/*
+ * THIS FILE WAS ALTERED BY Tyge Løvset, 7. April 2005.
+ */
+
+
+#ifndef TIXML_USE_STL
+
+#include "tinystr.h"
+
+// Error value for find primitive
+const TiXmlString::size_type TiXmlString::npos = static_cast< TiXmlString::size_type >(-1);
+
+
+// Null rep.
+TiXmlString::Rep TiXmlString::nullrep_ = { 0, 0, { '\0' } };
+
+
+void TiXmlString::reserve (size_type cap)
+{
+  if (cap > capacity())
+  {
+    TiXmlString tmp;
+    tmp.init(length(), cap);
+    memcpy(tmp.start(), data(), length());
+    swap(tmp);
+  }
+}
+
+
+TiXmlString& TiXmlString::assign(const char* str, size_type len)
+{
+  size_type cap = capacity();
+  if (len > cap || cap > 3*(len + 8))
+  {
+    TiXmlString tmp;
+    tmp.init(len);
+    memcpy(tmp.start(), str, len);
+    swap(tmp);
+  }
+  else
+  {
+    memmove(start(), str, len);
+    set_size(len);
+  }
+  return *this;
+}
+
+
+TiXmlString& TiXmlString::append(const char* str, size_type len)
+{
+  size_type newsize = length() + len;
+  if (newsize > capacity())
+  {
+    reserve (newsize + capacity());
+  }
+  memmove(finish(), str, len);
+  set_size(newsize);
+  return *this;
+}
+
+
+TiXmlString operator + (const TiXmlString & a, const TiXmlString & b)
+{
+  TiXmlString tmp;
+  tmp.reserve(a.length() + b.length());
+  tmp += a;
+  tmp += b;
+  return tmp;
+}
+
+TiXmlString operator + (const TiXmlString & a, const char* b)
+{
+  TiXmlString tmp;
+  TiXmlString::size_type b_len = static_cast<TiXmlString::size_type>( strlen(b) );
+  tmp.reserve(a.length() + b_len);
+  tmp += a;
+  tmp.append(b, b_len);
+  return tmp;
+}
+
+TiXmlString operator + (const char* a, const TiXmlString & b)
+{
+  TiXmlString tmp;
+  TiXmlString::size_type a_len = static_cast<TiXmlString::size_type>( strlen(a) );
+  tmp.reserve(a_len + b.length());
+  tmp.append(a, a_len);
+  tmp += b;
+  return tmp;
+}
+
+
+#endif  // TIXML_USE_STL
diff --git a/lib/third_party/tinyxml/tinystr.h b/lib/third_party/tinyxml/tinystr.h
new file mode 100644 (file)
index 0000000..5d03866
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+  www.sourceforge.net/projects/tinyxml
+  Original file by Yves Berquin.
+
+  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.
+*/
+
+/*
+ * THIS FILE WAS ALTERED BY Tyge Lovset, 7. April 2005.
+ *
+ * - completely rewritten. compact, clean, and fast implementation.
+ * - sizeof(TiXmlString) = pointer size (4 bytes on 32-bit systems)
+ * - fixed reserve() to work as per specification.
+ * - fixed buggy compares operator==(), operator<(), and operator>()
+ * - fixed operator+=() to take a const ref argument, following spec.
+ * - added "copy" constructor with length, and most compare operators.
+ * - added swap(), clear(), size(), capacity(), operator+().
+ */
+
+#ifndef TIXML_USE_STL
+
+#ifndef TIXML_STRING_INCLUDED
+#define TIXML_STRING_INCLUDED
+
+#include <assert.h>
+#include <string.h>
+#include <tinyxml/cpPlugins_tinyxml_Export.h>
+
+/*      The support for explicit isn't that universal, and it isn't really
+        required - it is used to check that the TiXmlString class isn't incorrectly
+        used. Be nice to old compilers and macro it here:
+*/
+#if defined(_MSC_VER) && (_MSC_VER >= 1200 )
+// Microsoft visual studio, version 6 and higher.
+#define TIXML_EXPLICIT explicit
+#elif defined(__GNUC__) && (__GNUC__ >= 3 )
+// GCC version 3 and higher.s
+#define TIXML_EXPLICIT explicit
+#else
+#define TIXML_EXPLICIT
+#endif
+
+
+/*
+  TiXmlString is an emulation of a subset of the std::string template.
+  Its purpose is to allow compiling TinyXML on compilers with no or poor STL support.
+  Only the member functions relevant to the TinyXML project have been implemented.
+  The buffer allocation is made by a simplistic power of 2 like mechanism : if we increase
+  a string and there's no more room, we allocate a buffer twice as big as we need.
+*/
+class cpPlugins_tinyxml_EXPORT TiXmlString
+{
+public :
+  // The size type used
+  typedef size_t size_type;
+
+  // Error value for find primitive
+  static const size_type npos; // = -1;
+
+
+  // TiXmlString empty constructor
+  TiXmlString () : rep_(&nullrep_)
+    {
+    }
+
+  // TiXmlString copy constructor
+  TiXmlString ( const TiXmlString & copy) : rep_(0)
+    {
+      init(copy.length());
+      memcpy(start(), copy.data(), length());
+    }
+
+  // TiXmlString constructor, based on a string
+  TIXML_EXPLICIT TiXmlString ( const char * copy) : rep_(0)
+    {
+      init( static_cast<size_type>( strlen(copy) ));
+      memcpy(start(), copy, length());
+    }
+
+  // TiXmlString constructor, based on a string
+  TIXML_EXPLICIT TiXmlString ( const char * str, size_type len) : rep_(0)
+    {
+      init(len);
+      memcpy(start(), str, len);
+    }
+
+  // TiXmlString destructor
+  ~TiXmlString ()
+    {
+      quit();
+    }
+
+  // = operator
+  TiXmlString& operator = (const char * copy)
+    {
+      return assign( copy, (size_type)strlen(copy));
+    }
+
+  // = operator
+  TiXmlString& operator = (const TiXmlString & copy)
+    {
+      return assign(copy.start(), copy.length());
+    }
+
+
+  // += operator. Maps to append
+  TiXmlString& operator += (const char * suffix)
+    {
+      return append(suffix, static_cast<size_type>( strlen(suffix) ));
+    }
+
+  // += operator. Maps to append
+  TiXmlString& operator += (char single)
+    {
+      return append(&single, 1);
+    }
+
+  // += operator. Maps to append
+  TiXmlString& operator += (const TiXmlString & suffix)
+    {
+      return append(suffix.data(), suffix.length());
+    }
+
+
+  // Convert a TiXmlString into a null-terminated char *
+  const char * c_str () const { return rep_->str; }
+
+  // Convert a TiXmlString into a char * (need not be null terminated).
+  const char * data () const { return rep_->str; }
+
+  // Return the length of a TiXmlString
+  size_type length () const { return rep_->size; }
+
+  // Alias for length()
+  size_type size () const { return rep_->size; }
+
+  // Checks if a TiXmlString is empty
+  bool empty () const { return rep_->size == 0; }
+
+  // Return capacity of string
+  size_type capacity () const { return rep_->capacity; }
+
+
+  // single char extraction
+  const char& at (size_type index) const
+    {
+      assert( index < length() );
+      return rep_->str[ index ];
+    }
+
+  // [] operator
+  char& operator [] (size_type index) const
+    {
+      assert( index < length() );
+      return rep_->str[ index ];
+    }
+
+  // find a char in a string. Return TiXmlString::npos if not found
+  size_type find (char lookup) const
+    {
+      return find(lookup, 0);
+    }
+
+  // find a char in a string from an offset. Return TiXmlString::npos if not found
+  size_type find (char tofind, size_type offset) const
+    {
+      if (offset >= length()) return npos;
+
+      for (const char* p = c_str() + offset; *p != '\0'; ++p)
+      {
+        if (*p == tofind) return static_cast< size_type >( p - c_str() );
+      }
+      return npos;
+    }
+
+  void clear ()
+    {
+      //Lee:
+      //The original was just too strange, though correct:
+      //      TiXmlString().swap(*this);
+      //Instead use the quit & re-init:
+      quit();
+      init(0,0);
+    }
+
+  /*      Function to reserve a big amount of data when we know we'll need it. Be aware that this
+          function DOES NOT clear the content of the TiXmlString if any exists.
+  */
+  void reserve (size_type cap);
+
+  TiXmlString& assign (const char* str, size_type len);
+
+  TiXmlString& append (const char* str, size_type len);
+
+  void swap (TiXmlString& other)
+    {
+      Rep* r = rep_;
+      rep_ = other.rep_;
+      other.rep_ = r;
+    }
+
+private:
+
+  void init(size_type sz) { init(sz, sz); }
+  void set_size(size_type sz) { rep_->str[ rep_->size = sz ] = '\0'; }
+  char* start() const { return rep_->str; }
+  char* finish() const { return rep_->str + rep_->size; }
+
+  struct Rep
+  {
+    size_type size, capacity;
+    char str[1];
+  };
+
+  void init(size_type sz, size_type cap)
+    {
+      if (cap)
+      {
+        // Lee: the original form:
+        //      rep_ = static_cast<Rep*>(operator new(sizeof(Rep) + cap));
+        // doesn't work in some cases of new being overloaded. Switching
+        // to the normal allocation, although use an 'int' for systems
+        // that are overly picky about structure alignment.
+        const size_type bytesNeeded = sizeof(Rep) + cap;
+        const size_type intsNeeded = ( bytesNeeded + sizeof(int) - 1 ) / sizeof( int );
+        rep_ = reinterpret_cast<Rep*>( new int[ intsNeeded ] );
+
+        rep_->str[ rep_->size = sz ] = '\0';
+        rep_->capacity = cap;
+      }
+      else
+      {
+        rep_ = &nullrep_;
+      }
+    }
+
+  void quit()
+    {
+      if (rep_ != &nullrep_)
+      {
+        // The rep_ is really an array of ints. (see the allocator, above).
+        // Cast it back before delete, so the compiler won't incorrectly call destructors.
+        delete [] ( reinterpret_cast<int*>( rep_ ) );
+      }
+    }
+
+  Rep * rep_;
+  static Rep nullrep_;
+
+} ;
+
+
+inline bool operator == (const TiXmlString & a, const TiXmlString & b)
+{
+  return    ( a.length() == b.length() )                          // optimization on some platforms
+    && ( strcmp(a.c_str(), b.c_str()) == 0 );        // actual compare
+}
+inline bool operator < (const TiXmlString & a, const TiXmlString & b)
+{
+  return strcmp(a.c_str(), b.c_str()) < 0;
+}
+
+inline bool operator != (const TiXmlString & a, const TiXmlString & b) { return !(a == b); }
+inline bool operator >  (const TiXmlString & a, const TiXmlString & b) { return b < a; }
+inline bool operator <= (const TiXmlString & a, const TiXmlString & b) { return !(b < a); }
+inline bool operator >= (const TiXmlString & a, const TiXmlString & b) { return !(a < b); }
+
+inline bool operator == (const TiXmlString & a, const char* b) { return strcmp(a.c_str(), b) == 0; }
+inline bool operator == (const char* a, const TiXmlString & b) { return b == a; }
+inline bool operator != (const TiXmlString & a, const char* b) { return !(a == b); }
+inline bool operator != (const char* a, const TiXmlString & b) { return !(b == a); }
+
+TiXmlString operator + (const TiXmlString & a, const TiXmlString & b);
+TiXmlString operator + (const TiXmlString & a, const char* b);
+TiXmlString operator + (const char* a, const TiXmlString & b);
+
+
+/*
+  TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString.
+  Only the operators that we need for TinyXML have been developped.
+*/
+class TiXmlOutStream : public TiXmlString
+{
+public :
+
+  // TiXmlOutStream << operator.
+  TiXmlOutStream & operator << (const TiXmlString & in)
+    {
+      *this += in;
+      return *this;
+    }
+
+  // TiXmlOutStream << operator.
+  TiXmlOutStream & operator << (const char * in)
+    {
+      *this += in;
+      return *this;
+    }
+
+} ;
+
+#endif  // TIXML_STRING_INCLUDED
+#endif  // TIXML_USE_STL
diff --git a/lib/third_party/tinyxml/tinyxml.cpp b/lib/third_party/tinyxml/tinyxml.cpp
new file mode 100644 (file)
index 0000000..f345990
--- /dev/null
@@ -0,0 +1,1838 @@
+/*
+  www.sourceforge.net/projects/tinyxml
+  Original code (2.0 and earlier )copyright (c) 2000-2006 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 <ctype.h>
+
+#ifdef TIXML_USE_STL
+#include <sstream>
+#include <iostream>
+#endif
+
+#include "tinyxml.h"
+
+FILE* TiXmlFOpen( const char* filename, const char* mode );
+
+bool TiXmlBase::condenseWhiteSpace = true;
+
+// Microsoft compiler security
+FILE* TiXmlFOpen( const char* filename, const char* mode )
+{
+#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
+  FILE* fp = 0;
+  errno_t err = fopen_s( &fp, filename, mode );
+  if ( !err && fp )
+    return fp;
+  return 0;
+#else
+  return fopen( filename, mode );
+#endif
+}
+
+void TiXmlBase::EncodeString( const TIXML_STRING& str, TIXML_STRING* outString )
+{
+  int i=0;
+
+  while( i<(int)str.length() )
+  {
+    unsigned char c = (unsigned char) str[i];
+
+    if (    c == '&'
+            && i < ( (int)str.length() - 2 )
+            && str[i+1] == '#'
+            && str[i+2] == 'x' )
+    {
+      // Hexadecimal character reference.
+      // Pass through unchanged.
+      // &#xA9;       -- copyright symbol, for example.
+      //
+      // The -1 is a bug fix from Rob Laveaux. It keeps
+      // an overflow from happening if there is no ';'.
+      // There are actually 2 ways to exit this loop -
+      // while fails (error case) and break (semicolon found).
+      // However, there is no mechanism (currently) for
+      // this function to return an error.
+      while ( i<(int)str.length()-1 )
+      {
+        outString->append( str.c_str() + i, 1 );
+        ++i;
+        if ( str[i] == ';' )
+          break;
+      }
+    }
+    else if ( c == '&' )
+    {
+      outString->append( entity[0].str, entity[0].strLength );
+      ++i;
+    }
+    else if ( c == '<' )
+    {
+      outString->append( entity[1].str, entity[1].strLength );
+      ++i;
+    }
+    else if ( c == '>' )
+    {
+      outString->append( entity[2].str, entity[2].strLength );
+      ++i;
+    }
+    else if ( c == '\"' )
+    {
+      outString->append( entity[3].str, entity[3].strLength );
+      ++i;
+    }
+    else if ( c == '\'' )
+    {
+      outString->append( entity[4].str, entity[4].strLength );
+      ++i;
+    }
+    else if ( c < 32 )
+    {
+      // Easy pass at non-alpha/numeric/symbol
+      // Below 32 is symbolic.
+      char buf[ 32 ];
+
+#if defined(TIXML_SNPRINTF)
+      TIXML_SNPRINTF( buf, sizeof(buf), "&#x%02X;", (unsigned) ( c & 0xff ) );
+#else
+      sprintf( buf, "&#x%02X;", (unsigned) ( c & 0xff ) );
+#endif
+
+      //*ME:  warning C4267: convert 'size_t' to 'int'
+          //*ME:  Int-Cast to make compiler happy ...
+          outString->append( buf, (int)strlen( buf ) );
+      ++i;
+    }
+    else
+    {
+      //char realc = (char) c;
+      //outString->append( &realc, 1 );
+      *outString += (char) c; // somewhat more efficient function call.
+      ++i;
+    }
+  }
+}
+
+
+TiXmlNode::TiXmlNode( NodeType _type ) : TiXmlBase()
+{
+  parent = 0;
+  type = _type;
+  firstChild = 0;
+  lastChild = 0;
+  prev = 0;
+  next = 0;
+}
+
+
+TiXmlNode::~TiXmlNode()
+{
+  TiXmlNode* node = firstChild;
+  TiXmlNode* temp = 0;
+
+  while ( node )
+  {
+    temp = node;
+    node = node->next;
+    delete temp;
+  }
+}
+
+
+void TiXmlNode::CopyTo( TiXmlNode* target ) const
+{
+  target->SetValue (value.c_str() );
+  target->userData = userData;
+  target->location = location;
+}
+
+
+void TiXmlNode::Clear()
+{
+  TiXmlNode* node = firstChild;
+  TiXmlNode* temp = 0;
+
+  while ( node )
+  {
+    temp = node;
+    node = node->next;
+    delete temp;
+  }
+
+  firstChild = 0;
+  lastChild = 0;
+}
+
+
+TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node )
+{
+  assert( node->parent == 0 || node->parent == this );
+  assert( node->GetDocument() == 0 || node->GetDocument() == this->GetDocument() );
+
+  if ( node->Type() == TiXmlNode::TINYXML_DOCUMENT )
+  {
+    delete node;
+    if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );
+    return 0;
+  }
+
+  node->parent = this;
+
+  node->prev = lastChild;
+  node->next = 0;
+
+  if ( lastChild )
+    lastChild->next = node;
+  else
+    firstChild = node;                      // it was an empty list.
+
+  lastChild = node;
+  return node;
+}
+
+
+TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis )
+{
+  if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT )
+  {
+    if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );
+    return 0;
+  }
+  TiXmlNode* node = addThis.Clone();
+  if ( !node )
+    return 0;
+
+  return LinkEndChild( node );
+}
+
+
+TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis )
+{
+  if ( !beforeThis || beforeThis->parent != this ) {
+    return 0;
+  }
+  if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT )
+  {
+    if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );
+    return 0;
+  }
+
+  TiXmlNode* node = addThis.Clone();
+  if ( !node )
+    return 0;
+  node->parent = this;
+
+  node->next = beforeThis;
+  node->prev = beforeThis->prev;
+  if ( beforeThis->prev )
+  {
+    beforeThis->prev->next = node;
+  }
+  else
+  {
+    assert( firstChild == beforeThis );
+    firstChild = node;
+  }
+  beforeThis->prev = node;
+  return node;
+}
+
+
+TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis )
+{
+  if ( !afterThis || afterThis->parent != this ) {
+    return 0;
+  }
+  if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT )
+  {
+    if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );
+    return 0;
+  }
+
+  TiXmlNode* node = addThis.Clone();
+  if ( !node )
+    return 0;
+  node->parent = this;
+
+  node->prev = afterThis;
+  node->next = afterThis->next;
+  if ( afterThis->next )
+  {
+    afterThis->next->prev = node;
+  }
+  else
+  {
+    assert( lastChild == afterThis );
+    lastChild = node;
+  }
+  afterThis->next = node;
+  return node;
+}
+
+
+TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis )
+{
+  if ( !replaceThis )
+    return 0;
+
+  if ( replaceThis->parent != this )
+    return 0;
+
+  if ( withThis.ToDocument() ) {
+    // A document can never be a child.     Thanks to Noam.
+    TiXmlDocument* document = GetDocument();
+    if ( document )
+      document->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );
+    return 0;
+  }
+
+  TiXmlNode* node = withThis.Clone();
+  if ( !node )
+    return 0;
+
+  node->next = replaceThis->next;
+  node->prev = replaceThis->prev;
+
+  if ( replaceThis->next )
+    replaceThis->next->prev = node;
+  else
+    lastChild = node;
+
+  if ( replaceThis->prev )
+    replaceThis->prev->next = node;
+  else
+    firstChild = node;
+
+  delete replaceThis;
+  node->parent = this;
+  return node;
+}
+
+
+bool TiXmlNode::RemoveChild( TiXmlNode* removeThis )
+{
+  if ( !removeThis ) {
+    return false;
+  }
+
+  if ( removeThis->parent != this )
+  {
+    assert( 0 );
+    return false;
+  }
+
+  if ( removeThis->next )
+    removeThis->next->prev = removeThis->prev;
+  else
+    lastChild = removeThis->prev;
+
+  if ( removeThis->prev )
+    removeThis->prev->next = removeThis->next;
+  else
+    firstChild = removeThis->next;
+
+  delete removeThis;
+  return true;
+}
+
+const TiXmlNode* TiXmlNode::FirstChild( const char * _value ) const
+{
+  const TiXmlNode* node;
+  for ( node = firstChild; node; node = node->next )
+  {
+    if ( strcmp( node->Value(), _value ) == 0 )
+      return node;
+  }
+  return 0;
+}
+
+
+const TiXmlNode* TiXmlNode::LastChild( const char * _value ) const
+{
+  const TiXmlNode* node;
+  for ( node = lastChild; node; node = node->prev )
+  {
+    if ( strcmp( node->Value(), _value ) == 0 )
+      return node;
+  }
+  return 0;
+}
+
+
+const TiXmlNode* TiXmlNode::IterateChildren( const TiXmlNode* previous ) const
+{
+  if ( !previous )
+  {
+    return FirstChild();
+  }
+  else
+  {
+    assert( previous->parent == this );
+    return previous->NextSibling();
+  }
+}
+
+
+const TiXmlNode* TiXmlNode::IterateChildren( const char * val, const TiXmlNode* previous ) const
+{
+  if ( !previous )
+  {
+    return FirstChild( val );
+  }
+  else
+  {
+    assert( previous->parent == this );
+    return previous->NextSibling( val );
+  }
+}
+
+
+const TiXmlNode* TiXmlNode::NextSibling( const char * _value ) const
+{
+  const TiXmlNode* node;
+  for ( node = next; node; node = node->next )
+  {
+    if ( strcmp( node->Value(), _value ) == 0 )
+      return node;
+  }
+  return 0;
+}
+
+
+const TiXmlNode* TiXmlNode::PreviousSibling( const char * _value ) const
+{
+  const TiXmlNode* node;
+  for ( node = prev; node; node = node->prev )
+  {
+    if ( strcmp( node->Value(), _value ) == 0 )
+      return node;
+  }
+  return 0;
+}
+
+
+void TiXmlElement::RemoveAttribute( const char * name )
+{
+#ifdef TIXML_USE_STL
+  TIXML_STRING str( name );
+  TiXmlAttribute* node = attributeSet.Find( str );
+#else
+  TiXmlAttribute* node = attributeSet.Find( name );
+#endif
+  if ( node )
+  {
+    attributeSet.Remove( node );
+    delete node;
+  }
+}
+
+const TiXmlElement* TiXmlNode::FirstChildElement() const
+{
+  const TiXmlNode* node;
+
+  for (   node = FirstChild();
+          node;
+          node = node->NextSibling() )
+  {
+    if ( node->ToElement() )
+      return node->ToElement();
+  }
+  return 0;
+}
+
+
+const TiXmlElement* TiXmlNode::FirstChildElement( const char * _value ) const
+{
+  const TiXmlNode* node;
+
+  for (   node = FirstChild( _value );
+          node;
+          node = node->NextSibling( _value ) )
+  {
+    if ( node->ToElement() )
+      return node->ToElement();
+  }
+  return 0;
+}
+
+
+const TiXmlElement* TiXmlNode::NextSiblingElement() const
+{
+  const TiXmlNode* node;
+
+  for (   node = NextSibling();
+          node;
+          node = node->NextSibling() )
+  {
+    if ( node->ToElement() )
+      return node->ToElement();
+  }
+  return 0;
+}
+
+
+const TiXmlElement* TiXmlNode::NextSiblingElement( const char * _value ) const
+{
+  const TiXmlNode* node;
+
+  for (   node = NextSibling( _value );
+          node;
+          node = node->NextSibling( _value ) )
+  {
+    if ( node->ToElement() )
+      return node->ToElement();
+  }
+  return 0;
+}
+
+
+const TiXmlDocument* TiXmlNode::GetDocument() const
+{
+  const TiXmlNode* node;
+
+  for( node = this; node; node = node->parent )
+  {
+    if ( node->ToDocument() )
+      return node->ToDocument();
+  }
+  return 0;
+}
+
+
+TiXmlElement::TiXmlElement (const char * _value)
+  : TiXmlNode( TiXmlNode::TINYXML_ELEMENT )
+{
+  firstChild = lastChild = 0;
+  value = _value;
+}
+
+
+#ifdef TIXML_USE_STL
+TiXmlElement::TiXmlElement( const std::string& _value )
+  : TiXmlNode( TiXmlNode::TINYXML_ELEMENT )
+{
+  firstChild = lastChild = 0;
+  value = _value;
+}
+#endif
+
+
+TiXmlElement::TiXmlElement( const TiXmlElement& copy)
+  : TiXmlNode( TiXmlNode::TINYXML_ELEMENT )
+{
+  firstChild = lastChild = 0;
+  copy.CopyTo( this );
+}
+
+
+void TiXmlElement::operator=( const TiXmlElement& base )
+{
+  ClearThis();
+  base.CopyTo( this );
+}
+
+
+TiXmlElement::~TiXmlElement()
+{
+  ClearThis();
+}
+
+
+void TiXmlElement::ClearThis()
+{
+  Clear();
+  while( attributeSet.First() )
+  {
+    TiXmlAttribute* node = attributeSet.First();
+    attributeSet.Remove( node );
+    delete node;
+  }
+}
+
+
+const char* TiXmlElement::Attribute( const char* name ) const
+{
+  const TiXmlAttribute* node = attributeSet.Find( name );
+  if ( node )
+    return node->Value();
+  return 0;
+}
+
+
+#ifdef TIXML_USE_STL
+const std::string* TiXmlElement::Attribute( const std::string& name ) const
+{
+  const TiXmlAttribute* attrib = attributeSet.Find( name );
+  if ( attrib )
+    return &attrib->ValueStr();
+  return 0;
+}
+#endif
+
+
+const char* TiXmlElement::Attribute( const char* name, int* i ) const
+{
+  const TiXmlAttribute* attrib = attributeSet.Find( name );
+  const char* result = 0;
+
+  if ( attrib ) {
+    result = attrib->Value();
+    if ( i ) {
+      attrib->QueryIntValue( i );
+    }
+  }
+  return result;
+}
+
+
+#ifdef TIXML_USE_STL
+const std::string* TiXmlElement::Attribute( const std::string& name, int* i ) const
+{
+  const TiXmlAttribute* attrib = attributeSet.Find( name );
+  const std::string* result = 0;
+
+  if ( attrib ) {
+    result = &attrib->ValueStr();
+    if ( i ) {
+      attrib->QueryIntValue( i );
+    }
+  }
+  return result;
+}
+#endif
+
+
+const char* TiXmlElement::Attribute( const char* name, double* d ) const
+{
+  const TiXmlAttribute* attrib = attributeSet.Find( name );
+  const char* result = 0;
+
+  if ( attrib ) {
+    result = attrib->Value();
+    if ( d ) {
+      attrib->QueryDoubleValue( d );
+    }
+  }
+  return result;
+}
+
+
+#ifdef TIXML_USE_STL
+const std::string* TiXmlElement::Attribute( const std::string& name, double* d ) const
+{
+  const TiXmlAttribute* attrib = attributeSet.Find( name );
+  const std::string* result = 0;
+
+  if ( attrib ) {
+    result = &attrib->ValueStr();
+    if ( d ) {
+      attrib->QueryDoubleValue( d );
+    }
+  }
+  return result;
+}
+#endif
+
+
+int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const
+{
+  const TiXmlAttribute* attrib = attributeSet.Find( name );
+  if ( !attrib )
+    return TIXML_NO_ATTRIBUTE;
+  return attrib->QueryIntValue( ival );
+}
+
+
+#ifdef TIXML_USE_STL
+int TiXmlElement::QueryIntAttribute( const std::string& name, int* ival ) const
+{
+  const TiXmlAttribute* attrib = attributeSet.Find( name );
+  if ( !attrib )
+    return TIXML_NO_ATTRIBUTE;
+  return attrib->QueryIntValue( ival );
+}
+#endif
+
+
+int TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const
+{
+  const TiXmlAttribute* attrib = attributeSet.Find( name );
+  if ( !attrib )
+    return TIXML_NO_ATTRIBUTE;
+  return attrib->QueryDoubleValue( dval );
+}
+
+
+#ifdef TIXML_USE_STL
+int TiXmlElement::QueryDoubleAttribute( const std::string& name, double* dval ) const
+{
+  const TiXmlAttribute* attrib = attributeSet.Find( name );
+  if ( !attrib )
+    return TIXML_NO_ATTRIBUTE;
+  return attrib->QueryDoubleValue( dval );
+}
+#endif
+
+
+void TiXmlElement::SetAttribute( const char * name, int val )
+{
+  TiXmlAttribute* attrib = attributeSet.FindOrCreate( name );
+  if ( attrib ) {
+    attrib->SetIntValue( val );
+  }
+}
+
+
+#ifdef TIXML_USE_STL
+void TiXmlElement::SetAttribute( const std::string& name, int val )
+{
+  TiXmlAttribute* attrib = attributeSet.FindOrCreate( name );
+  if ( attrib ) {
+    attrib->SetIntValue( val );
+  }
+}
+#endif
+
+
+void TiXmlElement::SetDoubleAttribute( const char * name, double val )
+{
+  TiXmlAttribute* attrib = attributeSet.FindOrCreate( name );
+  if ( attrib ) {
+    attrib->SetDoubleValue( val );
+  }
+}
+
+
+#ifdef TIXML_USE_STL
+void TiXmlElement::SetDoubleAttribute( const std::string& name, double val )
+{
+  TiXmlAttribute* attrib = attributeSet.FindOrCreate( name );
+  if ( attrib ) {
+    attrib->SetDoubleValue( val );
+  }
+}
+#endif
+
+
+void TiXmlElement::SetAttribute( const char * cname, const char * cvalue )
+{
+  TiXmlAttribute* attrib = attributeSet.FindOrCreate( cname );
+  if ( attrib ) {
+    attrib->SetValue( cvalue );
+  }
+}
+
+
+#ifdef TIXML_USE_STL
+void TiXmlElement::SetAttribute( const std::string& _name, const std::string& _value )
+{
+  TiXmlAttribute* attrib = attributeSet.FindOrCreate( _name );
+  if ( attrib ) {
+    attrib->SetValue( _value );
+  }
+}
+#endif
+
+
+void TiXmlElement::Print( FILE* cfile, int depth ) const
+{
+  int i;
+  assert( cfile );
+  for ( i=0; i<depth; i++ ) {
+    fprintf( cfile, "    " );
+  }
+
+  fprintf( cfile, "<%s", value.c_str() );
+
+  const TiXmlAttribute* attrib;
+  for ( attrib = attributeSet.First(); attrib; attrib = attrib->Next() )
+  {
+    fprintf( cfile, " " );
+    attrib->Print( cfile, depth );
+  }
+
+  // There are 3 different formatting approaches:
+  // 1) An element without children is printed as a <foo /> node
+  // 2) An element with only a text child is printed as <foo> text </foo>
+  // 3) An element with children is printed on multiple lines.
+  TiXmlNode* node;
+  if ( !firstChild )
+  {
+    fprintf( cfile, " />" );
+  }
+  else if ( firstChild == lastChild && firstChild->ToText() )
+  {
+    fprintf( cfile, ">" );
+    firstChild->Print( cfile, depth + 1 );
+    fprintf( cfile, "</%s>", value.c_str() );
+  }
+  else
+  {
+    fprintf( cfile, ">" );
+
+    for ( node = firstChild; node; node=node->NextSibling() )
+    {
+      if ( !node->ToText() )
+      {
+        fprintf( cfile, "\n" );
+      }
+      node->Print( cfile, depth+1 );
+    }
+    fprintf( cfile, "\n" );
+    for( i=0; i<depth; ++i ) {
+      fprintf( cfile, "    " );
+    }
+    fprintf( cfile, "</%s>", value.c_str() );
+  }
+}
+
+
+void TiXmlElement::CopyTo( TiXmlElement* target ) const
+{
+  // superclass:
+  TiXmlNode::CopyTo( target );
+
+  // Element class:
+  // Clone the attributes, then clone the children.
+  const TiXmlAttribute* attribute = 0;
+  for(    attribute = attributeSet.First();
+          attribute;
+          attribute = attribute->Next() )
+  {
+    target->SetAttribute( attribute->Name(), attribute->Value() );
+  }
+
+  TiXmlNode* node = 0;
+  for ( node = firstChild; node; node = node->NextSibling() )
+  {
+    target->LinkEndChild( node->Clone() );
+  }
+}
+
+bool TiXmlElement::Accept( TiXmlVisitor* visitor ) const
+{
+  if ( visitor->VisitEnter( *this, attributeSet.First() ) )
+  {
+    for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() )
+    {
+      if ( !node->Accept( visitor ) )
+        break;
+    }
+  }
+  return visitor->VisitExit( *this );
+}
+
+
+TiXmlNode* TiXmlElement::Clone() const
+{
+  TiXmlElement* clone = new TiXmlElement( Value() );
+  if ( !clone )
+    return 0;
+
+  CopyTo( clone );
+  return clone;
+}
+
+
+const char* TiXmlElement::GetText() const
+{
+  const TiXmlNode* child = this->FirstChild();
+  if ( child ) {
+    const TiXmlText* childText = child->ToText();
+    if ( childText ) {
+      return childText->Value();
+    }
+  }
+  return 0;
+}
+
+
+TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT )
+{
+  tabsize = 4;
+  useMicrosoftBOM = false;
+  ClearError();
+}
+
+TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT )
+{
+  tabsize = 4;
+  useMicrosoftBOM = false;
+  value = documentName;
+  ClearError();
+}
+
+
+#ifdef TIXML_USE_STL
+TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT )
+{
+  tabsize = 4;
+  useMicrosoftBOM = false;
+  value = documentName;
+  ClearError();
+}
+#endif
+
+
+TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT )
+{
+  copy.CopyTo( this );
+}
+
+
+void TiXmlDocument::operator=( const TiXmlDocument& copy )
+{
+  Clear();
+  copy.CopyTo( this );
+}
+
+
+bool TiXmlDocument::LoadFile( TiXmlEncoding encoding )
+{
+  return LoadFile( Value(), encoding );
+}
+
+
+bool TiXmlDocument::SaveFile() const
+{
+  return SaveFile( Value() );
+}
+
+bool TiXmlDocument::LoadFile( const char* _filename, TiXmlEncoding encoding )
+{
+  TIXML_STRING filename( _filename );
+  value = filename;
+
+  // reading in binary mode so that tinyxml can normalize the EOL
+  FILE* file = TiXmlFOpen( value.c_str (), "rb" );
+
+  if ( file )
+  {
+    bool result = LoadFile( file, encoding );
+    fclose( file );
+    return result;
+  }
+  else
+  {
+    SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );
+    return false;
+  }
+}
+
+bool TiXmlDocument::LoadFile( FILE* file, TiXmlEncoding encoding )
+{
+  if ( !file )
+  {
+    SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );
+    return false;
+  }
+
+  // Delete the existing data:
+  Clear();
+  location.Clear();
+
+  // Get the file size, so we can pre-allocate the string. HUGE speed impact.
+  long length = 0;
+  fseek( file, 0, SEEK_END );
+  length = ftell( file );
+  fseek( file, 0, SEEK_SET );
+
+  // Strange case, but good to handle up front.
+  if ( length <= 0 )
+  {
+    SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
+    return false;
+  }
+
+  // Subtle bug here. TinyXml did use fgets. But from the XML spec:
+  // 2.11 End-of-Line Handling
+  // <snip>
+  // <quote>
+  // ...the XML processor MUST behave as if it normalized all line breaks in external
+  // parsed entities (including the document entity) on input, before parsing, by translating
+  // both the two-character sequence #xD #xA and any #xD that is not followed by #xA to
+  // a single #xA character.
+  // </quote>
+  //
+  // It is not clear fgets does that, and certainly isn't clear it works cross platform.
+  // Generally, you expect fgets to translate from the convention of the OS to the c/unix
+  // convention, and not work generally.
+
+  /*
+    while( fgets( buf, sizeof(buf), file ) )
+    {
+    data += buf;
+    }
+  */
+
+  char* buf = new char[ length+1 ];
+  buf[0] = 0;
+
+  if ( fread( buf, length, 1, file ) != 1 ) {
+    delete [] buf;
+    SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );
+    return false;
+  }
+
+  // Process the buffer in place to normalize new lines. (See comment above.)
+  // Copies from the 'p' to 'q' pointer, where p can advance faster if
+  // a newline-carriage return is hit.
+  //
+  // Wikipedia:
+  // Systems based on ASCII or a compatible character set use either LF  (Line feed, '\n', 0x0A, 10 in decimal) or
+  // CR (Carriage return, '\r', 0x0D, 13 in decimal) individually, or CR followed by LF (CR+LF, 0x0D 0x0A)...
+  //              * LF:    Multics, Unix and Unix-like systems (GNU/Linux, AIX, Xenix, Mac OS X, FreeBSD, etc.), BeOS, Amiga, RISC OS, and others
+  //          * CR+LF: DEC RT-11 and most other early non-Unix, non-IBM OSes, CP/M, MP/M, DOS, OS/2, Microsoft Windows, Symbian OS
+  //          * CR:    Commodore 8-bit machines, Apple II family, Mac OS up to version 9 and OS-9
+
+  const char* p = buf;    // the read head
+  char* q = buf;                  // the write head
+  const char CR = 0x0d;
+  const char LF = 0x0a;
+
+  buf[length] = 0;
+  while( *p ) {
+    assert( p < (buf+length) );
+    assert( q <= (buf+length) );
+    assert( q <= p );
+
+    if ( *p == CR ) {
+      *q++ = LF;
+      p++;
+      if ( *p == LF ) {               // check for CR+LF (and skip LF)
+        p++;
+      }
+    }
+    else {
+      *q++ = *p++;
+    }
+  }
+  assert( q <= (buf+length) );
+  *q = 0;
+
+  Parse( buf, 0, encoding );
+
+  delete [] buf;
+  return !Error();
+}
+
+
+bool TiXmlDocument::SaveFile( const char * filename ) const
+{
+  // The old c stuff lives on...
+  FILE* fp = TiXmlFOpen( filename, "w" );
+  if ( fp )
+  {
+    bool result = SaveFile( fp );
+    fclose( fp );
+    return result;
+  }
+  return false;
+}
+
+
+bool TiXmlDocument::SaveFile( FILE* fp ) const
+{
+  if ( useMicrosoftBOM )
+  {
+    const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
+    const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
+    const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
+
+    fputc( TIXML_UTF_LEAD_0, fp );
+    fputc( TIXML_UTF_LEAD_1, fp );
+    fputc( TIXML_UTF_LEAD_2, fp );
+  }
+  Print( fp, 0 );
+  return (ferror(fp) == 0);
+}
+
+
+void TiXmlDocument::CopyTo( TiXmlDocument* target ) const
+{
+  TiXmlNode::CopyTo( target );
+
+  target->error = error;
+  target->errorId = errorId;
+  target->errorDesc = errorDesc;
+  target->tabsize = tabsize;
+  target->errorLocation = errorLocation;
+  target->useMicrosoftBOM = useMicrosoftBOM;
+
+  TiXmlNode* node = 0;
+  for ( node = firstChild; node; node = node->NextSibling() )
+  {
+    target->LinkEndChild( node->Clone() );
+  }
+}
+
+
+TiXmlNode* TiXmlDocument::Clone() const
+{
+  TiXmlDocument* clone = new TiXmlDocument();
+  if ( !clone )
+    return 0;
+
+  CopyTo( clone );
+  return clone;
+}
+
+
+void TiXmlDocument::Print( FILE* cfile, int depth ) const
+{
+  assert( cfile );
+  for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() )
+  {
+    node->Print( cfile, depth );
+    fprintf( cfile, "\n" );
+  }
+}
+
+
+bool TiXmlDocument::Accept( TiXmlVisitor* visitor ) const
+{
+  if ( visitor->VisitEnter( *this ) )
+  {
+    for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() )
+    {
+      if ( !node->Accept( visitor ) )
+        break;
+    }
+  }
+  return visitor->VisitExit( *this );
+}
+
+
+const TiXmlAttribute* TiXmlAttribute::Next() const
+{
+  // We are using knowledge of the sentinel. The sentinel
+  // have a value or name.
+  if ( next->value.empty() && next->name.empty() )
+    return 0;
+  return next;
+}
+
+/*
+  TiXmlAttribute* TiXmlAttribute::Next()
+  {
+  // We are using knowledge of the sentinel. The sentinel
+  // have a value or name.
+  if ( next->value.empty() && next->name.empty() )
+  return 0;
+  return next;
+  }
+*/
+
+const TiXmlAttribute* TiXmlAttribute::Previous() const
+{
+  // We are using knowledge of the sentinel. The sentinel
+  // have a value or name.
+  if ( prev->value.empty() && prev->name.empty() )
+    return 0;
+  return prev;
+}
+
+/*
+  TiXmlAttribute* TiXmlAttribute::Previous()
+  {
+  // We are using knowledge of the sentinel. The sentinel
+  // have a value or name.
+  if ( prev->value.empty() && prev->name.empty() )
+  return 0;
+  return prev;
+  }
+*/
+
+void TiXmlAttribute::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const
+{
+  TIXML_STRING n, v;
+
+  EncodeString( name, &n );
+  EncodeString( value, &v );
+
+  if (value.find ('\"') == TIXML_STRING::npos) {
+    if ( cfile ) {
+      fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() );
+    }
+    if ( str ) {
+      (*str) += n; (*str) += "=\""; (*str) += v; (*str) += "\"";
+    }
+  }
+  else {
+    if ( cfile ) {
+      fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() );
+    }
+    if ( str ) {
+      (*str) += n; (*str) += "='"; (*str) += v; (*str) += "'";
+    }
+  }
+}
+
+
+int TiXmlAttribute::QueryIntValue( int* ival ) const
+{
+  if ( TIXML_SSCANF( value.c_str(), "%d", ival ) == 1 )
+    return TIXML_SUCCESS;
+  return TIXML_WRONG_TYPE;
+}
+
+int TiXmlAttribute::QueryDoubleValue( double* dval ) const
+{
+  if ( TIXML_SSCANF( value.c_str(), "%lf", dval ) == 1 )
+    return TIXML_SUCCESS;
+  return TIXML_WRONG_TYPE;
+}
+
+void TiXmlAttribute::SetIntValue( int _value )
+{
+  char buf [64];
+#if defined(TIXML_SNPRINTF)
+  TIXML_SNPRINTF(buf, sizeof(buf), "%d", _value);
+#else
+  sprintf (buf, "%d", _value);
+#endif
+  SetValue (buf);
+}
+
+void TiXmlAttribute::SetDoubleValue( double _value )
+{
+  char buf [256];
+#if defined(TIXML_SNPRINTF)
+  TIXML_SNPRINTF( buf, sizeof(buf), "%g", _value);
+#else
+  sprintf (buf, "%g", _value);
+#endif
+  SetValue (buf);
+}
+
+int TiXmlAttribute::IntValue() const
+{
+  return atoi (value.c_str ());
+}
+
+double  TiXmlAttribute::DoubleValue() const
+{
+  return atof (value.c_str ());
+}
+
+
+TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::TINYXML_COMMENT )
+{
+  copy.CopyTo( this );
+}
+
+
+void TiXmlComment::operator=( const TiXmlComment& base )
+{
+  Clear();
+  base.CopyTo( this );
+}
+
+
+void TiXmlComment::Print( FILE* cfile, int depth ) const
+{
+  assert( cfile );
+  for ( int i=0; i<depth; i++ )
+  {
+    fprintf( cfile,  "    " );
+  }
+  fprintf( cfile, "<!--%s-->", value.c_str() );
+}
+
+
+void TiXmlComment::CopyTo( TiXmlComment* target ) const
+{
+  TiXmlNode::CopyTo( target );
+}
+
+
+bool TiXmlComment::Accept( TiXmlVisitor* visitor ) const
+{
+  return visitor->Visit( *this );
+}
+
+
+TiXmlNode* TiXmlComment::Clone() const
+{
+  TiXmlComment* clone = new TiXmlComment();
+
+  if ( !clone )
+    return 0;
+
+  CopyTo( clone );
+  return clone;
+}
+
+
+void TiXmlText::Print( FILE* cfile, int depth ) const
+{
+  assert( cfile );
+  if ( cdata )
+  {
+    int i;
+    fprintf( cfile, "\n" );
+    for ( i=0; i<depth; i++ ) {
+      fprintf( cfile, "    " );
+    }
+    fprintf( cfile, "<![CDATA[%s]]>\n", value.c_str() );    // unformatted output
+  }
+  else
+  {
+    TIXML_STRING buffer;
+    EncodeString( value, &buffer );
+    fprintf( cfile, "%s", buffer.c_str() );
+  }
+}
+
+
+void TiXmlText::CopyTo( TiXmlText* target ) const
+{
+  TiXmlNode::CopyTo( target );
+  target->cdata = cdata;
+}
+
+
+bool TiXmlText::Accept( TiXmlVisitor* visitor ) const
+{
+  return visitor->Visit( *this );
+}
+
+
+TiXmlNode* TiXmlText::Clone() const
+{
+  TiXmlText* clone = 0;
+  clone = new TiXmlText( "" );
+
+  if ( !clone )
+    return 0;
+
+  CopyTo( clone );
+  return clone;
+}
+
+
+TiXmlDeclaration::TiXmlDeclaration( const char * _version,
+                                    const char * _encoding,
+                                    const char * _standalone )
+  : TiXmlNode( TiXmlNode::TINYXML_DECLARATION )
+{
+  version = _version;
+  encoding = _encoding;
+  standalone = _standalone;
+}
+
+
+#ifdef TIXML_USE_STL
+TiXmlDeclaration::TiXmlDeclaration(     const std::string& _version,
+                                        const std::string& _encoding,
+                                        const std::string& _standalone )
+  : TiXmlNode( TiXmlNode::TINYXML_DECLARATION )
+{
+  version = _version;
+  encoding = _encoding;
+  standalone = _standalone;
+}
+#endif
+
+
+TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy )
+  : TiXmlNode( TiXmlNode::TINYXML_DECLARATION )
+{
+  copy.CopyTo( this );
+}
+
+
+void TiXmlDeclaration::operator=( const TiXmlDeclaration& copy )
+{
+  Clear();
+  copy.CopyTo( this );
+}
+
+
+void TiXmlDeclaration::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const
+{
+  if ( cfile ) fprintf( cfile, "<?xml " );
+  if ( str )       (*str) += "<?xml ";
+
+  if ( !version.empty() ) {
+    if ( cfile ) fprintf (cfile, "version=\"%s\" ", version.c_str ());
+    if ( str ) { (*str) += "version=\""; (*str) += version; (*str) += "\" "; }
+  }
+  if ( !encoding.empty() ) {
+    if ( cfile ) fprintf (cfile, "encoding=\"%s\" ", encoding.c_str ());
+    if ( str ) { (*str) += "encoding=\""; (*str) += encoding; (*str) += "\" "; }
+  }
+  if ( !standalone.empty() ) {
+    if ( cfile ) fprintf (cfile, "standalone=\"%s\" ", standalone.c_str ());
+    if ( str ) { (*str) += "standalone=\""; (*str) += standalone; (*str) += "\" "; }
+  }
+  if ( cfile ) fprintf( cfile, "?>" );
+  if ( str )       (*str) += "?>";
+}
+
+
+void TiXmlDeclaration::CopyTo( TiXmlDeclaration* target ) const
+{
+  TiXmlNode::CopyTo( target );
+
+  target->version = version;
+  target->encoding = encoding;
+  target->standalone = standalone;
+}
+
+
+bool TiXmlDeclaration::Accept( TiXmlVisitor* visitor ) const
+{
+  return visitor->Visit( *this );
+}
+
+
+TiXmlNode* TiXmlDeclaration::Clone() const
+{
+  TiXmlDeclaration* clone = new TiXmlDeclaration();
+
+  if ( !clone )
+    return 0;
+
+  CopyTo( clone );
+  return clone;
+}
+
+
+void TiXmlUnknown::Print( FILE* cfile, int depth ) const
+{
+  for ( int i=0; i<depth; i++ )
+    fprintf( cfile, "    " );
+  fprintf( cfile, "<%s>", value.c_str() );
+}
+
+
+void TiXmlUnknown::CopyTo( TiXmlUnknown* target ) const
+{
+  TiXmlNode::CopyTo( target );
+}
+
+
+bool TiXmlUnknown::Accept( TiXmlVisitor* visitor ) const
+{
+  return visitor->Visit( *this );
+}
+
+
+TiXmlNode* TiXmlUnknown::Clone() const
+{
+  TiXmlUnknown* clone = new TiXmlUnknown();
+
+  if ( !clone )
+    return 0;
+
+  CopyTo( clone );
+  return clone;
+}
+
+
+TiXmlAttributeSet::TiXmlAttributeSet()
+{
+  sentinel.next = &sentinel;
+  sentinel.prev = &sentinel;
+}
+
+
+TiXmlAttributeSet::~TiXmlAttributeSet()
+{
+  assert( sentinel.next == &sentinel );
+  assert( sentinel.prev == &sentinel );
+}
+
+
+void TiXmlAttributeSet::Add( TiXmlAttribute* addMe )
+{
+#ifdef TIXML_USE_STL
+  assert( !Find( TIXML_STRING( addMe->Name() ) ) );       // Shouldn't be multiply adding to the set.
+#else
+  assert( !Find( addMe->Name() ) );       // Shouldn't be multiply adding to the set.
+#endif
+
+  addMe->next = &sentinel;
+  addMe->prev = sentinel.prev;
+
+  sentinel.prev->next = addMe;
+  sentinel.prev      = addMe;
+}
+
+void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe )
+{
+  TiXmlAttribute* node;
+
+  for( node = sentinel.next; node != &sentinel; node = node->next )
+  {
+    if ( node == removeMe )
+    {
+      node->prev->next = node->next;
+      node->next->prev = node->prev;
+      node->next = 0;
+      node->prev = 0;
+      return;
+    }
+  }
+  assert( 0 );            // we tried to remove a non-linked attribute.
+}
+
+
+#ifdef TIXML_USE_STL
+TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) const
+{
+  for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next )
+  {
+    if ( node->name == name )
+      return node;
+  }
+  return 0;
+}
+
+TiXmlAttribute* TiXmlAttributeSet::FindOrCreate( const std::string& _name )
+{
+  TiXmlAttribute* attrib = Find( _name );
+  if ( !attrib ) {
+    attrib = new TiXmlAttribute();
+    Add( attrib );
+    attrib->SetName( _name );
+  }
+  return attrib;
+}
+#endif
+
+
+TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) const
+{
+  for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next )
+  {
+    if ( strcmp( node->name.c_str(), name ) == 0 )
+      return node;
+  }
+  return 0;
+}
+
+
+TiXmlAttribute* TiXmlAttributeSet::FindOrCreate( const char* _name )
+{
+  TiXmlAttribute* attrib = Find( _name );
+  if ( !attrib ) {
+    attrib = new TiXmlAttribute();
+    Add( attrib );
+    attrib->SetName( _name );
+  }
+  return attrib;
+}
+
+
+#ifdef TIXML_USE_STL
+std::istream& operator>> (std::istream & in, TiXmlNode & base)
+{
+  TIXML_STRING tag;
+  tag.reserve( 8 * 1000 );
+  base.StreamIn( &in, &tag );
+
+  base.Parse( tag.c_str(), 0, TIXML_DEFAULT_ENCODING );
+  return in;
+}
+#endif
+
+
+#ifdef TIXML_USE_STL
+std::ostream& operator<< (std::ostream & out, const TiXmlNode & base)
+{
+  TiXmlPrinter printer;
+  printer.SetStreamPrinting();
+  base.Accept( &printer );
+  out << printer.Str();
+
+  return out;
+}
+
+
+std::string& operator<< (std::string& out, const TiXmlNode& base )
+{
+  TiXmlPrinter printer;
+  printer.SetStreamPrinting();
+  base.Accept( &printer );
+  out.append( printer.Str() );
+
+  return out;
+}
+#endif
+
+
+TiXmlHandle TiXmlHandle::FirstChild() const
+{
+  if ( node )
+  {
+    TiXmlNode* child = node->FirstChild();
+    if ( child )
+      return TiXmlHandle( child );
+  }
+  return TiXmlHandle( 0 );
+}
+
+
+TiXmlHandle TiXmlHandle::FirstChild( const char * value ) const
+{
+  if ( node )
+  {
+    TiXmlNode* child = node->FirstChild( value );
+    if ( child )
+      return TiXmlHandle( child );
+  }
+  return TiXmlHandle( 0 );
+}
+
+
+TiXmlHandle TiXmlHandle::FirstChildElement() const
+{
+  if ( node )
+  {
+    TiXmlElement* child = node->FirstChildElement();
+    if ( child )
+      return TiXmlHandle( child );
+  }
+  return TiXmlHandle( 0 );
+}
+
+
+TiXmlHandle TiXmlHandle::FirstChildElement( const char * value ) const
+{
+  if ( node )
+  {
+    TiXmlElement* child = node->FirstChildElement( value );
+    if ( child )
+      return TiXmlHandle( child );
+  }
+  return TiXmlHandle( 0 );
+}
+
+
+TiXmlHandle TiXmlHandle::Child( int count ) const
+{
+  if ( node )
+  {
+    int i;
+    TiXmlNode* child = node->FirstChild();
+    for (   i=0;
+            child && i<count;
+            child = child->NextSibling(), ++i )
+    {
+      // nothing
+    }
+    if ( child )
+      return TiXmlHandle( child );
+  }
+  return TiXmlHandle( 0 );
+}
+
+
+TiXmlHandle TiXmlHandle::Child( const char* value, int count ) const
+{
+  if ( node )
+  {
+    int i;
+    TiXmlNode* child = node->FirstChild( value );
+    for (   i=0;
+            child && i<count;
+            child = child->NextSibling( value ), ++i )
+    {
+      // nothing
+    }
+    if ( child )
+      return TiXmlHandle( child );
+  }
+  return TiXmlHandle( 0 );
+}
+
+
+TiXmlHandle TiXmlHandle::ChildElement( int count ) const
+{
+  if ( node )
+  {
+    int i;
+    TiXmlElement* child = node->FirstChildElement();
+    for (   i=0;
+            child && i<count;
+            child = child->NextSiblingElement(), ++i )
+    {
+      // nothing
+    }
+    if ( child )
+      return TiXmlHandle( child );
+  }
+  return TiXmlHandle( 0 );
+}
+
+
+TiXmlHandle TiXmlHandle::ChildElement( const char* value, int count ) const
+{
+  if ( node )
+  {
+    int i;
+    TiXmlElement* child = node->FirstChildElement( value );
+    for (   i=0;
+            child && i<count;
+            child = child->NextSiblingElement( value ), ++i )
+    {
+      // nothing
+    }
+    if ( child )
+      return TiXmlHandle( child );
+  }
+  return TiXmlHandle( 0 );
+}
+
+
+bool TiXmlPrinter::VisitEnter( const TiXmlDocument& )
+{
+  return true;
+}
+
+bool TiXmlPrinter::VisitExit( const TiXmlDocument& )
+{
+  return true;
+}
+
+bool TiXmlPrinter::VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute )
+{
+  DoIndent();
+  buffer += "<";
+  buffer += element.Value();
+
+  for( const TiXmlAttribute* attrib = firstAttribute; attrib; attrib = attrib->Next() )
+  {
+    buffer += " ";
+    attrib->Print( 0, 0, &buffer );
+  }
+
+  if ( !element.FirstChild() )
+  {
+    buffer += " />";
+    DoLineBreak();
+  }
+  else
+  {
+    buffer += ">";
+    if (    element.FirstChild()->ToText()
+            && element.LastChild() == element.FirstChild()
+            && element.FirstChild()->ToText()->CDATA() == false )
+    {
+      simpleTextPrint = true;
+      // no DoLineBreak()!
+    }
+    else
+    {
+      DoLineBreak();
+    }
+  }
+  ++depth;
+  return true;
+}
+
+
+bool TiXmlPrinter::VisitExit( const TiXmlElement& element )
+{
+  --depth;
+  if ( !element.FirstChild() )
+  {
+    // nothing.
+  }
+  else
+  {
+    if ( simpleTextPrint )
+    {
+      simpleTextPrint = false;
+    }
+    else
+    {
+      DoIndent();
+    }
+    buffer += "</";
+    buffer += element.Value();
+    buffer += ">";
+    DoLineBreak();
+  }
+  return true;
+}
+
+
+bool TiXmlPrinter::Visit( const TiXmlText& text )
+{
+  if ( text.CDATA() )
+  {
+    DoIndent();
+    buffer += "<![CDATA[";
+    buffer += text.Value();
+    buffer += "]]>";
+    DoLineBreak();
+  }
+  else if ( simpleTextPrint )
+  {
+    TIXML_STRING str;
+    TiXmlBase::EncodeString( text.ValueTStr(), &str );
+    buffer += str;
+  }
+  else
+  {
+    DoIndent();
+    TIXML_STRING str;
+    TiXmlBase::EncodeString( text.ValueTStr(), &str );
+    buffer += str;
+    DoLineBreak();
+  }
+  return true;
+}
+
+
+bool TiXmlPrinter::Visit( const TiXmlDeclaration& declaration )
+{
+  DoIndent();
+  declaration.Print( 0, 0, &buffer );
+  DoLineBreak();
+  return true;
+}
+
+
+bool TiXmlPrinter::Visit( const TiXmlComment& comment )
+{
+  DoIndent();
+  buffer += "<!--";
+  buffer += comment.Value();
+  buffer += "-->";
+  DoLineBreak();
+  return true;
+}
+
+
+bool TiXmlPrinter::Visit( const TiXmlUnknown& unknown )
+{
+  DoIndent();
+  buffer += "<";
+  buffer += unknown.Value();
+  buffer += ">";
+  DoLineBreak();
+  return true;
+}
diff --git a/lib/third_party/tinyxml/tinyxml.h b/lib/third_party/tinyxml/tinyxml.h
new file mode 100644 (file)
index 0000000..d8ad8e3
--- /dev/null
@@ -0,0 +1,1800 @@
+/*
+  www.sourceforge.net/projects/tinyxml
+  Original code (2.0 and earlier )copyright (c) 2000-2006 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 TINYXML_INCLUDED
+#define TINYXML_INCLUDED
+
+#ifdef _MSC_VER
+#pragma warning( push )
+#pragma warning( disable : 4530 )
+#pragma warning( disable : 4786 )
+#endif
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+// Help out windows:
+#if defined( _DEBUG ) && !defined( DEBUG )
+#define DEBUG
+#endif
+
+#ifdef TIXML_USE_STL
+#include <string>
+#include <iostream>
+#include <sstream>
+#define TIXML_STRING            std::string
+#else
+#include "tinystr.h"
+#define TIXML_STRING            TiXmlString
+#endif
+
+#include <tinyxml/cpPlugins_tinyxml_Export.h>
+
+// Deprecated library function hell. Compilers want to use the
+// new safe versions. This probably doesn't fully address the problem,
+// but it gets closer. There are too many compilers for me to fully
+// test. If you get compilation troubles, undefine TIXML_SAFE
+#define TIXML_SAFE
+
+#ifdef TIXML_SAFE
+#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
+// Microsoft visual studio, version 2005 and higher.
+#define TIXML_SNPRINTF _snprintf_s
+#define TIXML_SSCANF   sscanf_s
+#elif defined(_MSC_VER) && (_MSC_VER >= 1200 )
+// Microsoft visual studio, version 6 and higher.
+//#pragma message( "Using _sn* functions." )
+#define TIXML_SNPRINTF _snprintf
+#define TIXML_SSCANF   sscanf
+#elif defined(__GNUC__) && (__GNUC__ >= 3 )
+// GCC version 3 and higher.s
+//#warning( "Using sn* functions." )
+#define TIXML_SNPRINTF snprintf
+#define TIXML_SSCANF   sscanf
+#else
+#define TIXML_SNPRINTF snprintf
+#define TIXML_SSCANF   sscanf
+#endif
+#endif
+
+class TiXmlDocument;
+class TiXmlElement;
+class TiXmlComment;
+class TiXmlUnknown;
+class TiXmlAttribute;
+class TiXmlText;
+class TiXmlDeclaration;
+class TiXmlParsingData;
+
+const int TIXML_MAJOR_VERSION = 2;
+const int TIXML_MINOR_VERSION = 6;
+const int TIXML_PATCH_VERSION = 1;
+
+/*      Internal structure for tracking location of items
+        in the XML file.
+*/
+struct cpPlugins_tinyxml_EXPORT TiXmlCursor
+{
+  TiXmlCursor()           { Clear(); }
+  void Clear()            { row = col = -1; }
+
+  int row;        // 0 based.
+  int col;        // 0 based.
+};
+
+
+/**
+   Implements the interface to the "Visitor pattern" (see the Accept() method.)
+   If you call the Accept() method, it requires being passed a TiXmlVisitor
+   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 leaves
+   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 sibilings</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 suppert Visiting.
+
+   You should never change the document from a callback.
+
+   @sa TiXmlNode::Accept()
+*/
+class TiXmlVisitor
+{
+public:
+  virtual ~TiXmlVisitor() {}
+
+  /// Visit a document.
+  virtual bool VisitEnter( const TiXmlDocument& /*doc*/ )                 { return true; }
+  /// Visit a document.
+  virtual bool VisitExit( const TiXmlDocument& /*doc*/ )                  { return true; }
+
+  /// Visit an element.
+  virtual bool VisitEnter( const TiXmlElement& /*element*/, const TiXmlAttribute* /*firstAttribute*/ )    { return true; }
+  /// Visit an element.
+  virtual bool VisitExit( const TiXmlElement& /*element*/ )               { return true; }
+
+  /// Visit a declaration
+  virtual bool Visit( const TiXmlDeclaration& /*declaration*/ )   { return true; }
+  /// Visit a text node
+  virtual bool Visit( const TiXmlText& /*text*/ )                                 { return true; }
+  /// Visit a comment node
+  virtual bool Visit( const TiXmlComment& /*comment*/ )                   { return true; }
+  /// Visit an unknow node
+  virtual bool Visit( const TiXmlUnknown& /*unknown*/ )                   { return true; }
+};
+
+// Only used by Attribute::Query functions
+enum
+{
+  TIXML_SUCCESS,
+  TIXML_NO_ATTRIBUTE,
+  TIXML_WRONG_TYPE
+};
+
+
+// Used by the parsing routines.
+enum TiXmlEncoding
+{
+  TIXML_ENCODING_UNKNOWN,
+  TIXML_ENCODING_UTF8,
+  TIXML_ENCODING_LEGACY
+};
+
+const TiXmlEncoding TIXML_DEFAULT_ENCODING = TIXML_ENCODING_UNKNOWN;
+
+/** TiXmlBase is a base class for every class in TinyXml.
+    It does little except to establish that TinyXml classes
+    can be printed and provide some utility functions.
+
+    In XML, the document and elements can contain
+    other elements and other types of nodes.
+
+    @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)
+
+    A Decleration contains: Attributes (not on tree)
+    @endverbatim
+*/
+class cpPlugins_tinyxml_EXPORT TiXmlBase
+{
+  friend class TiXmlNode;
+  friend class TiXmlElement;
+  friend class TiXmlDocument;
+
+public:
+  TiXmlBase()     :       userData(0)             {}
+  virtual ~TiXmlBase()                    {}
+
+  /**     All TinyXml classes can print themselves to a filestream
+          or the string class (TiXmlString in non-STL mode, std::string
+          in STL mode.) Either or both cfile and str can be null.
+
+          This is a formatted print, and will insert
+          tabs and newlines.
+
+          (For an unformatted stream, use the << operator.)
+  */
+  virtual void Print( FILE* cfile, int depth ) const = 0;
+
+  /**     The world does not agree on whether white space should be kept or
+          not. In order to make everyone happy, these global, static functions
+          are provided to set whether or not TinyXml will condense all white space
+          into a single space or not. The default is to condense. Note changing this
+          value is not thread safe.
+  */
+  static void SetCondenseWhiteSpace( bool condense )              { condenseWhiteSpace = condense; }
+
+  /// Return the current white space setting.
+  static bool IsWhiteSpaceCondensed()                                             { return condenseWhiteSpace; }
+
+  /** Return the position, in the original source file, of this node or attribute.
+      The row and column are 1-based. (That is the first row and first column is
+      1,1). If the returns values are 0 or less, then the parser does not have
+      a row and column value.
+
+      Generally, the row and column value will be set when the TiXmlDocument::Load(),
+      TiXmlDocument::LoadFile(), or any TiXmlNode::Parse() is called. It will NOT be set
+      when the DOM was created from operator>>.
+
+      The values reflect the initial load. Once the DOM is modified programmatically
+      (by adding or changing nodes and attributes) the new values will NOT update to
+      reflect changes in the document.
+
+      There is a minor performance cost to computing the row and column. Computation
+      can be disabled if TiXmlDocument::SetTabSize() is called with 0 as the value.
+
+      @sa TiXmlDocument::SetTabSize()
+  */
+  int Row() const                 { return location.row + 1; }
+  int Column() const              { return location.col + 1; }    ///< See Row()
+
+  void  SetUserData( void* user )                 { userData = user; }    ///< Set a pointer to arbitrary user data.
+  void* GetUserData()                                             { return userData; }    ///< Get a pointer to arbitrary user data.
+  const void* GetUserData() const                 { return userData; }    ///< Get a pointer to arbitrary user data.
+
+  // Table that returs, for a given lead byte, the total number of bytes
+  // in the UTF-8 sequence.
+  static const int utf8ByteTable[256];
+
+  virtual const char* Parse(      const char* p,
+                                  TiXmlParsingData* data,
+                                  TiXmlEncoding encoding /*= TIXML_ENCODING_UNKNOWN */ ) = 0;
+
+  /** Expands entities in a string. Note this should not contian the tag's '<', '>', etc,
+      or they will be transformed into entities!
+  */
+  static void EncodeString( const TIXML_STRING& str, TIXML_STRING* out );
+
+  enum
+  {
+    TIXML_NO_ERROR = 0,
+    TIXML_ERROR,
+    TIXML_ERROR_OPENING_FILE,
+    TIXML_ERROR_PARSING_ELEMENT,
+    TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME,
+    TIXML_ERROR_READING_ELEMENT_VALUE,
+    TIXML_ERROR_READING_ATTRIBUTES,
+    TIXML_ERROR_PARSING_EMPTY,
+    TIXML_ERROR_READING_END_TAG,
+    TIXML_ERROR_PARSING_UNKNOWN,
+    TIXML_ERROR_PARSING_COMMENT,
+    TIXML_ERROR_PARSING_DECLARATION,
+    TIXML_ERROR_DOCUMENT_EMPTY,
+    TIXML_ERROR_EMBEDDED_NULL,
+    TIXML_ERROR_PARSING_CDATA,
+    TIXML_ERROR_DOCUMENT_TOP_ONLY,
+
+    TIXML_ERROR_STRING_COUNT
+  };
+
+protected:
+
+  static const char* SkipWhiteSpace( const char*, TiXmlEncoding encoding );
+
+  inline static bool IsWhiteSpace( char c )
+    {
+      return ( isspace( (unsigned char) c ) || c == '\n' || c == '\r' );
+    }
+  inline static bool IsWhiteSpace( int c )
+    {
+      if ( c < 256 )
+        return IsWhiteSpace( (char) c );
+      return false;   // Again, only truly correct for English/Latin...but usually works.
+    }
+
+#ifdef TIXML_USE_STL
+  static bool     StreamWhiteSpace( std::istream * in, TIXML_STRING * tag );
+  static bool StreamTo( std::istream * in, int character, TIXML_STRING * tag );
+#endif
+
+  /*      Reads an XML name into the string provided. Returns
+          a pointer just past the last character of the name,
+          or 0 if the function has an error.
+  */
+  static const char* ReadName( const char* p, TIXML_STRING* name, TiXmlEncoding encoding );
+
+  /*      Reads text. Returns a pointer past the given end tag.
+          Wickedly complex options, but it keeps the (sensitive) code in one place.
+  */
+  static const char* ReadText(    const char* in,                         // where to start
+                                  TIXML_STRING* text,                     // the string read
+                                  bool ignoreWhiteSpace,          // whether to keep the white space
+                                  const char* endTag,                     // what ends this text
+                                  bool ignoreCase,                        // whether to ignore case in the end tag
+                                  TiXmlEncoding encoding );       // the current encoding
+
+  // If an entity has been found, transform it into a character.
+  static const char* GetEntity( const char* in, char* value, int* length, TiXmlEncoding encoding );
+
+  // Get a character, while interpreting entities.
+  // The length can be from 0 to 4 bytes.
+  inline static const char* GetChar( const char* p, char* _value, int* length, TiXmlEncoding encoding )
+    {
+      assert( p );
+      if ( encoding == TIXML_ENCODING_UTF8 )
+      {
+        *length = utf8ByteTable[ *((const unsigned char*)p) ];
+        assert( *length >= 0 && *length < 5 );
+      }
+      else
+      {
+        *length = 1;
+      }
+
+      if ( *length == 1 )
+      {
+        if ( *p == '&' )
+          return GetEntity( p, _value, length, encoding );
+        *_value = *p;
+        return p+1;
+      }
+      else if ( *length )
+      {
+        //strncpy( _value, p, *length );        // lots of compilers don't like this function (unsafe),
+        // and the null terminator isn't needed
+        for( int i=0; p[i] && i<*length; ++i ) {
+          _value[i] = p[i];
+        }
+        return p + (*length);
+      }
+      else
+      {
+        // Not valid text.
+        return 0;
+      }
+    }
+
+  // Return true if the next characters in the stream are any of the endTag sequences.
+  // Ignore case only works for english, and should only be relied on when comparing
+  // to English words: StringEqual( p, "version", true ) is fine.
+  static bool StringEqual(        const char* p,
+                                  const char* endTag,
+                                  bool ignoreCase,
+                                  TiXmlEncoding encoding );
+
+  static const char* errorString[ TIXML_ERROR_STRING_COUNT ];
+
+  TiXmlCursor location;
+
+  /// Field containing a generic user pointer
+  void*                   userData;
+
+  // None of these methods are reliable for any language except English.
+  // Good for approximation, not great for accuracy.
+  static int IsAlpha( unsigned char anyByte, TiXmlEncoding encoding );
+  static int IsAlphaNum( unsigned char anyByte, TiXmlEncoding encoding );
+  inline static int ToLower( int v, TiXmlEncoding encoding )
+    {
+      if ( encoding == TIXML_ENCODING_UTF8 )
+      {
+        if ( v < 128 ) return tolower( v );
+        return v;
+      }
+      else
+      {
+        return tolower( v );
+      }
+    }
+  static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length );
+
+private:
+  TiXmlBase( const TiXmlBase& );                          // not implemented.
+  void operator=( const TiXmlBase& base );        // not allowed.
+
+  struct Entity
+  {
+    const char*     str;
+    unsigned int    strLength;
+    char                chr;
+  };
+  enum
+  {
+    NUM_ENTITY = 5,
+    MAX_ENTITY_LENGTH = 6
+
+  };
+  static Entity entity[ NUM_ENTITY ];
+  static bool condenseWhiteSpace;
+};
+
+
+/** The parent class for everything in the Document Object Model.
+    (Except for attributes).
+    Nodes have siblings, a parent, and children. A node can be
+    in a document, or stand on its own. The type of a TiXmlNode
+    can be queried, and it can be cast to its more defined type.
+*/
+class cpPlugins_tinyxml_EXPORT TiXmlNode : public TiXmlBase
+{
+  friend class TiXmlDocument;
+  friend class TiXmlElement;
+
+public:
+#ifdef TIXML_USE_STL
+
+  /** An input stream operator, for every class. Tolerant of newlines and
+      formatting, but doesn't expect them.
+  */
+  friend std::istream& operator >> (std::istream& in, TiXmlNode& base);
+
+  /** An output stream operator, for every class. Note that this outputs
+      without any newlines or formatting, as opposed to Print(), which
+      includes tabs and new lines.
+
+      The operator<< and operator>> are not completely symmetric. Writing
+      a node to a stream is very well defined. You'll get a nice stream
+      of output, without any extra whitespace or newlines.
+
+      But reading is not as well defined. (As it always is.) If you create
+      a TiXmlElement (for example) and read that from an input stream,
+      the text needs to define an element or junk will result. This is
+      true of all input streams, but it's worth keeping in mind.
+
+      A TiXmlDocument will read nodes until it reads a root element, and
+      all the children of that root element.
+  */
+  friend std::ostream& operator<< (std::ostream& out, const TiXmlNode& base);
+
+  /// Appends the XML node or attribute to a std::string.
+  friend std::string& operator<< (std::string& out, const TiXmlNode& base );
+
+#endif
+
+  /** The types of XML nodes supported by TinyXml. (All the
+      unsupported types are picked up by UNKNOWN.)
+  */
+  enum NodeType
+  {
+    TINYXML_DOCUMENT,
+    TINYXML_ELEMENT,
+    TINYXML_COMMENT,
+    TINYXML_UNKNOWN,
+    TINYXML_TEXT,
+    TINYXML_DECLARATION,
+    TINYXML_TYPECOUNT
+  };
+
+  virtual ~TiXmlNode();
+
+  /** The meaning of 'value' changes for the specific type of
+      TiXmlNode.
+      @verbatim
+      Document:       filename of the xml file
+      Element:        name of the element
+      Comment:        the comment text
+      Unknown:        the tag contents
+      Text:           the text string
+      @endverbatim
+
+      The subclasses will wrap this function.
+  */
+  const char *Value() const { return value.c_str (); }
+
+#ifdef TIXML_USE_STL
+  /** Return Value() as a std::string. If you only use STL,
+      this is more efficient than calling Value().
+      Only available in STL mode.
+  */
+  const std::string& ValueStr() const { return value; }
+#endif
+
+  const TIXML_STRING& ValueTStr() const { return value; }
+
+  /** Changes the value of the node. Defined as:
+      @verbatim
+      Document:       filename of the xml file
+      Element:        name of the element
+      Comment:        the comment text
+      Unknown:        the tag contents
+      Text:           the text string
+      @endverbatim
+  */
+  void SetValue(const char * _value) { value = _value;}
+
+#ifdef TIXML_USE_STL
+  /// STL std::string form.
+  void SetValue( const std::string& _value )      { value = _value; }
+#endif
+
+  /// Delete all the children of this node. Does not affect 'this'.
+  void Clear();
+
+  /// One step up the DOM.
+  TiXmlNode* Parent()                                                     { return parent; }
+  const TiXmlNode* Parent() const                         { return parent; }
+
+  const TiXmlNode* FirstChild()   const           { return firstChild; }  ///< The first child of this node. Will be null if there are no children.
+  TiXmlNode* FirstChild()                                         { return firstChild; }
+  const TiXmlNode* FirstChild( const char * value ) const;                        ///< The first child of this node with the matching 'value'. Will be null if none found.
+  /// The first child of this node with the matching 'value'. Will be null if none found.
+  TiXmlNode* FirstChild( const char * _value ) {
+    // Call through to the const version - safe since nothing is changed. Exiting syntax: cast this to a const (always safe)
+    // call the method, cast the return back to non-const.
+    return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->FirstChild( _value ));
+  }
+  const TiXmlNode* LastChild() const      { return lastChild; }           /// The last child of this node. Will be null if there are no children.
+  TiXmlNode* LastChild()  { return lastChild; }
+
+  const TiXmlNode* LastChild( const char * value ) const;                 /// The last child of this node matching 'value'. Will be null if there are no children.
+  TiXmlNode* LastChild( const char * _value ) {
+    return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->LastChild( _value ));
+  }
+
+#ifdef TIXML_USE_STL
+  const TiXmlNode* FirstChild( const std::string& _value ) const  {       return FirstChild (_value.c_str ());    }       ///< STL std::string form.
+  TiXmlNode* FirstChild( const std::string& _value )                              {       return FirstChild (_value.c_str ());    }       ///< STL std::string form.
+  const TiXmlNode* LastChild( const std::string& _value ) const   {       return LastChild (_value.c_str ());     }       ///< STL std::string form.
+  TiXmlNode* LastChild( const std::string& _value )                               {       return LastChild (_value.c_str ());     }       ///< STL std::string form.
+#endif
+
+  /** An alternate way to walk the children of a node.
+      One way to iterate over nodes is:
+      @verbatim
+      for( child = parent->FirstChild(); child; child = child->NextSibling() )
+      @endverbatim
+
+      IterateChildren does the same thing with the syntax:
+      @verbatim
+      child = 0;
+      while( child = parent->IterateChildren( child ) )
+      @endverbatim
+
+      IterateChildren takes the previous child as input and finds
+      the next one. If the previous child is null, it returns the
+      first. IterateChildren will return null when done.
+  */
+  const TiXmlNode* IterateChildren( const TiXmlNode* previous ) const;
+  TiXmlNode* IterateChildren( const TiXmlNode* previous ) {
+    return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( previous ) );
+  }
+
+  /// This flavor of IterateChildren searches for children with a particular 'value'
+  const TiXmlNode* IterateChildren( const char * value, const TiXmlNode* previous ) const;
+  TiXmlNode* IterateChildren( const char * _value, const TiXmlNode* previous ) {
+    return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( _value, previous ) );
+  }
+
+#ifdef TIXML_USE_STL
+  const TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) const  {       return IterateChildren (_value.c_str (), previous);     }       ///< STL std::string form.
+  TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) {    return IterateChildren (_value.c_str (), previous);     }       ///< STL std::string form.
+#endif
+
+  /** Add a new node related to this. Adds a child past the LastChild.
+      Returns a pointer to the new object or NULL if an error occured.
+  */
+  TiXmlNode* InsertEndChild( const TiXmlNode& addThis );
+
+
+  /** Add a new node related to this. Adds a child past the LastChild.
+
+  NOTE: the node to be added is passed by pointer, and will be
+  henceforth owned (and deleted) by tinyXml. This method is efficient
+  and avoids an extra copy, but should be used with care as it
+  uses a different memory model than the other insert functions.
+
+  @sa InsertEndChild
+  */
+  TiXmlNode* LinkEndChild( TiXmlNode* addThis );
+
+  /** Add a new node related to this. Adds a child before the specified child.
+      Returns a pointer to the new object or NULL if an error occured.
+  */
+  TiXmlNode* InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis );
+
+  /** Add a new node related to this. Adds a child after the specified child.
+      Returns a pointer to the new object or NULL if an error occured.
+  */
+  TiXmlNode* InsertAfterChild(  TiXmlNode* afterThis, const TiXmlNode& addThis );
+
+  /** Replace a child of this node.
+      Returns a pointer to the new object or NULL if an error occured.
+  */
+  TiXmlNode* ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis );
+
+  /// Delete a child of this node.
+  bool RemoveChild( TiXmlNode* removeThis );
+
+  /// Navigate to a sibling node.
+  const TiXmlNode* PreviousSibling() const                        { return prev; }
+  TiXmlNode* PreviousSibling()                                            { return prev; }
+
+  /// Navigate to a sibling node.
+  const TiXmlNode* PreviousSibling( const char * ) const;
+  TiXmlNode* PreviousSibling( const char *_prev ) {
+    return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->PreviousSibling( _prev ) );
+  }
+
+#ifdef TIXML_USE_STL
+  const TiXmlNode* PreviousSibling( const std::string& _value ) const     {       return PreviousSibling (_value.c_str ());       }       ///< STL std::string form.
+  TiXmlNode* PreviousSibling( const std::string& _value )                         {       return PreviousSibling (_value.c_str ());       }       ///< STL std::string form.
+  const TiXmlNode* NextSibling( const std::string& _value) const          {       return NextSibling (_value.c_str ());   }       ///< STL std::string form.
+  TiXmlNode* NextSibling( const std::string& _value)                                      {       return NextSibling (_value.c_str ());   }       ///< STL std::string form.
+#endif
+
+  /// Navigate to a sibling node.
+  const TiXmlNode* NextSibling() const                            { return next; }
+  TiXmlNode* NextSibling()                                                        { return next; }
+
+  /// Navigate to a sibling node with the given 'value'.
+  const TiXmlNode* NextSibling( const char * ) const;
+  TiXmlNode* NextSibling( const char* _next ) {
+    return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->NextSibling( _next ) );
+  }
+
+  /** Convenience function to get through elements.
+      Calls NextSibling and ToElement. Will skip all non-Element
+      nodes. Returns 0 if there is not another element.
+  */
+  const TiXmlElement* NextSiblingElement() const;
+  TiXmlElement* NextSiblingElement() {
+    return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement() );
+  }
+
+  /** Convenience function to get through elements.
+      Calls NextSibling and ToElement. Will skip all non-Element
+      nodes. Returns 0 if there is not another element.
+  */
+  const TiXmlElement* NextSiblingElement( const char * ) const;
+  TiXmlElement* NextSiblingElement( const char *_next ) {
+    return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement( _next ) );
+  }
+
+#ifdef TIXML_USE_STL
+  const TiXmlElement* NextSiblingElement( const std::string& _value) const        {       return NextSiblingElement (_value.c_str ());    }       ///< STL std::string form.
+  TiXmlElement* NextSiblingElement( const std::string& _value)                            {       return NextSiblingElement (_value.c_str ());    }       ///< STL std::string form.
+#endif
+
+  /// Convenience function to get through elements.
+  const TiXmlElement* FirstChildElement() const;
+  TiXmlElement* FirstChildElement() {
+    return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement() );
+  }
+
+  /// Convenience function to get through elements.
+  const TiXmlElement* FirstChildElement( const char * _value ) const;
+  TiXmlElement* FirstChildElement( const char * _value ) {
+    return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement( _value ) );
+  }
+
+#ifdef TIXML_USE_STL
+  const TiXmlElement* FirstChildElement( const std::string& _value ) const        {       return FirstChildElement (_value.c_str ());     }       ///< STL std::string form.
+  TiXmlElement* FirstChildElement( const std::string& _value )                            {       return FirstChildElement (_value.c_str ());     }       ///< STL std::string form.
+#endif
+
+  /** Query the type (as an enumerated value, above) of this node.
+      The possible types are: DOCUMENT, ELEMENT, COMMENT,
+      UNKNOWN, TEXT, and DECLARATION.
+  */
+  int Type() const        { return type; }
+
+  /** Return a pointer to the Document this node lives in.
+      Returns null if not in a document.
+  */
+  const TiXmlDocument* GetDocument() const;
+  TiXmlDocument* GetDocument() {
+    return const_cast< TiXmlDocument* >( (const_cast< const TiXmlNode* >(this))->GetDocument() );
+  }
+
+  /// Returns true if this node has no children.
+  bool NoChildren() const                                         { return !firstChild; }
+
+  virtual const TiXmlDocument*    ToDocument()    const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+  virtual const TiXmlElement*     ToElement()     const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+  virtual const TiXmlComment*     ToComment()     const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+  virtual const TiXmlUnknown*     ToUnknown()     const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+  virtual const TiXmlText*        ToText()        const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+  virtual const TiXmlDeclaration* ToDeclaration() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+
+  virtual TiXmlDocument*          ToDocument()    { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+  virtual TiXmlElement*           ToElement()         { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+  virtual TiXmlComment*           ToComment()     { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+  virtual TiXmlUnknown*           ToUnknown()         { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+  virtual TiXmlText*                  ToText()        { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+  virtual TiXmlDeclaration*       ToDeclaration() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+
+  /** Create an exact duplicate of this node and return it. The memory must be deleted
+      by the caller.
+  */
+  virtual TiXmlNode* Clone() const = 0;
+
+  /** Accept a hierchical visit 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( TiXmlVisitor* visitor ) const = 0;
+
+protected:
+  TiXmlNode( NodeType _type );
+
+  // Copy to the allocated object. Shared functionality between Clone, Copy constructor,
+  // and the assignment operator.
+  void CopyTo( TiXmlNode* target ) const;
+
+#ifdef TIXML_USE_STL
+  // The real work of the input operator.
+  virtual void StreamIn( std::istream* in, TIXML_STRING* tag ) = 0;
+#endif
+
+  // Figure out what is at *p, and parse it. Returns null if it is not an xml node.
+  TiXmlNode* Identify( const char* start, TiXmlEncoding encoding );
+
+  TiXmlNode*              parent;
+  NodeType                type;
+
+  TiXmlNode*              firstChild;
+  TiXmlNode*              lastChild;
+
+  TIXML_STRING    value;
+
+  TiXmlNode*              prev;
+  TiXmlNode*              next;
+
+private:
+  TiXmlNode( const TiXmlNode& );                          // not implemented.
+  void operator=( const TiXmlNode& base );        // not allowed.
+};
+
+
+/** An attribute is a name-value pair. Elements have an arbitrary
+    number of attributes, each with a unique name.
+
+    @note The attributes are not TiXmlNodes, since they are not
+    part of the tinyXML document object model. There are other
+    suggested ways to look at this problem.
+*/
+class cpPlugins_tinyxml_EXPORT TiXmlAttribute : public TiXmlBase
+{
+  friend class TiXmlAttributeSet;
+
+public:
+  /// Construct an empty attribute.
+  TiXmlAttribute() : TiXmlBase()
+    {
+      document = 0;
+      prev = next = 0;
+    }
+
+#ifdef TIXML_USE_STL
+  /// std::string constructor.
+  TiXmlAttribute( const std::string& _name, const std::string& _value )
+    {
+      name = _name;
+      value = _value;
+      document = 0;
+      prev = next = 0;
+    }
+#endif
+
+  /// Construct an attribute with a name and value.
+  TiXmlAttribute( const char * _name, const char * _value )
+    {
+      name = _name;
+      value = _value;
+      document = 0;
+      prev = next = 0;
+    }
+
+  const char*             Name()  const           { return name.c_str(); }                ///< Return the name of this attribute.
+  const char*             Value() const           { return value.c_str(); }               ///< Return the value of this attribute.
+#ifdef TIXML_USE_STL
+  const std::string& ValueStr() const     { return value; }                               ///< Return the value of this attribute.
+#endif
+  int                             IntValue() const;                                                                       ///< Return the value of this attribute, converted to an integer.
+  double                  DoubleValue() const;                                                            ///< Return the value of this attribute, converted to a double.
+
+  // Get the tinyxml string representation
+  const TIXML_STRING& NameTStr() const { return name; }
+
+  /** QueryIntValue examines the value string. It is an alternative to the
+      IntValue() method with richer error checking.
+      If the value is an integer, it is stored in 'value' and
+      the call returns TIXML_SUCCESS. If it is not
+      an integer, it returns TIXML_WRONG_TYPE.
+
+      A specialized but useful call. Note that for success it returns 0,
+      which is the opposite of almost all other TinyXml calls.
+  */
+  int QueryIntValue( int* _value ) const;
+  /// QueryDoubleValue examines the value string. See QueryIntValue().
+  int QueryDoubleValue( double* _value ) const;
+
+  void SetName( const char* _name )       { name = _name; }                               ///< Set the name of this attribute.
+  void SetValue( const char* _value )     { value = _value; }                             ///< Set the value.
+
+  void SetIntValue( int _value );                                                                         ///< Set the value from an integer.
+  void SetDoubleValue( double _value );                                                           ///< Set the value from a double.
+
+#ifdef TIXML_USE_STL
+  /// STL std::string form.
+  void SetName( const std::string& _name )        { name = _name; }
+  /// STL std::string form.
+  void SetValue( const std::string& _value )      { value = _value; }
+#endif
+
+  /// Get the next sibling attribute in the DOM. Returns null at end.
+  const TiXmlAttribute* Next() const;
+  TiXmlAttribute* Next() {
+    return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Next() );
+  }
+
+  /// Get the previous sibling attribute in the DOM. Returns null at beginning.
+  const TiXmlAttribute* Previous() const;
+  TiXmlAttribute* Previous() {
+    return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Previous() );
+  }
+
+  bool operator==( const TiXmlAttribute& rhs ) const { return rhs.name == name; }
+  bool operator<( const TiXmlAttribute& rhs )      const { return name < rhs.name; }
+  bool operator>( const TiXmlAttribute& rhs )  const { return name > rhs.name; }
+
+  /*      Attribute parsing starts: first letter of the name
+          returns: the next char after the value end quote
+  */
+  virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
+
+  // Prints this Attribute to a FILE stream.
+  virtual void Print( FILE* cfile, int depth ) const {
+    Print( cfile, depth, 0 );
+  }
+  void Print( FILE* cfile, int depth, TIXML_STRING* str ) const;
+
+  // [internal use]
+  // Set the document pointer so the attribute can report errors.
+  void SetDocument( TiXmlDocument* doc )  { document = doc; }
+
+private:
+  TiXmlAttribute( const TiXmlAttribute& );                                // not implemented.
+  void operator=( const TiXmlAttribute& base );   // not allowed.
+
+  TiXmlDocument*  document;       // A pointer back to a document, for error reporting.
+  TIXML_STRING name;
+  TIXML_STRING value;
+  TiXmlAttribute* prev;
+  TiXmlAttribute* next;
+};
+
+
+/*      A class used to manage a group of attributes.
+        It is only used internally, both by the ELEMENT and the DECLARATION.
+
+        The set can be changed transparent to the Element and Declaration
+        classes that use it, but NOT transparent to the Attribute
+        which has to implement a next() and previous() method. Which makes
+        it a bit problematic and prevents the use of STL.
+
+        This version is implemented with circular lists because:
+        - I like circular lists
+        - it demonstrates some independence from the (typical) doubly linked list.
+*/
+class cpPlugins_tinyxml_EXPORT TiXmlAttributeSet
+{
+public:
+  TiXmlAttributeSet();
+  ~TiXmlAttributeSet();
+
+  void Add( TiXmlAttribute* attribute );
+  void Remove( TiXmlAttribute* attribute );
+
+  const TiXmlAttribute* First()   const   { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; }
+  TiXmlAttribute* First()                                 { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; }
+  const TiXmlAttribute* Last() const              { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; }
+  TiXmlAttribute* Last()                                  { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; }
+
+  TiXmlAttribute* Find( const char* _name ) const;
+  TiXmlAttribute* FindOrCreate( const char* _name );
+
+#       ifdef TIXML_USE_STL
+  TiXmlAttribute* Find( const std::string& _name ) const;
+  TiXmlAttribute* FindOrCreate( const std::string& _name );
+#       endif
+
+
+private:
+  //*ME:  Because of hidden/disabled copy-construktor in TiXmlAttribute (sentinel-element),
+          //*ME:  this class must be also use a hidden/disabled copy-constructor !!!
+    TiXmlAttributeSet( const TiXmlAttributeSet& );  // not allowed
+  void operator=( const TiXmlAttributeSet& );     // not allowed (as TiXmlAttribute)
+
+  TiXmlAttribute sentinel;
+};
+
+
+/** 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 cpPlugins_tinyxml_EXPORT TiXmlElement : public TiXmlNode
+{
+public:
+  /// Construct an element.
+  TiXmlElement (const char * in_value);
+
+#ifdef TIXML_USE_STL
+  /// std::string constructor.
+  TiXmlElement( const std::string& _value );
+#endif
+
+  TiXmlElement( const TiXmlElement& );
+
+  void operator=( const TiXmlElement& base );
+
+  virtual ~TiXmlElement();
+
+  /** Given an attribute name, Attribute() returns the value
+      for the attribute of that name, or null if none exists.
+  */
+  const char* Attribute( const char* name ) const;
+
+  /** Given an attribute name, Attribute() returns the value
+      for the attribute of that name, or null if none exists.
+      If the attribute exists and can be converted to an integer,
+      the integer value will be put in the return 'i', if 'i'
+      is non-null.
+  */
+  const char* Attribute( const char* name, int* i ) const;
+
+  /** Given an attribute name, Attribute() returns the value
+      for the attribute of that name, or null if none exists.
+      If the attribute exists and can be converted to an double,
+      the double value will be put in the return 'd', if 'd'
+      is non-null.
+  */
+  const char* Attribute( const char* name, double* d ) const;
+
+  /** QueryIntAttribute examines the attribute - it is an alternative to the
+      Attribute() method with richer error checking.
+      If the attribute is an integer, it is stored in 'value' and
+      the call returns TIXML_SUCCESS. If it is not
+      an integer, it returns TIXML_WRONG_TYPE. If the attribute
+      does not exist, then TIXML_NO_ATTRIBUTE is returned.
+  */
+  int QueryIntAttribute( const char* name, int* _value ) const;
+  /// QueryDoubleAttribute examines the attribute - see QueryIntAttribute().
+  int QueryDoubleAttribute( const char* name, double* _value ) const;
+  /// QueryFloatAttribute examines the attribute - see QueryIntAttribute().
+  int QueryFloatAttribute( const char* name, float* _value ) const {
+    double d;
+    int result = QueryDoubleAttribute( name, &d );
+    if ( result == TIXML_SUCCESS ) {
+      *_value = (float)d;
+    }
+    return result;
+  }
+
+#ifdef TIXML_USE_STL
+  /// QueryStringAttribute examines the attribute - see QueryIntAttribute().
+  int QueryStringAttribute( const char* name, std::string* _value ) const {
+    const char* cstr = Attribute( name );
+    if ( cstr ) {
+      *_value = std::string( cstr );
+      return TIXML_SUCCESS;
+    }
+    return TIXML_NO_ATTRIBUTE;
+  }
+
+  /** Template form of the attribute query which will try to read the
+      attribute into the specified type. Very easy, very powerful, but
+      be careful to make sure to call this with the correct type.
+
+      NOTE: This method doesn't work correctly for 'string' types that contain spaces.
+
+      @return TIXML_SUCCESS, TIXML_WRONG_TYPE, or TIXML_NO_ATTRIBUTE
+  */
+  template< typename T > int QueryValueAttribute( const std::string& name, T* outValue ) const
+    {
+      const TiXmlAttribute* node = attributeSet.Find( name );
+      if ( !node )
+        return TIXML_NO_ATTRIBUTE;
+
+      std::stringstream sstream( node->ValueStr() );
+      sstream >> *outValue;
+      if ( !sstream.fail() )
+        return TIXML_SUCCESS;
+      return TIXML_WRONG_TYPE;
+    }
+
+  int QueryValueAttribute( const std::string& name, std::string* outValue ) const
+    {
+      const TiXmlAttribute* node = attributeSet.Find( name );
+      if ( !node )
+        return TIXML_NO_ATTRIBUTE;
+      *outValue = node->ValueStr();
+      return TIXML_SUCCESS;
+    }
+#endif
+
+  /** Sets an attribute of name to a given value. The attribute
+      will be created if it does not exist, or changed if it does.
+  */
+  void SetAttribute( const char* name, const char * _value );
+
+#ifdef TIXML_USE_STL
+  const std::string* Attribute( const std::string& name ) const;
+  const std::string* Attribute( const std::string& name, int* i ) const;
+  const std::string* Attribute( const std::string& name, double* d ) const;
+  int QueryIntAttribute( const std::string& name, int* _value ) const;
+  int QueryDoubleAttribute( const std::string& name, double* _value ) const;
+
+  /// STL std::string form.
+  void SetAttribute( const std::string& name, const std::string& _value );
+  ///< STL std::string form.
+  void SetAttribute( const std::string& name, int _value );
+  ///< STL std::string form.
+  void SetDoubleAttribute( const std::string& name, double value );
+#endif
+
+  /** Sets an attribute of name to a given value. The attribute
+      will be created if it does not exist, or changed if it does.
+  */
+  void SetAttribute( const char * name, int value );
+
+  /** Sets an attribute of name to a given value. The attribute
+      will be created if it does not exist, or changed if it does.
+  */
+  void SetDoubleAttribute( const char * name, double value );
+
+  /** Deletes an attribute with the given name.
+   */
+  void RemoveAttribute( const char * name );
+#ifdef TIXML_USE_STL
+  void RemoveAttribute( const std::string& name ) {       RemoveAttribute (name.c_str ());        }       ///< STL std::string form.
+#endif
+
+  const TiXmlAttribute* FirstAttribute() const    { return attributeSet.First(); }                ///< Access the first attribute in this element.
+  TiXmlAttribute* FirstAttribute()                                { return attributeSet.First(); }
+  const TiXmlAttribute* LastAttribute()   const   { return attributeSet.Last(); }         ///< Access the last attribute in this element.
+  TiXmlAttribute* LastAttribute()                                 { return attributeSet.Last(); }
+
+  /** 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 ".
+
+      WARNING: GetText() accesses a child node - don't become confused with the
+      similarly named TiXmlHandle::Text() and TiXmlNode::ToText() which are
+      safe type casts on the referenced node.
+  */
+  const char* GetText() const;
+
+  /// Creates a new Element and returns it - the returned element is a copy.
+  virtual TiXmlNode* Clone() const;
+  // Print the Element to a FILE stream.
+  virtual void Print( FILE* cfile, int depth ) const;
+
+  /*      Attribtue parsing starts: next char past '<'
+          returns: next char past '>'
+  */
+  virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
+
+  virtual const TiXmlElement*     ToElement()     const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+  virtual TiXmlElement*           ToElement()               { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+
+  /** Walk the XML tree visiting this node and all of its children.
+   */
+  virtual bool Accept( TiXmlVisitor* visitor ) const;
+
+protected:
+
+  void CopyTo( TiXmlElement* target ) const;
+  void ClearThis();       // like clear, but initializes 'this' object as well
+
+  // Used to be public [internal use]
+#ifdef TIXML_USE_STL
+  virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
+#endif
+  /*      [internal use]
+          Reads the "value" of the element -- another element, or text.
+          This should terminate with the current end tag.
+  */
+  const char* ReadValue( const char* in, TiXmlParsingData* prevData, TiXmlEncoding encoding );
+
+private:
+  TiXmlAttributeSet attributeSet;
+};
+
+
+/**     An XML comment.
+ */
+class TiXmlComment : public TiXmlNode
+{
+public:
+  /// Constructs an empty comment.
+  TiXmlComment() : TiXmlNode( TiXmlNode::TINYXML_COMMENT ) {}
+  /// Construct a comment from text.
+  TiXmlComment( const char* _value ) : TiXmlNode( TiXmlNode::TINYXML_COMMENT ) {
+    SetValue( _value );
+  }
+  TiXmlComment( const TiXmlComment& );
+  void operator=( const TiXmlComment& base );
+
+  virtual ~TiXmlComment() {}
+
+  /// Returns a copy of this Comment.
+  virtual TiXmlNode* Clone() const;
+  // Write this Comment to a FILE stream.
+  virtual void Print( FILE* cfile, int depth ) const;
+
+  /*      Attribtue parsing starts: at the ! of the !--
+          returns: next char past '>'
+  */
+  virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
+
+  virtual const TiXmlComment*  ToComment() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+  virtual TiXmlComment*  ToComment() { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+
+  /** Walk the XML tree visiting this node and all of its children.
+   */
+  virtual bool Accept( TiXmlVisitor* visitor ) const;
+
+protected:
+  void CopyTo( TiXmlComment* target ) const;
+
+  // used to be public
+#ifdef TIXML_USE_STL
+  virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
+#endif
+  //      virtual void StreamOut( TIXML_OSTREAM * out ) const;
+
+private:
+
+};
+
+
+/** XML text. 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 TiXmlText : public TiXmlNode
+{
+  friend class TiXmlElement;
+public:
+  /** Constructor for text element. By default, it is treated as
+      normal, encoded text. If you want it be output as a CDATA text
+      element, set the parameter _cdata to 'true'
+  */
+  TiXmlText (const char * initValue ) : TiXmlNode (TiXmlNode::TINYXML_TEXT)
+    {
+      SetValue( initValue );
+      cdata = false;
+    }
+  virtual ~TiXmlText() {}
+
+#ifdef TIXML_USE_STL
+  /// Constructor.
+  TiXmlText( const std::string& initValue ) : TiXmlNode (TiXmlNode::TINYXML_TEXT)
+    {
+      SetValue( initValue );
+      cdata = false;
+    }
+#endif
+
+  TiXmlText( const TiXmlText& copy ) : TiXmlNode( TiXmlNode::TINYXML_TEXT )       { copy.CopyTo( this ); }
+  void operator=( const TiXmlText& base )                                                         { base.CopyTo( this ); }
+
+  // Write this text object to a FILE stream.
+  virtual void Print( FILE* cfile, int depth ) const;
+
+  /// Queries whether this represents text using a CDATA section.
+  bool CDATA() const                              { return cdata; }
+  /// Turns on or off a CDATA representation of text.
+  void SetCDATA( bool _cdata )    { cdata = _cdata; }
+
+  virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
+
+  virtual const TiXmlText* ToText() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+  virtual TiXmlText*       ToText()       { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+
+  /** Walk the XML tree visiting this node and all of its children.
+   */
+  virtual bool Accept( TiXmlVisitor* content ) const;
+
+protected :
+  ///  [internal use] Creates a new Element and returns it.
+  virtual TiXmlNode* Clone() const;
+  void CopyTo( TiXmlText* target ) const;
+
+  bool Blank() const;     // returns true if all white space and new lines
+  // [internal use]
+#ifdef TIXML_USE_STL
+  virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
+#endif
+
+private:
+  bool cdata;                     // true if this should be input and output as a CDATA style text element
+};
+
+
+/** In correct XML the declaration is the first entry in the file.
+    @verbatim
+    <?xml version="1.0" standalone="yes"?>
+    @endverbatim
+
+    TinyXml will happily read or write files without a declaration,
+    however. There are 3 possible attributes to the declaration:
+    version, encoding, and standalone.
+
+    Note: In this version of the code, the attributes are
+    handled as special cases, not generic attributes, simply
+    because there can only be at most 3 and they are always the same.
+*/
+class cpPlugins_tinyxml_EXPORT TiXmlDeclaration : public TiXmlNode
+{
+public:
+  /// Construct an empty declaration.
+  TiXmlDeclaration()   : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) {}
+
+#ifdef TIXML_USE_STL
+  /// Constructor.
+  TiXmlDeclaration(       const std::string& _version,
+                          const std::string& _encoding,
+                          const std::string& _standalone );
+#endif
+
+  /// Construct.
+  TiXmlDeclaration(       const char* _version,
+                          const char* _encoding,
+                          const char* _standalone );
+
+  TiXmlDeclaration( const TiXmlDeclaration& copy );
+  void operator=( const TiXmlDeclaration& copy );
+
+  virtual ~TiXmlDeclaration()     {}
+
+  /// Version. Will return an empty string if none was found.
+  const char *Version() const                     { return version.c_str (); }
+  /// Encoding. Will return an empty string if none was found.
+  const char *Encoding() const            { return encoding.c_str (); }
+  /// Is this a standalone document?
+  const char *Standalone() const          { return standalone.c_str (); }
+
+  /// Creates a copy of this Declaration and returns it.
+  virtual TiXmlNode* Clone() const;
+  // Print this declaration to a FILE stream.
+  virtual void Print( FILE* cfile, int depth, TIXML_STRING* str ) const;
+  virtual void Print( FILE* cfile, int depth ) const {
+    Print( cfile, depth, 0 );
+  }
+
+  virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
+
+  virtual const TiXmlDeclaration* ToDeclaration() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+  virtual TiXmlDeclaration*       ToDeclaration()       { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+
+  /** Walk the XML tree visiting this node and all of its children.
+   */
+  virtual bool Accept( TiXmlVisitor* visitor ) const;
+
+protected:
+  void CopyTo( TiXmlDeclaration* target ) const;
+  // used to be public
+#ifdef TIXML_USE_STL
+  virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
+#endif
+
+private:
+
+  TIXML_STRING version;
+  TIXML_STRING encoding;
+  TIXML_STRING standalone;
+};
+
+
+/** 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 TiXmlUnknown : public TiXmlNode
+{
+public:
+  TiXmlUnknown() : TiXmlNode( TiXmlNode::TINYXML_UNKNOWN )        {}
+  virtual ~TiXmlUnknown() {}
+
+  TiXmlUnknown( const TiXmlUnknown& copy ) : TiXmlNode( TiXmlNode::TINYXML_UNKNOWN )              { copy.CopyTo( this ); }
+  void operator=( const TiXmlUnknown& copy )                                                                              { copy.CopyTo( this ); }
+
+  /// Creates a copy of this Unknown and returns it.
+  virtual TiXmlNode* Clone() const;
+  // Print this Unknown to a FILE stream.
+  virtual void Print( FILE* cfile, int depth ) const;
+
+  virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
+
+  virtual const TiXmlUnknown*     ToUnknown()     const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+  virtual TiXmlUnknown*           ToUnknown()         { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+
+  /** Walk the XML tree visiting this node and all of its children.
+   */
+  virtual bool Accept( TiXmlVisitor* content ) const;
+
+protected:
+  void CopyTo( TiXmlUnknown* target ) const;
+
+#ifdef TIXML_USE_STL
+  virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
+#endif
+
+private:
+
+};
+
+
+/** Always the top level node. A document binds together all the
+    XML pieces. It can be saved, loaded, and printed to the screen.
+    The 'value' of a document node is the xml file name.
+*/
+class cpPlugins_tinyxml_EXPORT TiXmlDocument : public TiXmlNode
+{
+public:
+  /// Create an empty document, that has no name.
+  TiXmlDocument();
+  /// Create a document with a name. The name of the document is also the filename of the xml.
+  TiXmlDocument( const char * documentName );
+
+#ifdef TIXML_USE_STL
+  /// Constructor.
+  TiXmlDocument( const std::string& documentName );
+#endif
+
+  TiXmlDocument( const TiXmlDocument& copy );
+  void operator=( const TiXmlDocument& copy );
+
+  virtual ~TiXmlDocument() {}
+
+  /** Load a file using the current document value.
+      Returns true if successful. Will delete any existing
+      document data before loading.
+  */
+  bool LoadFile( TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
+  /// Save a file using the current document value. Returns true if successful.
+  bool SaveFile() const;
+  /// Load a file using the given filename. Returns true if successful.
+  bool LoadFile( const char * filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
+  /// Save a file using the given filename. Returns true if successful.
+  bool SaveFile( const char * filename ) const;
+  /** Load a file using the given FILE*. Returns true if successful. Note that this method
+      doesn't stream - the entire object pointed at by the FILE*
+      will be interpreted as an XML file. TinyXML doesn't stream in XML from the current
+      file location. Streaming may be added in the future.
+  */
+  bool LoadFile( FILE*, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
+  /// Save a file using the given FILE*. Returns true if successful.
+  bool SaveFile( FILE* ) const;
+
+#ifdef TIXML_USE_STL
+  bool LoadFile( const std::string& filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING )                   ///< STL std::string version.
+    {
+      return LoadFile( filename.c_str(), encoding );
+    }
+  bool SaveFile( const std::string& filename ) const              ///< STL std::string version.
+    {
+      return SaveFile( filename.c_str() );
+    }
+#endif
+
+  /** Parse the given null terminated block of xml data. Passing in an encoding to this
+      method (either TIXML_ENCODING_LEGACY or TIXML_ENCODING_UTF8 will force TinyXml
+      to use that encoding, regardless of what TinyXml might otherwise try to detect.
+  */
+  virtual const char* Parse( const char* p, TiXmlParsingData* data = 0, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
+
+  /** Get the root element -- the only top level element -- of the document.
+      In well formed XML, there should only be one. TinyXml is tolerant of
+      multiple elements at the document level.
+  */
+  const TiXmlElement* RootElement() const         { return FirstChildElement(); }
+  TiXmlElement* RootElement()                                     { return FirstChildElement(); }
+
+  /** If an error occurs, Error will be set to true. Also,
+      - The ErrorId() will contain the integer identifier of the error (not generally useful)
+      - The ErrorDesc() method will return the name of the error. (very useful)
+      - The ErrorRow() and ErrorCol() will return the location of the error (if known)
+  */
+  bool Error() const                                              { return error; }
+
+  /// Contains a textual (english) description of the error if one occurs.
+  const char * ErrorDesc() const  { return errorDesc.c_str (); }
+
+  /** Generally, you probably want the error string ( ErrorDesc() ). But if you
+      prefer the ErrorId, this function will fetch it.
+  */
+  int ErrorId()   const                           { return errorId; }
+
+  /** Returns the location (if known) of the error. The first column is column 1,
+      and the first row is row 1. A value of 0 means the row and column wasn't applicable
+      (memory errors, for example, have no row/column) or the parser lost the error. (An
+      error in the error reporting, in that case.)
+
+      @sa SetTabSize, Row, Column
+  */
+  int ErrorRow() const    { return errorLocation.row+1; }
+  int ErrorCol() const    { return errorLocation.col+1; } ///< The column where the error occured. See ErrorRow()
+
+  /** SetTabSize() allows the error reporting functions (ErrorRow() and ErrorCol())
+      to report the correct values for row and column. It does not change the output
+      or input in any way.
+
+      By calling this method, with a tab size
+      greater than 0, the row and column of each node and attribute is stored
+      when the file is loaded. Very useful for tracking the DOM back in to
+      the source file.
+
+      The tab size is required for calculating the location of nodes. If not
+      set, the default of 4 is used. The tabsize is set per document. Setting
+      the tabsize to 0 disables row/column tracking.
+
+      Note that row and column tracking is not supported when using operator>>.
+
+      The tab size needs to be enabled before the parse or load. Correct usage:
+      @verbatim
+      TiXmlDocument doc;
+      doc.SetTabSize( 8 );
+      doc.Load( "myfile.xml" );
+      @endverbatim
+
+      @sa Row, Column
+  */
+  void SetTabSize( int _tabsize )         { tabsize = _tabsize; }
+
+  int TabSize() const     { return tabsize; }
+
+  /** If you have handled the error, it can be reset with this call. The error
+      state is automatically cleared if you Parse a new XML block.
+  */
+  void ClearError()                                               {       error = false;
+    errorId = 0;
+    errorDesc = "";
+    errorLocation.row = errorLocation.col = 0;
+    //errorLocation.last = 0;
+  }
+
+  /** Write the document to standard out using formatted printing ("pretty print"). */
+  void Print() const                                              { Print( stdout, 0 ); }
+
+  /* Write the document to a string using formatted printing ("pretty print"). This
+     will allocate a character array (new char[]) and return it as a pointer. The
+     calling code pust call delete[] on the return char* to avoid a memory leak.
+  */
+  //char* PrintToMemory() const;
+
+  /// Print this Document to a FILE stream.
+  virtual void Print( FILE* cfile, int depth = 0 ) const;
+  // [internal use]
+  void SetError( int err, const char* errorLocation, TiXmlParsingData* prevData, TiXmlEncoding encoding );
+
+  virtual const TiXmlDocument*    ToDocument()    const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+  virtual TiXmlDocument*          ToDocument()          { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+
+  /** Walk the XML tree visiting this node and all of its children.
+   */
+  virtual bool Accept( TiXmlVisitor* content ) const;
+
+protected :
+  // [internal use]
+  virtual TiXmlNode* Clone() const;
+#ifdef TIXML_USE_STL
+  virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
+#endif
+
+private:
+  void CopyTo( TiXmlDocument* target ) const;
+
+  bool error;
+  int  errorId;
+  TIXML_STRING errorDesc;
+  int tabsize;
+  TiXmlCursor errorLocation;
+  bool useMicrosoftBOM;           // the UTF-8 BOM were found when read. Note this, and try to write.
+};
+
+
+/**
+   A TiXmlHandle is a class that wraps a node pointer with null checks; this is
+   an incredibly useful thing. Note that TiXmlHandle 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
+   TiXmlElement* root = document.FirstChildElement( "Document" );
+   if ( root )
+   {
+   TiXmlElement* element = root->FirstChildElement( "Element" );
+   if ( element )
+   {
+   TiXmlElement* child = element->FirstChildElement( "Child" );
+   if ( child )
+   {
+   TiXmlElement* child2 = child->NextSiblingElement( "Child" );
+   if ( child2 )
+   {
+   // Finally do something useful.
+   @endverbatim
+
+   And that doesn't even cover "else" cases. TiXmlHandle addresses the verbosity
+   of such code. A TiXmlHandle checks for null     pointers so it is perfectly safe
+   and correct to use:
+
+   @verbatim
+   TiXmlHandle docHandle( &document );
+   TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).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
+   TiXmlHandle handleCopy = handle;
+   @endverbatim
+
+   What they should not be used for is iteration:
+
+   @verbatim
+   int i=0;
+   while ( true )
+   {
+   TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", i ).ToElement();
+   if ( !child )
+   break;
+   // do something
+   ++i;
+   }
+   @endverbatim
+
+   It seems reasonable, but it is in fact two embedded while loops. The Child method is
+   a linear walk to find the element, so this code would iterate much more than it needs
+   to. Instead, prefer:
+
+   @verbatim
+   TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild( "Child" ).ToElement();
+
+   for( child; child; child=child->NextSiblingElement() )
+   {
+   // do something
+   }
+   @endverbatim
+*/
+class TiXmlHandle
+{
+public:
+  /// Create a handle from any node (at any depth of the tree.) This can be a null pointer.
+  TiXmlHandle( TiXmlNode* _node )                                 { this->node = _node; }
+  /// Copy constructor
+  TiXmlHandle( const TiXmlHandle& ref )                   { this->node = ref.node; }
+  TiXmlHandle operator=( const TiXmlHandle& ref ) { this->node = ref.node; return *this; }
+
+  /// Return a handle to the first child node.
+  TiXmlHandle FirstChild() const;
+  /// Return a handle to the first child node with the given name.
+  TiXmlHandle FirstChild( const char * value ) const;
+  /// Return a handle to the first child element.
+  TiXmlHandle FirstChildElement() const;
+  /// Return a handle to the first child element with the given name.
+  TiXmlHandle FirstChildElement( const char * value ) const;
+
+  /** Return a handle to the "index" child with the given name.
+      The first child is 0, the second 1, etc.
+  */
+  TiXmlHandle Child( const char* value, int index ) const;
+  /** Return a handle to the "index" child.
+      The first child is 0, the second 1, etc.
+  */
+  TiXmlHandle Child( int index ) const;
+  /** Return a handle to the "index" child element with the given name.
+      The first child element is 0, the second 1, etc. Note that only TiXmlElements
+      are indexed: other types are not counted.
+  */
+  TiXmlHandle ChildElement( const char* value, int index ) const;
+  /** Return a handle to the "index" child element.
+      The first child element is 0, the second 1, etc. Note that only TiXmlElements
+      are indexed: other types are not counted.
+  */
+  TiXmlHandle ChildElement( int index ) const;
+
+#ifdef TIXML_USE_STL
+  TiXmlHandle FirstChild( const std::string& _value ) const                               { return FirstChild( _value.c_str() ); }
+  TiXmlHandle FirstChildElement( const std::string& _value ) const                { return FirstChildElement( _value.c_str() ); }
+
+  TiXmlHandle Child( const std::string& _value, int index ) const                 { return Child( _value.c_str(), index ); }
+  TiXmlHandle ChildElement( const std::string& _value, int index ) const  { return ChildElement( _value.c_str(), index ); }
+#endif
+
+  /** Return the handle as a TiXmlNode. This may return null.
+   */
+  TiXmlNode* ToNode() const                       { return node; }
+  /** Return the handle as a TiXmlElement. This may return null.
+   */
+  TiXmlElement* ToElement() const         { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); }
+  /**     Return the handle as a TiXmlText. This may return null.
+   */
+  TiXmlText* ToText() const                       { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); }
+  /** Return the handle as a TiXmlUnknown. This may return null.
+   */
+  TiXmlUnknown* ToUnknown() const         { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); }
+
+  /** @deprecated use ToNode.
+      Return the handle as a TiXmlNode. This may return null.
+  */
+  TiXmlNode* Node() const                 { return ToNode(); }
+  /** @deprecated use ToElement.
+      Return the handle as a TiXmlElement. This may return null.
+  */
+  TiXmlElement* Element() const   { return ToElement(); }
+  /**     @deprecated use ToText()
+          Return the handle as a TiXmlText. This may return null.
+  */
+  TiXmlText* Text() const                 { return ToText(); }
+  /** @deprecated use ToUnknown()
+      Return the handle as a TiXmlUnknown. This may return null.
+  */
+  TiXmlUnknown* Unknown() const   { return ToUnknown(); }
+
+private:
+  TiXmlNode* node;
+};
+
+
+/** Print to memory functionality. The TiXmlPrinter is useful when you need to:
+
+-# Print to memory (especially in non-STL mode)
+-# Control formatting (line endings, etc.)
+
+When constructed, the TiXmlPrinter is in its default "pretty printing" mode.
+Before calling Accept() you can call methods to control the printing
+of the XML document. After TiXmlNode::Accept() is called, the printed document can
+be accessed via the CStr(), Str(), and Size() methods.
+
+TiXmlPrinter uses the Visitor API.
+@verbatim
+TiXmlPrinter printer;
+printer.SetIndent( "\t" );
+
+doc.Accept( &printer );
+fprintf( stdout, "%s", printer.CStr() );
+@endverbatim
+*/
+class TiXmlPrinter : public TiXmlVisitor
+{
+public:
+  TiXmlPrinter() : depth( 0 ), simpleTextPrint( false ),
+                   buffer(), indent( "    " ), lineBreak( "\n" ) {}
+
+  virtual bool VisitEnter( const TiXmlDocument& doc );
+  virtual bool VisitExit( const TiXmlDocument& doc );
+
+  virtual bool VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute );
+  virtual bool VisitExit( const TiXmlElement& element );
+
+  virtual bool Visit( const TiXmlDeclaration& declaration );
+  virtual bool Visit( const TiXmlText& text );
+  virtual bool Visit( const TiXmlComment& comment );
+  virtual bool Visit( const TiXmlUnknown& unknown );
+
+  /** Set the indent characters for printing. By default 4 spaces
+      but tab (\t) is also useful, or null/empty string for no indentation.
+  */
+  void SetIndent( const char* _indent )                   { indent = _indent ? _indent : "" ; }
+  /// Query the indention string.
+  const char* Indent()                                                    { return indent.c_str(); }
+  /** Set the line breaking string. By default set to newline (\n).
+      Some operating systems prefer other characters, or can be
+      set to the null/empty string for no indenation.
+  */
+  void SetLineBreak( const char* _lineBreak )             { lineBreak = _lineBreak ? _lineBreak : ""; }
+  /// Query the current line breaking string.
+  const char* LineBreak()                                                 { return lineBreak.c_str(); }
+
+  /** Switch over to "stream printing" which is the most dense formatting without
+      linebreaks. Common when the XML is needed for network transmission.
+  */
+  void SetStreamPrinting()                                                { indent = "";
+    lineBreak = "";
+  }
+  /// Return the result.
+  const char* CStr()                                                              { return buffer.c_str(); }
+  /// Return the length of the result string.
+  size_t Size()                                                                   { return buffer.size(); }
+
+#ifdef TIXML_USE_STL
+  /// Return the result.
+  const std::string& Str()                                                { return buffer; }
+#endif
+
+private:
+  void DoIndent() {
+    for( int i=0; i<depth; ++i )
+      buffer += indent;
+  }
+  void DoLineBreak() {
+    buffer += lineBreak;
+  }
+
+  int depth;
+  bool simpleTextPrint;
+  TIXML_STRING buffer;
+  TIXML_STRING indent;
+  TIXML_STRING lineBreak;
+};
+
+
+#ifdef _MSC_VER
+#pragma warning( pop )
+#endif
+
+#endif
diff --git a/lib/third_party/tinyxml/tinyxmlerror.cpp b/lib/third_party/tinyxml/tinyxmlerror.cpp
new file mode 100644 (file)
index 0000000..e1d9f3e
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+  www.sourceforge.net/projects/tinyxml
+  Original code (2.0 and earlier )copyright (c) 2000-2006 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 "tinyxml.h"
+
+// The goal of the seperate error file is to make the first
+// step towards localization. tinyxml (currently) only supports
+// english error messages, but the could now be translated.
+//
+// It also cleans up the code a bit.
+//
+
+const char* TiXmlBase::errorString[ TIXML_ERROR_STRING_COUNT ] =
+{
+  "No error",
+  "Error",
+  "Failed to open file",
+  "Error parsing Element.",
+  "Failed to read Element name",
+  "Error reading Element value.",
+  "Error reading Attributes.",
+  "Error: empty tag.",
+  "Error reading end tag.",
+  "Error parsing Unknown.",
+  "Error parsing Comment.",
+  "Error parsing Declaration.",
+  "Error document empty.",
+  "Error null (0) or unexpected EOF found in input stream.",
+  "Error parsing CDATA.",
+  "Error when TiXmlDocument added to document, because TiXmlDocument can only be at the root.",
+};
diff --git a/lib/third_party/tinyxml/tinyxmlparser.cpp b/lib/third_party/tinyxml/tinyxmlparser.cpp
new file mode 100644 (file)
index 0000000..505e5c7
--- /dev/null
@@ -0,0 +1,1634 @@
+/*
+  www.sourceforge.net/projects/tinyxml
+  Original code (2.0 and earlier )copyright (c) 2000-2002 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 <ctype.h>
+#include <stddef.h>
+
+#include "tinyxml.h"
+
+//#define DEBUG_PARSER
+#if defined( DEBUG_PARSER )
+#       if defined( DEBUG ) && defined( _MSC_VER )
+#               include <windows.h>
+#               define TIXML_LOG OutputDebugString
+#       else
+#               define TIXML_LOG printf
+#       endif
+#endif
+
+// Note tha "PutString" hardcodes the same list. This
+// is less flexible than it appears. Changing the entries
+// or order will break putstring.
+TiXmlBase::Entity TiXmlBase::entity[ NUM_ENTITY ] =
+{
+  { "&amp;",  5, '&' },
+  { "&lt;",   4, '<' },
+  { "&gt;",   4, '>' },
+  { "&quot;", 6, '\"' },
+  { "&apos;", 6, '\'' }
+};
+
+// Bunch of unicode info at:
+//              http://www.unicode.org/faq/utf_bom.html
+// Including the basic of this table, which determines the #bytes in the
+// sequence from the lead byte. 1 placed for invalid sequences --
+// although the result will be junk, pass it through as much as possible.
+// Beware of the non-characters in UTF-8:
+//                              ef bb bf (Microsoft "lead bytes")
+//                              ef bf be
+//                              ef bf bf
+
+const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
+const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
+const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
+
+const int TiXmlBase::utf8ByteTable[256] =
+{
+  //      0       1       2       3       4       5       6       7       8       9       a       b       c       d       e       f
+  1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      // 0x00
+  1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      // 0x10
+  1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      // 0x20
+  1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      // 0x30
+  1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      // 0x40
+  1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      // 0x50
+  1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      // 0x60
+  1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      // 0x70 End of ASCII range
+  1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      // 0x80 0x80 to 0xc1 invalid
+  1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      // 0x90
+  1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      // 0xa0
+  1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      // 0xb0
+  1,      1,      2,      2,      2,      2,      2,      2,      2,      2,      2,      2,      2,      2,      2,      2,      // 0xc0 0xc2 to 0xdf 2 byte
+  2,      2,      2,      2,      2,      2,      2,      2,      2,      2,      2,      2,      2,      2,      2,      2,      // 0xd0
+  3,      3,      3,      3,      3,      3,      3,      3,      3,      3,      3,      3,      3,      3,      3,      3,      // 0xe0 0xe0 to 0xef 3 byte
+  4,      4,      4,      4,      4,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1       // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid
+};
+
+
+void TiXmlBase::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; return; }        // This code won't covert this correctly anyway.
+
+  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]);
+  }
+}
+
+
+/*static*/ int TiXmlBase::IsAlpha( unsigned char anyByte, TiXmlEncoding /*encoding*/ )
+{
+  // This will only work for low-ascii, everything else is assumed to be a valid
+  // letter. I'm not sure this is the best approach, but it is quite tricky trying
+  // to figure out alhabetical vs. not across encoding. So take a very
+  // conservative approach.
+
+//      if ( encoding == TIXML_ENCODING_UTF8 )
+//      {
+  if ( anyByte < 127 )
+    return isalpha( anyByte );
+  else
+    return 1;       // What else to do? The unicode set is huge...get the english ones right.
+//      }
+//      else
+//      {
+//              return isalpha( anyByte );
+//      }
+}
+
+
+/*static*/ int TiXmlBase::IsAlphaNum( unsigned char anyByte, TiXmlEncoding /*encoding*/ )
+{
+  // This will only work for low-ascii, everything else is assumed to be a valid
+  // letter. I'm not sure this is the best approach, but it is quite tricky trying
+  // to figure out alhabetical vs. not across encoding. So take a very
+  // conservative approach.
+
+//      if ( encoding == TIXML_ENCODING_UTF8 )
+//      {
+  if ( anyByte < 127 )
+    return isalnum( anyByte );
+  else
+    return 1;       // What else to do? The unicode set is huge...get the english ones right.
+//      }
+//      else
+//      {
+//              return isalnum( anyByte );
+//      }
+}
+
+
+class TiXmlParsingData
+{
+  friend class TiXmlDocument;
+public:
+  void Stamp( const char* now, TiXmlEncoding encoding );
+
+  const TiXmlCursor& Cursor()     { return cursor; }
+
+private:
+  // Only used by the document!
+  TiXmlParsingData( const char* start, int _tabsize, int row, int col )
+    {
+      assert( start );
+      stamp = start;
+      tabsize = _tabsize;
+      cursor.row = row;
+      cursor.col = col;
+    }
+
+  TiXmlCursor             cursor;
+  const char*             stamp;
+  int                             tabsize;
+};
+
+
+void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding )
+{
+  assert( now );
+
+  // Do nothing if the tabsize is 0.
+  if ( tabsize < 1 )
+  {
+    return;
+  }
+
+  // Get the current row, column.
+  int row = cursor.row;
+  int col = cursor.col;
+  const char* p = stamp;
+  assert( p );
+
+  while ( p < now )
+  {
+    // Treat p as unsigned, so we have a happy compiler.
+    const unsigned char* pU = (const unsigned char*)p;
+
+    // Code contributed by Fletcher Dunn: (modified by lee)
+    switch (*pU) {
+    case 0:
+      // We *should* never get here, but in case we do, don't
+      // advance past the terminating null character, ever
+      return;
+
+    case '\r':
+      // bump down to the next line
+      ++row;
+      col = 0;
+      // Eat the character
+      ++p;
+
+      // Check for \r\n sequence, and treat this as a single character
+      if (*p == '\n') {
+        ++p;
+      }
+      break;
+
+    case '\n':
+      // bump down to the next line
+      ++row;
+      col = 0;
+
+      // Eat the character
+      ++p;
+
+      // Check for \n\r sequence, and treat this as a single
+      // character.  (Yes, this bizarre thing does occur still
+      // on some arcane platforms...)
+      if (*p == '\r') {
+        ++p;
+      }
+      break;
+
+    case '\t':
+      // Eat the character
+      ++p;
+
+      // Skip to next tab stop
+      col = (col / tabsize + 1) * tabsize;
+      break;
+
+    case TIXML_UTF_LEAD_0:
+      if ( encoding == TIXML_ENCODING_UTF8 )
+      {
+        if ( *(p+1) && *(p+2) )
+        {
+          // In these cases, don't advance the column. These are
+          // 0-width spaces.
+          if ( *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 )
+            p += 3;
+          else if ( *(pU+1)==0xbfU && *(pU+2)==0xbeU )
+            p += 3;
+          else if ( *(pU+1)==0xbfU && *(pU+2)==0xbfU )
+            p += 3;
+          else
+          { p +=3; ++col; }       // A normal character.
+        }
+      }
+      else
+      {
+        ++p;
+        ++col;
+      }
+      break;
+
+    default:
+      if ( encoding == TIXML_ENCODING_UTF8 )
+      {
+        // Eat the 1 to 4 byte utf8 character.
+        int step = TiXmlBase::utf8ByteTable[*((const unsigned char*)p)];
+        if ( step == 0 )
+          step = 1;               // Error case from bad encoding, but handle gracefully.
+        p += step;
+
+        // Just advance one column, of course.
+        ++col;
+      }
+      else
+      {
+        ++p;
+        ++col;
+      }
+      break;
+    }
+  }
+  cursor.row = row;
+  cursor.col = col;
+  assert( cursor.row >= -1 );
+  assert( cursor.col >= -1 );
+  stamp = p;
+  assert( stamp );
+}
+
+
+const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding )
+{
+  if ( !p || !*p )
+  {
+    return 0;
+  }
+  if ( encoding == TIXML_ENCODING_UTF8 )
+  {
+    while ( *p )
+    {
+      const unsigned char* pU = (const unsigned char*)p;
+
+      // Skip the stupid Microsoft UTF-8 Byte order marks
+      if (    *(pU+0)==TIXML_UTF_LEAD_0
+              && *(pU+1)==TIXML_UTF_LEAD_1
+              && *(pU+2)==TIXML_UTF_LEAD_2 )
+      {
+        p += 3;
+        continue;
+      }
+      else if(*(pU+0)==TIXML_UTF_LEAD_0
+              && *(pU+1)==0xbfU
+              && *(pU+2)==0xbeU )
+      {
+        p += 3;
+        continue;
+      }
+      else if(*(pU+0)==TIXML_UTF_LEAD_0
+              && *(pU+1)==0xbfU
+              && *(pU+2)==0xbfU )
+      {
+        p += 3;
+        continue;
+      }
+
+      if ( IsWhiteSpace( *p ) )               // Still using old rules for white space.
+        ++p;
+      else
+        break;
+    }
+  }
+  else
+  {
+    while ( *p && IsWhiteSpace( *p ) )
+      ++p;
+  }
+
+  return p;
+}
+
+#ifdef TIXML_USE_STL
+/*static*/ bool TiXmlBase::StreamWhiteSpace( std::istream * in, TIXML_STRING * tag )
+{
+  for( ;; )
+  {
+    if ( !in->good() ) return false;
+
+    int c = in->peek();
+    // At this scope, we can't get to a document. So fail silently.
+    if ( !IsWhiteSpace( c ) || c <= 0 )
+      return true;
+
+    *tag += (char) in->get();
+  }
+}
+
+/*static*/ bool TiXmlBase::StreamTo( std::istream * in, int character, TIXML_STRING * tag )
+{
+  //assert( character > 0 && character < 128 );   // else it won't work in utf-8
+  while ( in->good() )
+  {
+    int c = in->peek();
+    if ( c == character )
+      return true;
+    if ( c <= 0 )           // Silent failure: can't get document at this scope
+      return false;
+
+    in->get();
+    *tag += (char) c;
+  }
+  return false;
+}
+#endif
+
+// One of TinyXML's more performance demanding functions. Try to keep the memory overhead down. The
+// "assign" optimization removes over 10% of the execution time.
+//
+const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncoding encoding )
+{
+  // Oddly, not supported on some comilers,
+  //name->clear();
+  // So use this:
+  *name = "";
+  assert( p );
+
+  // Names start with letters or underscores.
+  // Of course, in unicode, tinyxml has no idea what a letter *is*. The
+  // algorithm is generous.
+  //
+  // After that, they can be letters, underscores, numbers,
+  // hyphens, or colons. (Colons are valid ony for namespaces,
+  // but tinyxml can't tell namespaces from names.)
+  if (    p && *p
+          && ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) )
+  {
+    const char* start = p;
+    while(          p && *p
+                    &&      (               IsAlphaNum( (unsigned char ) *p, encoding )
+                                            || *p == '_'
+                                            || *p == '-'
+                                            || *p == '.'
+                                            || *p == ':' ) )
+    {
+      //(*name) += *p; // expensive
+      ++p;
+    }
+    if ( p-start > 0 ) {
+      name->assign( start, p-start );
+    }
+    return p;
+  }
+  return 0;
+}
+
+const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXmlEncoding encoding )
+{
+  // Presume an entity, and pull it out.
+  TIXML_STRING ent;
+  int i;
+  *length = 0;
+
+  if ( *(p+1) && *(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;
+      }
+    }
+    if ( encoding == TIXML_ENCODING_UTF8 )
+    {
+      // convert the UCS to UTF-8
+      ConvertUTF32ToUTF8( ucs, value, length );
+    }
+    else
+    {
+      *value = (char)ucs;
+      *length = 1;
+    }
+    return p + delta + 1;
+  }
+
+  // Now try to match it.
+  for( i=0; i<NUM_ENTITY; ++i )
+  {
+    if ( strncmp( entity[i].str, p, entity[i].strLength ) == 0 )
+    {
+      assert( strlen( entity[i].str ) == entity[i].strLength );
+      *value = entity[i].chr;
+      *length = 1;
+      return ( p + entity[i].strLength );
+    }
+  }
+
+  // So it wasn't an entity, its unrecognized, or something like that.
+  *value = *p;    // Don't put back the last one, since we return it!
+  //*length = 1;  // Leave unrecognized entities - this doesn't really work.
+  // Just writes strange XML.
+  return p+1;
+}
+
+
+bool TiXmlBase::StringEqual( const char* p,
+                             const char* tag,
+                             bool ignoreCase,
+                             TiXmlEncoding encoding )
+{
+  assert( p );
+  assert( tag );
+  if ( !p || !*p )
+  {
+    assert( 0 );
+    return false;
+  }
+
+  const char* q = p;
+
+  if ( ignoreCase )
+  {
+    while ( *q && *tag && ToLower( *q, encoding ) == ToLower( *tag, encoding ) )
+    {
+      ++q;
+      ++tag;
+    }
+
+    if ( *tag == 0 )
+      return true;
+  }
+  else
+  {
+    while ( *q && *tag && *q == *tag )
+    {
+      ++q;
+      ++tag;
+    }
+
+    if ( *tag == 0 )                // Have we found the end of the tag, and everything equal?
+      return true;
+  }
+  return false;
+}
+
+const char* TiXmlBase::ReadText(        const char* p,
+                                        TIXML_STRING * text,
+                                        bool trimWhiteSpace,
+                                        const char* endTag,
+                                        bool caseInsensitive,
+                                        TiXmlEncoding encoding )
+{
+  *text = "";
+  if (    !trimWhiteSpace                 // certain tags always keep whitespace
+          || !condenseWhiteSpace )       // if true, whitespace is always kept
+  {
+    // Keep all the white space.
+    while (    p && *p
+               && !StringEqual( p, endTag, caseInsensitive, encoding )
+      )
+    {
+      int len;
+      char cArr[4] = { 0, 0, 0, 0 };
+      p = GetChar( p, cArr, &len, encoding );
+      text->append( cArr, len );
+    }
+  }
+  else
+  {
+    bool whitespace = false;
+
+    // Remove leading white space:
+    p = SkipWhiteSpace( p, encoding );
+    while (    p && *p
+               && !StringEqual( p, endTag, caseInsensitive, encoding ) )
+    {
+      if ( *p == '\r' || *p == '\n' )
+      {
+        whitespace = true;
+        ++p;
+      }
+      else if ( IsWhiteSpace( *p ) )
+      {
+        whitespace = true;
+        ++p;
+      }
+      else
+      {
+        // If we've found whitespace, add it before the
+        // new character. Any whitespace just becomes a space.
+        if ( whitespace )
+        {
+          (*text) += ' ';
+          whitespace = false;
+        }
+        int len;
+        char cArr[4] = { 0, 0, 0, 0 };
+        p = GetChar( p, cArr, &len, encoding );
+        if ( len == 1 )
+          (*text) += cArr[0];     // more efficient
+        else
+          text->append( cArr, len );
+      }
+    }
+  }
+  if ( p && *p )
+    p += strlen( endTag );
+  return p;
+}
+
+#ifdef TIXML_USE_STL
+
+void TiXmlDocument::StreamIn( std::istream * in, TIXML_STRING * tag )
+{
+  // The basic issue with a document is that we don't know what we're
+  // streaming. Read something presumed to be a tag (and hope), then
+  // identify it, and call the appropriate stream method on the tag.
+  //
+  // This "pre-streaming" will never read the closing ">" so the
+  // sub-tag can orient itself.
+
+  if ( !StreamTo( in, '<', tag ) )
+  {
+    SetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
+    return;
+  }
+
+  while ( in->good() )
+  {
+    int tagIndex = (int) tag->length();
+    while ( in->good() && in->peek() != '>' )
+    {
+      int c = in->get();
+      if ( c <= 0 )
+      {
+        SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
+        break;
+      }
+      (*tag) += (char) c;
+    }
+
+    if ( in->good() )
+    {
+      // We now have something we presume to be a node of
+      // some sort. Identify it, and call the node to
+      // continue streaming.
+      TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING );
+
+      if ( node )
+      {
+        node->StreamIn( in, tag );
+        bool isElement = node->ToElement() != 0;
+        delete node;
+        node = 0;
+
+        // If this is the root element, we're done. Parsing will be
+        // done by the >> operator.
+        if ( isElement )
+        {
+          return;
+        }
+      }
+      else
+      {
+        SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN );
+        return;
+      }
+    }
+  }
+  // We should have returned sooner.
+  SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN );
+}
+
+#endif
+
+const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiXmlEncoding encoding )
+{
+  ClearError();
+
+  // Parse away, at the document level. Since a document
+  // contains nothing but other tags, most of what happens
+  // here is skipping white space.
+  if ( !p || !*p )
+  {
+    SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
+    return 0;
+  }
+
+  // Note that, for a document, this needs to come
+  // before the while space skip, so that parsing
+  // starts from the pointer we are given.
+  location.Clear();
+  if ( prevData )
+  {
+    location.row = prevData->cursor.row;
+    location.col = prevData->cursor.col;
+  }
+  else
+  {
+    location.row = 0;
+    location.col = 0;
+  }
+  TiXmlParsingData data( p, TabSize(), location.row, location.col );
+  location = data.Cursor();
+
+  if ( encoding == TIXML_ENCODING_UNKNOWN )
+  {
+    // Check for the Microsoft UTF-8 lead bytes.
+    const unsigned char* pU = (const unsigned char*)p;
+    if (    *(pU+0) && *(pU+0) == TIXML_UTF_LEAD_0
+            && *(pU+1) && *(pU+1) == TIXML_UTF_LEAD_1
+            && *(pU+2) && *(pU+2) == TIXML_UTF_LEAD_2 )
+    {
+      encoding = TIXML_ENCODING_UTF8;
+      useMicrosoftBOM = true;
+    }
+  }
+
+  p = SkipWhiteSpace( p, encoding );
+  if ( !p )
+  {
+    SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
+    return 0;
+  }
+
+  while ( p && *p )
+  {
+    TiXmlNode* node = Identify( p, encoding );
+    if ( node )
+    {
+      p = node->Parse( p, &data, encoding );
+      LinkEndChild( node );
+    }
+    else
+    {
+      break;
+    }
+
+    // Did we get encoding info?
+    if (    encoding == TIXML_ENCODING_UNKNOWN
+            && node->ToDeclaration() )
+    {
+      TiXmlDeclaration* dec = node->ToDeclaration();
+      const char* enc = dec->Encoding();
+      assert( enc );
+
+      if ( *enc == 0 )
+        encoding = TIXML_ENCODING_UTF8;
+      else if ( StringEqual( enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN ) )
+        encoding = TIXML_ENCODING_UTF8;
+      else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) )
+        encoding = TIXML_ENCODING_UTF8; // incorrect, but be nice
+      else
+        encoding = TIXML_ENCODING_LEGACY;
+    }
+
+    p = SkipWhiteSpace( p, encoding );
+  }
+
+  // Was this empty?
+  if ( !firstChild ) {
+    SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, encoding );
+    return 0;
+  }
+
+  // All is well.
+  return p;
+}
+
+void TiXmlDocument::SetError( int err, const char* pError, TiXmlParsingData* data, TiXmlEncoding encoding )
+{
+  // The first error in a chain is more accurate - don't set again!
+  if ( error )
+    return;
+
+  assert( err > 0 && err < TIXML_ERROR_STRING_COUNT );
+  error   = true;
+  errorId = err;
+  errorDesc = errorString[ errorId ];
+
+  errorLocation.Clear();
+  if ( pError && data )
+  {
+    data->Stamp( pError, encoding );
+    errorLocation = data->Cursor();
+  }
+}
+
+
+TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding )
+{
+  TiXmlNode* returnNode = 0;
+
+  p = SkipWhiteSpace( p, encoding );
+  if( !p || !*p || *p != '<' )
+  {
+    return 0;
+  }
+
+  p = SkipWhiteSpace( p, encoding );
+
+  if ( !p || !*p )
+  {
+    return 0;
+  }
+
+  // What is this thing?
+  // - Elements start with a letter or underscore, but xml is reserved.
+  // - Comments: <!--
+  // - Decleration: <?xml
+  // - Everthing else is unknown to tinyxml.
+  //
+
+  const char* xmlHeader = { "<?xml" };
+  const char* commentHeader = { "<!--" };
+  const char* dtdHeader = { "<!" };
+  const char* cdataHeader = { "<![CDATA[" };
+
+  if ( StringEqual( p, xmlHeader, true, encoding ) )
+  {
+#ifdef DEBUG_PARSER
+    TIXML_LOG( "XML parsing Declaration\n" );
+#endif
+    returnNode = new TiXmlDeclaration();
+  }
+  else if ( StringEqual( p, commentHeader, false, encoding ) )
+  {
+#ifdef DEBUG_PARSER
+    TIXML_LOG( "XML parsing Comment\n" );
+#endif
+    returnNode = new TiXmlComment();
+  }
+  else if ( StringEqual( p, cdataHeader, false, encoding ) )
+  {
+#ifdef DEBUG_PARSER
+    TIXML_LOG( "XML parsing CDATA\n" );
+#endif
+    TiXmlText* text = new TiXmlText( "" );
+    text->SetCDATA( true );
+    returnNode = text;
+  }
+  else if ( StringEqual( p, dtdHeader, false, encoding ) )
+  {
+#ifdef DEBUG_PARSER
+    TIXML_LOG( "XML parsing Unknown(1)\n" );
+#endif
+    returnNode = new TiXmlUnknown();
+  }
+  else if (    IsAlpha( *(p+1), encoding )
+               || *(p+1) == '_' )
+  {
+#ifdef DEBUG_PARSER
+    TIXML_LOG( "XML parsing Element\n" );
+#endif
+    returnNode = new TiXmlElement( "" );
+  }
+  else
+  {
+#ifdef DEBUG_PARSER
+    TIXML_LOG( "XML parsing Unknown(2)\n" );
+#endif
+    returnNode = new TiXmlUnknown();
+  }
+
+  if ( returnNode )
+  {
+    // Set the parent, so it can report errors
+    returnNode->parent = this;
+  }
+  return returnNode;
+}
+
+#ifdef TIXML_USE_STL
+
+void TiXmlElement::StreamIn (std::istream * in, TIXML_STRING * tag)
+{
+  // We're called with some amount of pre-parsing. That is, some of "this"
+  // element is in "tag". Go ahead and stream to the closing ">"
+  while( in->good() )
+  {
+    int c = in->get();
+    if ( c <= 0 )
+    {
+      TiXmlDocument* document = GetDocument();
+      if ( document )
+        document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
+      return;
+    }
+    (*tag) += (char) c ;
+
+    if ( c == '>' )
+      break;
+  }
+
+  if ( tag->length() < 3 ) return;
+
+  // Okay...if we are a "/>" tag, then we're done. We've read a complete tag.
+  // If not, identify and stream.
+
+  if (    tag->at( tag->length() - 1 ) == '>'
+          && tag->at( tag->length() - 2 ) == '/' )
+  {
+    // All good!
+    return;
+  }
+  else if ( tag->at( tag->length() - 1 ) == '>' )
+  {
+    // There is more. Could be:
+    //              text
+    //              cdata text (which looks like another node)
+    //              closing tag
+    //              another node.
+    for ( ;; )
+    {
+      StreamWhiteSpace( in, tag );
+
+      // Do we have text?
+      if ( in->good() && in->peek() != '<' )
+      {
+        // Yep, text.
+        TiXmlText text( "" );
+        text.StreamIn( in, tag );
+
+        // What follows text is a closing tag or another node.
+        // Go around again and figure it out.
+        continue;
+      }
+
+      // We now have either a closing tag...or another node.
+      // We should be at a "<", regardless.
+      if ( !in->good() ) return;
+      assert( in->peek() == '<' );
+      int tagIndex = (int) tag->length();
+
+      bool closingTag = false;
+      bool firstCharFound = false;
+
+      for( ;; )
+      {
+        if ( !in->good() )
+          return;
+
+        int c = in->peek();
+        if ( c <= 0 )
+        {
+          TiXmlDocument* document = GetDocument();
+          if ( document )
+            document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
+          return;
+        }
+
+        if ( c == '>' )
+          break;
+
+        *tag += (char) c;
+        in->get();
+
+        // Early out if we find the CDATA id.
+        if ( c == '[' && tag->size() >= 9 )
+        {
+          size_t len = tag->size();
+          const char* start = tag->c_str() + len - 9;
+          if ( strcmp( start, "<![CDATA[" ) == 0 ) {
+            assert( !closingTag );
+            break;
+          }
+        }
+
+        if ( !firstCharFound && c != '<' && !IsWhiteSpace( c ) )
+        {
+          firstCharFound = true;
+          if ( c == '/' )
+            closingTag = true;
+        }
+      }
+      // If it was a closing tag, then read in the closing '>' to clean up the input stream.
+      // If it was not, the streaming will be done by the tag.
+      if ( closingTag )
+      {
+        if ( !in->good() )
+          return;
+
+        int c = in->get();
+        if ( c <= 0 )
+        {
+          TiXmlDocument* document = GetDocument();
+          if ( document )
+            document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
+          return;
+        }
+        assert( c == '>' );
+        *tag += (char) c;
+
+        // We are done, once we've found our closing tag.
+        return;
+      }
+      else
+      {
+        // If not a closing tag, id it, and stream.
+        const char* tagloc = tag->c_str() + tagIndex;
+        TiXmlNode* node = Identify( tagloc, TIXML_DEFAULT_ENCODING );
+        if ( !node )
+          return;
+        node->StreamIn( in, tag );
+        delete node;
+        node = 0;
+
+        // No return: go around from the beginning: text, closing tag, or node.
+      }
+    }
+  }
+}
+#endif
+
+const char* TiXmlElement::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
+{
+  p = SkipWhiteSpace( p, encoding );
+  TiXmlDocument* document = GetDocument();
+
+  if ( !p || !*p )
+  {
+    if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, 0, 0, encoding );
+    return 0;
+  }
+
+  if ( data )
+  {
+    data->Stamp( p, encoding );
+    location = data->Cursor();
+  }
+
+  if ( *p != '<' )
+  {
+    if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, p, data, encoding );
+    return 0;
+  }
+
+  p = SkipWhiteSpace( p+1, encoding );
+
+  // Read the name.
+  const char* pErr = p;
+
+  p = ReadName( p, &value, encoding );
+  if ( !p || !*p )
+  {
+    if ( document ) document->SetError( TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, pErr, data, encoding );
+    return 0;
+  }
+
+  TIXML_STRING endTag ("</");
+  endTag += value;
+
+  // Check for and read attributes. Also look for an empty
+  // tag or an end tag.
+  while ( p && *p )
+  {
+    pErr = p;
+    p = SkipWhiteSpace( p, encoding );
+    if ( !p || !*p )
+    {
+      if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding );
+      return 0;
+    }
+    if ( *p == '/' )
+    {
+      ++p;
+      // Empty tag.
+      if ( *p  != '>' )
+      {
+        if ( document ) document->SetError( TIXML_ERROR_PARSING_EMPTY, p, data, encoding );
+        return 0;
+      }
+      return (p+1);
+    }
+    else if ( *p == '>' )
+    {
+      // Done with attributes (if there were any.)
+      // Read the value -- which can include other
+      // elements -- read the end tag, and return.
+      ++p;
+      p = ReadValue( p, data, encoding );             // Note this is an Element method, and will set the error if one happens.
+      if ( !p || !*p ) {
+        // We were looking for the end tag, but found nothing.
+        // Fix for [ 1663758 ] Failure to report error on bad XML
+        if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding );
+        return 0;
+      }
+
+      // We should find the end tag now
+      // note that:
+      // </foo > and
+      // </foo>
+      // are both valid end tags.
+      if ( StringEqual( p, endTag.c_str(), false, encoding ) )
+      {
+        p += endTag.length();
+        p = SkipWhiteSpace( p, encoding );
+        if ( p && *p && *p == '>' ) {
+          ++p;
+          return p;
+        }
+        if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding );
+        return 0;
+      }
+      else
+      {
+        if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding );
+        return 0;
+      }
+    }
+    else
+    {
+      // Try to read an attribute:
+      TiXmlAttribute* attrib = new TiXmlAttribute();
+      if ( !attrib )
+      {
+        return 0;
+      }
+
+      attrib->SetDocument( document );
+      pErr = p;
+      p = attrib->Parse( p, data, encoding );
+
+      if ( !p || !*p )
+      {
+        if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, pErr, data, encoding );
+        delete attrib;
+        return 0;
+      }
+
+      // Handle the strange case of double attributes:
+#ifdef TIXML_USE_STL
+      TiXmlAttribute* node = attributeSet.Find( attrib->NameTStr() );
+#else
+      TiXmlAttribute* node = attributeSet.Find( attrib->Name() );
+#endif
+      if ( node )
+      {
+        if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, pErr, data, encoding );
+        delete attrib;
+        return 0;
+      }
+
+      attributeSet.Add( attrib );
+    }
+  }
+  return p;
+}
+
+
+const char* TiXmlElement::ReadValue( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
+{
+  TiXmlDocument* document = GetDocument();
+
+  // Read in text and elements in any order.
+  const char* pWithWhiteSpace = p;
+  p = SkipWhiteSpace( p, encoding );
+
+  while ( p && *p )
+  {
+    if ( *p != '<' )
+    {
+      // Take what we have, make a text element.
+      TiXmlText* textNode = new TiXmlText( "" );
+
+      if ( !textNode )
+      {
+        return 0;
+      }
+
+      if ( TiXmlBase::IsWhiteSpaceCondensed() )
+      {
+        p = textNode->Parse( p, data, encoding );
+      }
+      else
+      {
+        // Special case: we want to keep the white space
+        // so that leading spaces aren't removed.
+        p = textNode->Parse( pWithWhiteSpace, data, encoding );
+      }
+
+      if ( !textNode->Blank() )
+        LinkEndChild( textNode );
+      else
+        delete textNode;
+    }
+    else
+    {
+      // We hit a '<'
+      // Have we hit a new element or an end tag? This could also be
+      // a TiXmlText in the "CDATA" style.
+      if ( StringEqual( p, "</", false, encoding ) )
+      {
+        return p;
+      }
+      else
+      {
+        TiXmlNode* node = Identify( p, encoding );
+        if ( node )
+        {
+          p = node->Parse( p, data, encoding );
+          LinkEndChild( node );
+        }
+        else
+        {
+          return 0;
+        }
+      }
+    }
+    pWithWhiteSpace = p;
+    p = SkipWhiteSpace( p, encoding );
+  }
+
+  if ( !p )
+  {
+    if ( document ) document->SetError( TIXML_ERROR_READING_ELEMENT_VALUE, 0, 0, encoding );
+  }
+  return p;
+}
+
+
+#ifdef TIXML_USE_STL
+void TiXmlUnknown::StreamIn( std::istream * in, TIXML_STRING * tag )
+{
+  while ( in->good() )
+  {
+    int c = in->get();
+    if ( c <= 0 )
+    {
+      TiXmlDocument* document = GetDocument();
+      if ( document )
+        document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
+      return;
+    }
+    (*tag) += (char) c;
+
+    if ( c == '>' )
+    {
+      // All is well.
+      return;
+    }
+  }
+}
+#endif
+
+
+const char* TiXmlUnknown::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
+{
+  TiXmlDocument* document = GetDocument();
+  p = SkipWhiteSpace( p, encoding );
+
+  if ( data )
+  {
+    data->Stamp( p, encoding );
+    location = data->Cursor();
+  }
+  if ( !p || !*p || *p != '<' )
+  {
+    if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, p, data, encoding );
+    return 0;
+  }
+  ++p;
+  value = "";
+
+  while ( p && *p && *p != '>' )
+  {
+    value += *p;
+    ++p;
+  }
+
+  if ( !p )
+  {
+    if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, 0, 0, encoding );
+  }
+  if ( *p == '>' )
+    return p+1;
+  return p;
+}
+
+#ifdef TIXML_USE_STL
+void TiXmlComment::StreamIn( std::istream * in, TIXML_STRING * tag )
+{
+  while ( in->good() )
+  {
+    int c = in->get();
+    if ( c <= 0 )
+    {
+      TiXmlDocument* document = GetDocument();
+      if ( document )
+        document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
+      return;
+    }
+
+    (*tag) += (char) c;
+
+    if ( c == '>'
+         && tag->at( tag->length() - 2 ) == '-'
+         && tag->at( tag->length() - 3 ) == '-' )
+    {
+      // All is well.
+      return;
+    }
+  }
+}
+#endif
+
+
+const char* TiXmlComment::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
+{
+  TiXmlDocument* document = GetDocument();
+  value = "";
+
+  p = SkipWhiteSpace( p, encoding );
+
+  if ( data )
+  {
+    data->Stamp( p, encoding );
+    location = data->Cursor();
+  }
+  const char* startTag = "<!--";
+  const char* endTag   = "-->";
+
+  if ( !StringEqual( p, startTag, false, encoding ) )
+  {
+    document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding );
+    return 0;
+  }
+  p += strlen( startTag );
+
+  // [ 1475201 ] TinyXML parses entities in comments
+  // Oops - ReadText doesn't work, because we don't want to parse the entities.
+  // p = ReadText( p, &value, false, endTag, false, encoding );
+  //
+  // from the XML spec:
+  /*
+    [Definition: Comments may appear anywhere in a document outside other markup; in addition,
+    they may appear within the document type declaration at places allowed by the grammar.
+    They are not part of the document's character data; an XML processor MAY, but need not,
+    make it possible for an application to retrieve the text of comments. For compatibility,
+    the string "--" (double-hyphen) MUST NOT occur within comments.] Parameter entity
+    references MUST NOT be recognized within comments.
+
+    An example of a comment:
+
+    <!-- declarations for <head> & <body> -->
+  */
+
+  value = "";
+  // Keep all the white space.
+  while ( p && *p && !StringEqual( p, endTag, false, encoding ) )
+  {
+    value.append( p, 1 );
+    ++p;
+  }
+  if ( p && *p )
+    p += strlen( endTag );
+
+  return p;
+}
+
+
+const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
+{
+  p = SkipWhiteSpace( p, encoding );
+  if ( !p || !*p ) return 0;
+
+  if ( data )
+  {
+    data->Stamp( p, encoding );
+    location = data->Cursor();
+  }
+  // Read the name, the '=' and the value.
+  const char* pErr = p;
+  p = ReadName( p, &name, encoding );
+  if ( !p || !*p )
+  {
+    if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding );
+    return 0;
+  }
+  p = SkipWhiteSpace( p, encoding );
+  if ( !p || !*p || *p != '=' )
+  {
+    if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );
+    return 0;
+  }
+
+  ++p;    // skip '='
+  p = SkipWhiteSpace( p, encoding );
+  if ( !p || !*p )
+  {
+    if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );
+    return 0;
+  }
+
+  const char* end;
+  const char SINGLE_QUOTE = '\'';
+  const char DOUBLE_QUOTE = '\"';
+
+  if ( *p == SINGLE_QUOTE )
+  {
+    ++p;
+    end = "\'";             // single quote in string
+    p = ReadText( p, &value, false, end, false, encoding );
+  }
+  else if ( *p == DOUBLE_QUOTE )
+  {
+    ++p;
+    end = "\"";             // double quote in string
+    p = ReadText( p, &value, false, end, false, encoding );
+  }
+  else
+  {
+    // All attribute values should be in single or double quotes.
+    // But this is such a common error that the parser will try
+    // its best, even without them.
+    value = "";
+    while (    p && *p                                                                                      // existence
+               && !IsWhiteSpace( *p )                                                          // whitespace
+               && *p != '/' && *p != '>' )                                                     // tag end
+    {
+      if ( *p == SINGLE_QUOTE || *p == DOUBLE_QUOTE ) {
+        // [ 1451649 ] Attribute values with trailing quotes not handled correctly
+        // We did not have an opening quote but seem to have a
+        // closing one. Give up and throw an error.
+        if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );
+        return 0;
+      }
+      value += *p;
+      ++p;
+    }
+  }
+  return p;
+}
+
+#ifdef TIXML_USE_STL
+void TiXmlText::StreamIn( std::istream * in, TIXML_STRING * tag )
+{
+  while ( in->good() )
+  {
+    int c = in->peek();
+    if ( !cdata && (c == '<' ) )
+    {
+      return;
+    }
+    if ( c <= 0 )
+    {
+      TiXmlDocument* document = GetDocument();
+      if ( document )
+        document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
+      return;
+    }
+
+    (*tag) += (char) c;
+    in->get();      // "commits" the peek made above
+
+    if ( cdata && c == '>' && tag->size() >= 3 ) {
+      size_t len = tag->size();
+      if ( (*tag)[len-2] == ']' && (*tag)[len-3] == ']' ) {
+        // terminator of cdata.
+        return;
+      }
+    }
+  }
+}
+#endif
+
+const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
+{
+  value = "";
+  TiXmlDocument* document = GetDocument();
+
+  if ( data )
+  {
+    data->Stamp( p, encoding );
+    location = data->Cursor();
+  }
+
+  const char* const startTag = "<![CDATA[";
+  const char* const endTag   = "]]>";
+
+  if ( cdata || StringEqual( p, startTag, false, encoding ) )
+  {
+    cdata = true;
+
+    if ( !StringEqual( p, startTag, false, encoding ) )
+    {
+      document->SetError( TIXML_ERROR_PARSING_CDATA, p, data, encoding );
+      return 0;
+    }
+    p += strlen( startTag );
+
+    // Keep all the white space, ignore the encoding, etc.
+    while (    p && *p
+               && !StringEqual( p, endTag, false, encoding )
+      )
+    {
+      value += *p;
+      ++p;
+    }
+
+    TIXML_STRING dummy;
+    p = ReadText( p, &dummy, false, endTag, false, encoding );
+    return p;
+  }
+  else
+  {
+    bool ignoreWhite = true;
+
+    const char* end = "<";
+    p = ReadText( p, &value, ignoreWhite, end, false, encoding );
+    if ( p )
+      return p-1;     // don't truncate the '<'
+    return 0;
+  }
+}
+
+#ifdef TIXML_USE_STL
+void TiXmlDeclaration::StreamIn( std::istream * in, TIXML_STRING * tag )
+{
+  while ( in->good() )
+  {
+    int c = in->get();
+    if ( c <= 0 )
+    {
+      TiXmlDocument* document = GetDocument();
+      if ( document )
+        document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
+      return;
+    }
+    (*tag) += (char) c;
+
+    if ( c == '>' )
+    {
+      // All is well.
+      return;
+    }
+  }
+}
+#endif
+
+const char* TiXmlDeclaration::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding )
+{
+  p = SkipWhiteSpace( p, _encoding );
+  // Find the beginning, find the end, and look for
+  // the stuff in-between.
+  TiXmlDocument* document = GetDocument();
+  if ( !p || !*p || !StringEqual( p, "<?xml", true, _encoding ) )
+  {
+    if ( document ) document->SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding );
+    return 0;
+  }
+  if ( data )
+  {
+    data->Stamp( p, _encoding );
+    location = data->Cursor();
+  }
+  p += 5;
+
+  version = "";
+  encoding = "";
+  standalone = "";
+
+  while ( p && *p )
+  {
+    if ( *p == '>' )
+    {
+      ++p;
+      return p;
+    }
+
+    p = SkipWhiteSpace( p, _encoding );
+    if ( StringEqual( p, "version", true, _encoding ) )
+    {
+      TiXmlAttribute attrib;
+      p = attrib.Parse( p, data, _encoding );
+      version = attrib.Value();
+    }
+    else if ( StringEqual( p, "encoding", true, _encoding ) )
+    {
+      TiXmlAttribute attrib;
+      p = attrib.Parse( p, data, _encoding );
+      encoding = attrib.Value();
+    }
+    else if ( StringEqual( p, "standalone", true, _encoding ) )
+    {
+      TiXmlAttribute attrib;
+      p = attrib.Parse( p, data, _encoding );
+      standalone = attrib.Value();
+    }
+    else
+    {
+      // Read over whatever it is.
+      while( p && *p && *p != '>' && !IsWhiteSpace( *p ) )
+        ++p;
+    }
+  }
+  return 0;
+}
+
+bool TiXmlText::Blank() const
+{
+  for ( unsigned i=0; i<value.length(); i++ )
+    if ( !IsWhiteSpace( value[i] ) )
+      return false;
+  return true;
+}