util: Add helper method to load/save object from/to file.

Change-Id: I7417bbf85865e15c02e5dec170265bcdd3f2bae4
diff --git a/src/util/io.hpp b/src/util/io.hpp
new file mode 100644
index 0000000..3d39feb
--- /dev/null
+++ b/src/util/io.hpp
@@ -0,0 +1,150 @@
+/**
+ * Copyright (C) 2013 Regents of the University of California.
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NDN_UTIL_IO_HPP
+#define NDN_UTIL_IO_HPP
+
+#include "../common.hpp"
+
+#include "../encoding/block.hpp"
+
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <cryptopp/files.h>
+#include <cryptopp/base64.h>
+#include <cryptopp/hex.h>
+
+
+namespace ndn {
+namespace io {
+
+struct Error : public std::runtime_error { Error(const std::string &what) : std::runtime_error(what) {} };
+
+enum IoEncoding {
+  NO_ENCODING,
+  BASE_64,
+  HEX
+};
+
+template<typename T> 
+shared_ptr<T> 
+load(std::istream& is, IoEncoding encoding = BASE_64)
+{
+  typedef typename T::Error TypeError;
+  try
+    {
+      using namespace CryptoPP;
+
+      shared_ptr<T> object = make_shared<T>();
+
+      OBufferStream os;
+      
+      switch(encoding)
+	{
+	case NO_ENCODING:
+	  {
+	    FileSource ss(is, true, new FileSink(os));
+	    break;
+	  }
+	case BASE_64:
+	  {
+	    FileSource ss(is, true, new Base64Decoder(new FileSink(os)));
+	    break;
+	  }
+	case HEX:
+	  {
+	    FileSource ss(is, true, new HexDecoder(new FileSink(os)));
+	    break;
+	  }
+	default:
+	  return shared_ptr<T>(); 
+	}
+
+      object->wireDecode(Block(os.buf()));
+      return object;
+    }
+  catch(CryptoPP::Exception& e)
+    {
+      return shared_ptr<T>();
+    }
+  catch(Block::Error& e)
+    {
+      return shared_ptr<T>();
+    }
+  catch(TypeError& e)
+    {
+      return shared_ptr<T>();
+    }
+}
+
+template<typename T> 
+shared_ptr<T> 
+load(const std::string& file, IoEncoding encoding = BASE_64)
+{
+  std::ifstream is(file.c_str());
+  return load<T>(is, encoding);
+}
+
+template<typename T> 
+void
+save(const T& object, std::ostream& os, IoEncoding encoding = BASE_64)
+{
+  typedef typename T::Error TypeError;
+  try
+    {
+      using namespace CryptoPP;
+
+      Block block = object.wireEncode();
+      
+      switch(encoding)
+	{
+	case NO_ENCODING:
+	  {
+	    StringSource ss(block.wire(), block.size(), true, new FileSink(os));
+	    break;
+	  }
+	case BASE_64:
+	  {
+	    StringSource ss(block.wire(), block.size(), true, new Base64Encoder(new FileSink(os), true, 64));
+	    break;
+	  }
+	case HEX:
+	  {
+	    StringSource ss(block.wire(), block.size(), true, new HexEncoder(new FileSink(os)));
+	    break;
+	  }
+	default:
+	  return; 
+	}
+      return;
+    }
+  catch(CryptoPP::Exception& e)
+    {
+      throw Error(e.what());
+    }
+  catch(Block::Error& e)
+    {
+      throw Error(e.what());
+    }
+  catch(TypeError& e)
+    {
+      throw Error(e.what());
+    }
+}
+
+template<typename T>
+void
+save(const T& object, const std::string& file, IoEncoding encoding = BASE_64)
+{
+  std::ofstream os(file.c_str());
+  save(object, os, encoding);
+}
+
+} // namespace io
+} // namespace ndn
+
+#endif // NDN_UTIL_IO_HPP
+
diff --git a/tests/util/test-io.cpp b/tests/util/test-io.cpp
new file mode 100644
index 0000000..acbdc38
--- /dev/null
+++ b/tests/util/test-io.cpp
@@ -0,0 +1,36 @@
+/**
+ * Copyright (C) 2013 Regents of the University of California.
+ * See COPYING for copyright and distribution information.
+ */
+
+#include <boost/test/unit_test.hpp>
+
+#include "util/io.hpp"
+#include "security/key-chain.hpp"
+
+namespace ndn {
+
+BOOST_AUTO_TEST_SUITE(TestIO)
+
+BOOST_AUTO_TEST_CASE (Basic)
+{
+  KeyChainImpl<SecPublicInfoSqlite3, SecTpmFile> keychain;
+
+  Name identity("/TestIO/Basic/" + boost::lexical_cast<std::string>(time::now()));
+  Name certName;
+  BOOST_REQUIRE_NO_THROW(certName = keychain.createIdentity(identity));
+  shared_ptr<IdentityCertificate> idCert;
+  BOOST_REQUIRE_NO_THROW(idCert = keychain.getCertificate(certName));
+
+  std::string file("/tmp/TestIO-Basic");
+  io::save(*idCert, file);
+  shared_ptr<IdentityCertificate> readCert = io::load<IdentityCertificate>(file);
+
+  BOOST_CHECK(static_cast<bool>(readCert));
+  BOOST_CHECK(idCert->getName() == readCert->getName());
+  keychain.deleteIdentity(identity);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace ndn