add GZip support for protobuf
use GZip in serializing SyncStateMsg

use BytesPtr

Change-Id: I37dc41bda4a811b10308bc42e42f320cad986dba
diff --git a/ccnx/ccnx-common.h b/ccnx/ccnx-common.h
index 6d17116..d1b169d 100644
--- a/ccnx/ccnx-common.h
+++ b/ccnx/ccnx-common.h
@@ -39,6 +39,13 @@
 #include <map>
 #include <utility>
 #include <string.h>
+#include <boost/iostreams/filter/gzip.hpp>
+#include <boost/iostreams/filtering_stream.hpp>
+#include <boost/iostreams/device/back_inserter.hpp>
+#include <boost/range/iterator_range.hpp>
+#include <boost/make_shared.hpp>
+
+namespace io = boost::iostreams;
 
 namespace Ccnx {
 typedef std::vector<unsigned char> Bytes;
@@ -86,7 +93,7 @@
 }
 
 template<class Msg>
-inline BytesPtr
+BytesPtr
 serializeMsg(const Msg &msg)
 {
   int size = msg.ByteSize ();
@@ -96,7 +103,7 @@
 }
 
 template<class Msg>
-inline boost::shared_ptr<Msg>
+boost::shared_ptr<Msg>
 deserializeMsg (const Bytes &bytes)
 {
   boost::shared_ptr<Msg> retval (new Msg ());
@@ -104,6 +111,40 @@
   return retval;
 }
 
+template<class Msg>
+BytesPtr
+serializeGZipMsg(const Msg &msg)
+{
+  std::vector<char> bytes;   // Bytes couldn't work
+  {
+    boost::iostreams::filtering_ostream out;
+    out.push(boost::iostreams::gzip_compressor()); // gzip filter
+    out.push(boost::iostreams::back_inserter(bytes)); // back_inserter sink
+
+    msg.SerializeToOstream(&out);
+  }
+  BytesPtr uBytes = boost::make_shared<Bytes>(bytes.size());
+  memcpy(&(*uBytes)[0], &bytes[0], bytes.size());
+  return uBytes;
+}
+
+template<class Msg>
+boost::shared_ptr<Msg>
+deserializeGZipMsg(const Bytes &bytes)
+{
+  std::vector<char> sBytes(bytes.size());
+  memcpy(&sBytes[0], &bytes[0], bytes.size());
+  boost::iostreams::filtering_istream in;
+  in.push(boost::iostreams::gzip_decompressor()); // gzip filter
+  in.push(boost::make_iterator_range(sBytes)); // source
+
+  boost::shared_ptr<Msg> retval = boost::make_shared<Msg>();
+  retval->ParseFromIstream(&in);
+
+  return retval;
+}
+
+
 // --- Bytes operations end ---
 
 // Exceptions
diff --git a/src/sync-core.cc b/src/sync-core.cc
index 5a195f6..4aaf1a5 100644
--- a/src/sync-core.cc
+++ b/src/sync-core.cc
@@ -94,7 +94,7 @@
 
   // reply sync Interest with oldHash as last component
   Name syncName = Name (m_syncPrefix)(oldHash->GetHash(), oldHash->GetHashBytes());
-  BytesPtr syncData = serializeMsg (*msg);
+  BytesPtr syncData = serializeGZipMsg (*msg);
 
   m_ccnx->publishData(syncName, *syncData, FRESHNESS);
   _LOG_DEBUG ("[" << m_log->GetLocalName () << "] localStateChanged ");
@@ -141,7 +141,7 @@
     // we know the hash, should reply everything
     SyncStateMsgPtr msg = m_log->FindStateDifferences(*(Hash::Origin), *m_rootHash);
 
-    BytesPtr syncData = serializeMsg (*msg);
+    BytesPtr syncData = serializeGZipMsg (*msg);
     m_ccnx->publishData(name, *syncData, FRESHNESS);
     _LOG_TRACE ("[" << m_log->GetLocalName () << "] publishes " << hash.shortHash ());
     // _LOG_TRACE (msg);
@@ -171,7 +171,7 @@
     _LOG_TRACE ("found hash in sync log");
     SyncStateMsgPtr msg = m_log->FindStateDifferences(*hash, *m_rootHash);
 
-    BytesPtr syncData = serializeMsg (*msg);
+    BytesPtr syncData = serializeGZipMsg (*msg);
     m_ccnx->publishData(name, *syncData, FRESHNESS);
     _LOG_TRACE (m_log->GetLocalName () << " publishes: " << hash->shortHash ());
     _LOG_TRACE (msg);
@@ -252,9 +252,8 @@
 void
 SyncCore::handleStateData(const Bytes &content)
 {
-  SyncStateMsgPtr msg(new SyncStateMsg);
-  bool success = msg->ParseFromArray(head(content), content.size());
-  if(!success)
+  SyncStateMsgPtr msg = deserializeGZipMsg<SyncStateMsg>(content);
+  if(!(msg))
   {
     // ignore misformed SyncData
     _LOG_ERROR ("Misformed SyncData");
diff --git a/test/test-protobuf.cc b/test/test-protobuf.cc
new file mode 100644
index 0000000..fdf211b
--- /dev/null
+++ b/test/test-protobuf.cc
@@ -0,0 +1,47 @@
+#include "ccnx-common.h"
+#include "sync-core.h"
+#include <boost/make_shared.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/iostreams/filter/gzip.hpp>
+#include <boost/iostreams/filtering_stream.hpp>
+#include <boost/iostreams/device/back_inserter.hpp>
+#include <boost/range/iterator_range.hpp>
+#include <boost/make_shared.hpp>
+
+using namespace Ccnx;
+using namespace std;
+using namespace boost;
+
+BOOST_AUTO_TEST_SUITE(ProtobufTests)
+
+
+BOOST_AUTO_TEST_CASE (TestGzipProtobuf)
+{
+  SyncStateMsgPtr msg = make_shared<SyncStateMsg>();
+
+  SyncState *state = msg->add_state();
+  state->set_type(SyncState::UPDATE);
+  state->set_seq(100);
+  char x[100] = {'a'};
+  state->set_locator(&x[0], sizeof(x));
+  state->set_name(&x[0], sizeof(x));
+
+  BytesPtr bb = serializeMsg<SyncStateMsg>(*msg);
+
+  BytesPtr cb = serializeGZipMsg<SyncStateMsg>(*msg);
+  BOOST_CHECK(cb->size() < bb->size());
+  cout << cb->size() <<", " << bb->size() << endl;
+
+  SyncStateMsgPtr msg1 = deserializeGZipMsg<SyncStateMsg>(*cb);
+
+  BOOST_REQUIRE(msg1->state_size() == 1);
+
+  SyncState state1 = msg1->state(0);
+  BOOST_CHECK_EQUAL(state->seq(), state1.seq());
+  BOOST_CHECK_EQUAL(state->type(), state1.type());
+  string sx(x, 100);
+  BOOST_CHECK_EQUAL(sx, state1.name());
+  BOOST_CHECK_EQUAL(sx, state1.locator());
+}
+
+BOOST_AUTO_TEST_SUITE_END()