Finalizing state to/from XML encoding and decoding
diff --git a/model/sync-diff-state.cc b/model/sync-diff-state.cc
index 5a53e81..75e0be5 100644
--- a/model/sync-diff-state.cc
+++ b/model/sync-diff-state.cc
@@ -79,32 +79,4 @@
   m_leaves.insert (leaf);
 }
 
-#ifdef _DEBUG
-#define DEBUG_ENDL os << "\n";
-#else
-#define DEBUG_ENDL
-#endif
-
-std::ostream &
-operator << (std::ostream &os, const DiffState &state)
-{
-  os << "<state type=\"diff\">"; DEBUG_ENDL;
-  
-  BOOST_FOREACH (shared_ptr<const Leaf> _leaf, state.getLeaves ())
-    {
-      shared_ptr<const DiffLeaf> leaf = dynamic_pointer_cast<const DiffLeaf> (_leaf);
-      BOOST_ASSERT (leaf != 0);
-
-      os << "<item action=\"" << leaf->getOperation () << "\">"; DEBUG_ENDL;
-      os << "<name>" << leaf->getInfo () << "</name>"; DEBUG_ENDL;
-      if (leaf->getOperation () == UPDATE)
-        {
-          os << "<seq>" << leaf->getSeq () << "</seq>"; DEBUG_ENDL;
-        }
-      os << "</item>"; DEBUG_ENDL;
-    }
-  os << "</state>";
-}
-
-
 } // ns3
diff --git a/model/sync-diff-state.h b/model/sync-diff-state.h
index 053be84..ac35625 100644
--- a/model/sync-diff-state.h
+++ b/model/sync-diff-state.h
@@ -97,15 +97,6 @@
   DigestConstPtr m_digest;
 };
 
-/**
- * @brief Formats an XML representation of the diff state
- * @param os output stream
- * @param state state
- * @returns output stream
- */
-std::ostream &
-operator << (std::ostream &os, const DiffState &state);
-
 } // Sync
 
 #endif // SYNC_DIFF_STATE_H
diff --git a/model/sync-full-state.cc b/model/sync-full-state.cc
index f53de39..e8a2149 100644
--- a/model/sync-full-state.cc
+++ b/model/sync-full-state.cc
@@ -117,25 +117,4 @@
   m_leaves.erase (*info);
 }
 
-#ifdef _DEBUG
-#define DEBUG_ENDL os << "\n";
-#else
-#define DEBUG_ENDL
-#endif
-
-std::ostream &
-operator << (std::ostream &os, const FullState &state)
-{
-  os << "<state type=\"full\">"; DEBUG_ENDL;
-  
-  BOOST_FOREACH (shared_ptr<const Leaf> leaf, state.getLeaves ())
-    {
-      os << "<item>"; DEBUG_ENDL;
-      os << "<name>" << leaf->getInfo () << "</name>"; DEBUG_ENDL;
-      os << "<seq>" << leaf->getSeq () << "</seq>"; DEBUG_ENDL;
-      os << "</item>"; DEBUG_ENDL;
-    }
-  os << "</state>";
-}
-
 } // Sync
diff --git a/model/sync-full-state.h b/model/sync-full-state.h
index 96597d0..9769878 100644
--- a/model/sync-full-state.h
+++ b/model/sync-full-state.h
@@ -78,16 +78,6 @@
   DigestPtr m_digest;
 };
 
-/**
- * @brief Formats an XML representation of the full state
- * @param os output stream
- * @param state state
- * @returns output stream
- */
-std::ostream &
-operator << (std::ostream &os, const FullState &state);
-
-
 } // Sync
 
 #endif // SYNC_STATE_H
diff --git a/model/sync-global-function.cc b/model/sync-global-function.cc
deleted file mode 100644
index c01b682..0000000
--- a/model/sync-global-function.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2012 University of California, Los Angeles
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
- *         卞超轶 Chaoyi Bian <bcy@pku.edu.cn>
- *	   Alexander Afanasyev <alexander.afanasyev@ucla.edu>
- */
-
-#define TIXML_USE_STL
-
-#include <string>
-#include <tinyxml.h>
-#include "sync-state.h"
-#include "sync-std-name-info.h"
-
-using namespace std;
-
-namespace Sync
-{
-  string & operator >> (string &DataBuffer, State &state)
-  {
-    TiXmlDocument doc;
-
-    doc.Parse(DataBuffer.c_str());
-    for (TiXmlElement *iterator = doc.RootElement(); iterator != NULL; iterator = iterator->NextSiblingElement())
-    {
-      if (strcmp(iterator->Attribute("action"), "update") == 0)
-      {
-	TiXmlElement *name = iterator->FirstChildElement();
-	TiXmlElement *session = name->NextSiblingElement();
-	TiXmlElement *sequence = session->NextSiblingElement();
-	NameInfoConstPtr info = StdNameInfo::FindOrCreate(name->GetText());
-	SeqNo seqNo(atoi(session->GetText()), atoi(sequence->GetText()));
-
-	state.update(info, seqNo);
-      }
-      else
-      {
-	TiXmlElement *name = iterator->FirstChildElement();
-	NameInfoConstPtr info = StdNameInfo::FindOrCreate(name->GetText());
-	state.remove(info);
-      }
-    }
-
-    return DataBuffer;
-  }
-}
diff --git a/model/sync-state.cc b/model/sync-state.cc
index 268a45f..5e09655 100644
--- a/model/sync-state.cc
+++ b/model/sync-state.cc
@@ -21,8 +21,102 @@
  */
 
 #include "sync-state.h"
+#include "sync-diff-leaf.h"
+#include "sync-std-name-info.h"
+
 #include <boost/assert.hpp>
+#include <boost/foreach.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/throw_exception.hpp>
+#include <boost/lexical_cast.hpp>
+
+#define TIXML_USE_STL
+#include <tinyxml.h>
+
+using namespace std;
+using namespace boost;
+
+typedef error_info<struct tag_errmsg, string> info_str; 
 
 namespace Sync {
 
+#ifdef _DEBUG
+#define DEBUG_ENDL os << "\n";
+#else
+#define DEBUG_ENDL
+#endif
+
+std::ostream &
+operator << (std::ostream &os, const State &state)
+{
+  os << "<state>"; DEBUG_ENDL;
+  
+  BOOST_FOREACH (shared_ptr<const Leaf> leaf, state.getLeaves ().get<ordered> ())
+    {
+      shared_ptr<const DiffLeaf> diffLeaf = dynamic_pointer_cast<const DiffLeaf> (leaf);
+      if (diffLeaf != 0)
+        {
+          os << "<item action=\"" << diffLeaf->getOperation () << "\">"; DEBUG_ENDL;
+        }
+      else
+        {
+          os << "<item>"; DEBUG_ENDL;
+        }
+      os << "<name>" << leaf->getInfo () << "</name>"; DEBUG_ENDL;
+      if (diffLeaf == 0 || (diffLeaf != 0 && diffLeaf->getOperation () == UPDATE))
+        {
+          os << "<seq>" << leaf->getSeq () << "</seq>"; DEBUG_ENDL;
+        }
+      os << "</item>"; DEBUG_ENDL;
+    }
+  os << "</state>";
+}
+
+std::istream &
+operator >> (std::istream &in, State &state)
+{
+  TiXmlDocument doc;
+  in >> doc;
+
+  if (doc.RootElement() == 0)
+        BOOST_THROW_EXCEPTION (SyncXmlDecodingFailure () << info_str ("Empty XML"));
+  
+  for (TiXmlElement *iterator = doc.RootElement()->FirstChildElement ("item");
+       iterator != 0;
+       iterator = iterator->NextSiblingElement("item"))
+    {
+      TiXmlElement *name = iterator->FirstChildElement ("name");
+      if (name == 0 || name->GetText() == 0)
+        BOOST_THROW_EXCEPTION (SyncXmlDecodingFailure () << info_str ("<name> element is missing"));
+        
+      NameInfoConstPtr info = StdNameInfo::FindOrCreate (name->GetText());
+      
+      if (iterator->Attribute("action") == 0 || strcmp(iterator->Attribute("action"), "update") == 0)
+        {
+          TiXmlElement *seq = iterator->FirstChildElement ("seq");
+          if (seq == 0)
+            BOOST_THROW_EXCEPTION (SyncXmlDecodingFailure () << info_str ("<seq> element is missing"));
+          
+          TiXmlElement *session = seq->FirstChildElement ("session");
+          TiXmlElement *seqno = seq->FirstChildElement ("seqno");
+
+          if (session == 0 || session->GetText() == 0)
+            BOOST_THROW_EXCEPTION (SyncXmlDecodingFailure () << info_str ("<session> element is missing"));
+          if (seqno == 0 || seqno->GetText() == 0)
+            BOOST_THROW_EXCEPTION (SyncXmlDecodingFailure () << info_str ("<seqno> element is missing"));
+
+          state.update (info, SeqNo (
+                                     lexical_cast<uint32_t> (session->GetText()),
+                                     lexical_cast<uint32_t> (seqno->GetText())
+                                     ));
+        }
+      else
+        {
+          state.remove (info);
+        }
+    }
+
+  return in;
+}
+
 }
diff --git a/model/sync-state.h b/model/sync-state.h
index 71e65c1..26ea5f4 100644
--- a/model/sync-state.h
+++ b/model/sync-state.h
@@ -24,6 +24,7 @@
 #define SYNC_STATE_H
 
 #include "sync-state-leaf-container.h"
+#include <boost/exception/all.hpp>
 
 /**
  * \defgroup sync SYNC protocol
@@ -68,7 +69,29 @@
   LeafContainer m_leaves;
 };
 
-std::string & operator >> (std::string &DataBuffer, State &state);
+/**
+ * @brief Formats an XML representation of the state
+ * @param os output stream
+ * @param state state
+ * @returns output stream
+ */
+std::ostream &
+operator << (std::ostream &os, const State &state);
+
+/**
+ * @brief Parses an XML representation to the state
+ * @param DataBuffer input data
+ * @param state state
+ */
+// void
+// operator >> (const std::string &DataBuffer, State &state);
+std::istream &
+operator >> (std::istream &in, State &state);
+
+/**
+ * @brief Will be thrown when XML cannot be properly decoded to State
+ */
+struct SyncXmlDecodingFailure : virtual boost::exception, virtual std::exception { };
 
 } // Sync
 
diff --git a/test/test_state.cc b/test/test_state.cc
index e1a5e81..7732798 100644
--- a/test/test_state.cc
+++ b/test/test_state.cc
@@ -147,21 +147,52 @@
   state.update (name2, SeqNo (12));
   state.update (name3, SeqNo (8));  
 
+  string xml1 = "<state>"
+    "<item><name>1</name><seq><session>0</session><seqno>10</seqno></seq></item>"
+    "<item><name>2</name><seq><session>0</session><seqno>12</seqno></seq></item>"
+    "<item><name>3</name><seq><session>0</session><seqno>8</seqno></seq></item>"
+    "</state>";
   {
   ostringstream os;
   os << state;
   string s = os.str ();
   erase_all (s, "\n");
-  BOOST_CHECK_EQUAL (s, "<state type=\"full\"><item><name>3</name><seq><session>0</session><seqno>8</seqno></seq></item><item><name>2</name><seq><session>0</session><seqno>12</seqno></seq></item><item><name>1</name><seq><session>0</session><seqno>10</seqno></seq></item></state>");
+  BOOST_CHECK_EQUAL (s, xml1);
   }
   
   state.remove (name2);
+  string xml2 = "<state>"
+    "<item><name>1</name><seq><session>0</session><seqno>10</seqno></seq></item>"
+    "<item><name>3</name><seq><session>0</session><seqno>8</seqno></seq></item>"
+    "</state>";
   {
   ostringstream os;
   os << state;
   string s = os.str ();
   erase_all (s, "\n");
-  BOOST_CHECK_EQUAL (s, "<state type=\"full\"><item><name>3</name><seq><session>0</session><seqno>8</seqno></seq></item><item><name>1</name><seq><session>0</session><seqno>10</seqno></seq></item></state>");
+  BOOST_CHECK_EQUAL (s, xml2);
+  }
+
+  FullState state2;
+  istringstream xml1_is (xml1);
+  BOOST_CHECK_NO_THROW (xml1_is >> state2);
+  {
+  ostringstream os;
+  os << state2;
+  string xml1_test = os.str ();
+  erase_all (xml1_test, "\n");
+  BOOST_CHECK_EQUAL (xml1_test, xml1);
+  }
+  
+  istringstream xml2_is ("<state><item action=\"remove\"><name>2</name></item></state>");
+  BOOST_CHECK_NO_THROW (xml2_is >> state2);
+  
+  {
+  ostringstream os;
+  os << state2;
+  string xml2_test = os.str ();
+  erase_all (xml2_test, "\n");
+  BOOST_CHECK_EQUAL (xml2_test, xml2);
   }
 }
 
@@ -177,22 +208,58 @@
   state.update (name2, SeqNo (12));
   state.update (name3, SeqNo (8));  
 
+  string xml1 = "<state>"
+    "<item action=\"update\"><name>1</name><seq><session>0</session><seqno>10</seqno></seq></item>"
+    "<item action=\"update\"><name>2</name><seq><session>0</session><seqno>12</seqno></seq></item>"
+    "<item action=\"update\"><name>3</name><seq><session>0</session><seqno>8</seqno></seq></item>"
+    "</state>";
   {
   ostringstream os;
   os << state;
-  string s = os.str ();
-  erase_all (s, "\n");
-  BOOST_CHECK_EQUAL (s, "<state type=\"diff\"><item action=\"update\"><name>3</name><seq><session>0</session><seqno>8</seqno></seq></item><item action=\"update\"><name>2</name><seq><session>0</session><seqno>12</seqno></seq></item><item action=\"update\"><name>1</name><seq><session>0</session><seqno>10</seqno></seq></item></state>");
+  string xml1_test = os.str ();
+  erase_all (xml1_test, "\n");
+  BOOST_CHECK_EQUAL (xml1_test, xml1);
   }
   
   state.remove (name2);
+  string xml2 = "<state>"
+    "<item action=\"update\"><name>1</name><seq><session>0</session><seqno>10</seqno></seq></item>"
+    "<item action=\"remove\"><name>2</name></item>"
+    "<item action=\"update\"><name>3</name><seq><session>0</session><seqno>8</seqno></seq></item>"
+    "</state>";
   {
   ostringstream os;
   os << state;
-  string s = os.str ();
-  erase_all (s, "\n");
-  BOOST_CHECK_EQUAL (s, "<state type=\"diff\"><item action=\"update\"><name>3</name><seq><session>0</session><seqno>8</seqno></seq></item><item action=\"remove\"><name>2</name></item><item action=\"update\"><name>1</name><seq><session>0</session><seqno>10</seqno></seq></item></state>");
+  string xml2_test = os.str ();
+  erase_all (xml2_test, "\n");
+  BOOST_CHECK_EQUAL (xml2_test, xml2);
   }
+
+  ////////////  ////////////  ////////////  ////////////  ////////////  ////////////
+  
+  DiffState state2;
+  istringstream xml1_is (xml1);
+  BOOST_CHECK_NO_THROW (xml1_is >> state2);
+  
+  {
+  ostringstream os;
+  os << state2;
+  string xml1_test = os.str ();
+  erase_all (xml1_test, "\n");
+  BOOST_CHECK_EQUAL (xml1_test, xml1);
+  }
+
+  istringstream xml2_is ("<state><item action=\"remove\"><name>2</name></item></state>");
+  BOOST_CHECK_NO_THROW (xml2_is >> state2);
+  
+  {
+  ostringstream os;
+  os << state2;
+  string xml2_test = os.str ();
+  erase_all (xml2_test, "\n");
+  BOOST_CHECK_EQUAL (xml2_test, xml2);
+  }
+
 }
 
 BOOST_AUTO_TEST_SUITE_END()