encoding: Construct Block from istream

Change-Id: Iee330e861197e9c347fd7c15a887c2b9fc5552be
diff --git a/include/ndn-cpp-dev/encoding/block.hpp b/include/ndn-cpp-dev/encoding/block.hpp
index 85cdaf5..de8c5a5 100644
--- a/include/ndn-cpp-dev/encoding/block.hpp
+++ b/include/ndn-cpp-dev/encoding/block.hpp
@@ -50,6 +50,11 @@
   Block(const uint8_t *buffer, size_t maxlength);
 
   Block(const void *buffer, size_t maxlength);
+
+  /*
+   * @brief A helper version of a constructor to create Block from the stream. 
+   */
+  Block(std::istream& is);
   
   /**
    * @brief Create Block from the wire buffer (no parsing)
diff --git a/include/ndn-cpp-dev/encoding/tlv.hpp b/include/ndn-cpp-dev/encoding/tlv.hpp
index dfa11fe..3d42402 100644
--- a/include/ndn-cpp-dev/encoding/tlv.hpp
+++ b/include/ndn-cpp-dev/encoding/tlv.hpp
@@ -11,6 +11,7 @@
 #define NDN_TLV_HPP
 
 #include <stdexcept>
+#include <iterator>
 #include "buffer.hpp"
 #include "endian.h"
 
@@ -176,6 +177,73 @@
     }
 }
 
+template<>
+inline uint64_t
+readVarNumber<std::istream_iterator<uint8_t> >(std::istream_iterator<uint8_t> &begin, 
+                                               const std::istream_iterator<uint8_t> &end)
+{
+  if (begin == end)
+    throw Error("Empty buffer during TLV processing");
+  
+  uint8_t value = *begin;
+  ++begin;
+  if (value < 253)
+    {
+      return value;
+    }
+  else if (value == 253)
+    {
+      uint8_t buffer[2];
+      int count = 0;
+      
+      while(begin != end && count < 2){
+        buffer[count] = *begin;
+        begin++;
+        count++;
+      }
+
+      if (count < 2)
+        throw Error("Insufficient data during TLV processing");
+      
+      uint16_t value = *reinterpret_cast<const uint16_t*>(buffer); 
+      return be16toh(value);
+    }
+  else if (value == 254)
+    {
+      uint8_t buffer[4];
+      int count = 0;
+      
+      while(begin != end && count < 4){
+        buffer[count] = *begin;
+        begin++;
+        count++;
+      }
+
+      if (count < 4)
+        throw Error("Insufficient data during TLV processing");
+      
+      uint32_t value = *reinterpret_cast<const uint32_t*>(buffer);
+      return be32toh(value);
+    }
+  else // if (value == 255)
+    {
+      uint8_t buffer[8];
+      int count = 0;
+      
+      while(begin != end && count < 8){
+        buffer[count] = *begin;
+        begin++;
+        count++;
+      }
+
+      if (count < 8)
+        throw Error("Insufficient data during TLV processing");
+      
+      uint64_t value = *reinterpret_cast<const uint64_t*>(buffer);
+      return be64toh(value);
+    }
+}
+
 template<class InputIterator>
 inline uint32_t
 readType(InputIterator &begin, const InputIterator &end)
@@ -278,6 +346,77 @@
   throw Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)");
 }
 
+template<>
+inline uint64_t
+readNonNegativeInteger<std::istream_iterator<uint8_t> >(size_t size, 
+                                                        std::istream_iterator<uint8_t> &begin, 
+                                                        const std::istream_iterator<uint8_t> &end)
+{
+  switch (size) {
+  case 1:
+    {
+      if(begin == end)
+        throw Error("Insufficient data during TLV processing");
+      
+      uint8_t value = *begin;
+      begin++;
+      return value;
+    }
+  case 2:
+    {
+      uint8_t buffer[2];
+      int count = 0;
+      
+      while(begin != end && count < 2){
+        buffer[count] = *begin;
+        begin++;
+        count++;
+      }
+      
+      if (count < 2)
+        throw Error("Insufficient data during TLV processing");
+      
+      uint16_t value = *reinterpret_cast<const uint16_t*>(buffer);
+      return be16toh(value);
+    }
+  case 4:
+    {
+      uint8_t buffer[4];
+      int count = 0;
+      
+      while(begin != end && count < 4){
+        buffer[count] = *begin;
+        begin++;
+        count++;
+      }
+
+      if (count < 4)
+        throw Error("Insufficient data during TLV processing");
+      
+      uint32_t value = *reinterpret_cast<const uint32_t*>(buffer);
+      return be32toh(value);
+    }
+  case 8:
+    {
+      uint8_t buffer[8];
+      int count = 0;
+      
+      while(begin != end && count < 8){
+        buffer[count] = *begin;
+        begin++;
+        count++;
+      }
+
+      if (count < 8)
+        throw Error("Insufficient data during TLV processing");
+      
+      uint64_t value = *reinterpret_cast<const uint64_t*>(buffer);
+      return be64toh(value);
+    }
+  }
+  throw Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)");
+}
+
 inline size_t
 sizeOfNonNegativeInteger(uint64_t varNumber)
 {
diff --git a/src/encoding/block.cpp b/src/encoding/block.cpp
index 7fab48f..4b41ebc 100644
--- a/src/encoding/block.cpp
+++ b/src/encoding/block.cpp
@@ -49,6 +49,44 @@
     }
 }
 
+Block::Block(std::istream& is)
+{
+  std::istream_iterator<uint8_t> tmp_begin(is);  
+  std::istream_iterator<uint8_t> tmp_end;
+  
+  m_type = Tlv::readType(tmp_begin, tmp_end);
+  uint64_t length = Tlv::readVarNumber(tmp_begin, tmp_end);
+
+  // We may still have some problem here, if some exception happens in this constructor, we may completely lose all the bytes extracted from the stream.
+
+  OBufferStream os;
+  size_t headerLength = Tlv::writeVarNumber(os, m_type);
+  headerLength += Tlv::writeVarNumber(os, length);
+  
+  char* buf = new char[length];
+  buf[0] = *tmp_begin;
+  is.read(buf+1, length-1);
+
+  if(length-1 != is.gcount())
+    {
+      delete [] buf;
+      throw Tlv::Error("Not enough data in the buffer to fully parse TLV");
+    } 
+
+  os.write(buf, length);
+  delete [] buf;
+
+  m_buffer = os.buf();
+
+  m_begin = m_buffer->begin();
+  m_end = m_buffer->end();
+  m_size = m_end - m_begin;
+
+  m_value_begin = m_buffer->begin() + headerLength;
+  m_value_end   = m_buffer->end();
+}
+
+
 Block::Block(const uint8_t *buffer, size_t maxlength)
 {
   const uint8_t * tmp_begin = buffer;
diff --git a/tests_boost/Makefile.am b/tests_boost/Makefile.am
index dadf1c1..3564e82 100644
--- a/tests_boost/Makefile.am
+++ b/tests_boost/Makefile.am
@@ -7,6 +7,7 @@
   test-encode-decode-certificate.cpp \
   test-encode-decode-data.cpp \
   test-encode-decode-interest.cpp \
-  test-encode-decode-forwarding-entry.cpp
+  test-encode-decode-forwarding-entry.cpp \
+  test-encode-decode-block.cpp
 
 unit_tests_LDADD = ../libndn-cpp-dev.la @BOOST_SYSTEM_LIB@ @BOOST_UNIT_TEST_FRAMEWORK_LIB@ @OPENSSL_LIBS@ @CRYPTOPP_LIBS@ @OSX_SECURITY_LIBS@
diff --git a/tests_boost/test-encode-decode-block.cpp b/tests_boost/test-encode-decode-block.cpp
new file mode 100644
index 0000000..f14b83a
--- /dev/null
+++ b/tests_boost/test-encode-decode-block.cpp
@@ -0,0 +1,66 @@
+/**
+ * Copyright (C) 2013 Regents of the University of California.
+ * @author: Jeff Thompson <jefft0@remap.ucla.edu>
+ * See COPYING for copyright and distribution information.
+ */
+
+#include <boost/test/unit_test.hpp>
+
+#include <ndn-cpp-dev/interest.hpp>
+
+using namespace std;
+using namespace ndn;
+
+BOOST_AUTO_TEST_SUITE(TestBlock)
+
+const uint8_t Interest1[] = {
+  0x1,  0x41, // NDN Interest
+      0x3,  0x14, // Name
+          0x4,  0x5, // NameComponent
+              0x6c,  0x6f,  0x63,  0x61,  0x6c,
+          0x4,  0x3, // NameComponent
+              0x6e,  0x64,  0x6e,
+          0x4,  0x6, // NameComponent
+              0x70,  0x72,  0x65,  0x66,  0x69,  0x78,
+      0x5,  0x1f, // Selectors
+          0x09,  0x1,  0x1,  // MinSuffix
+          0x0a,  0x1,  0x1,  // MaxSuffix
+          0x0c,  0x14, // Exclude
+              0x4,  0x4, // NameComponent
+                  0x61,  0x6c,  0x65,  0x78,
+              0x4,  0x4, // NameComponent
+                  0x78,  0x78,  0x78,  0x78,
+              0xf,  0x0, // Any
+              0x4,  0x4, // NameComponent
+                  0x79,  0x79,  0x79,  0x79,
+          0x0d,  0x1, // ChildSelector
+              0x1,
+      0x6,  0x1, // Nonce
+          0x1,
+      0x7,  0x1, // Scope
+          0x1,
+      0x8,       // InterestLifetime
+          0x2,  0x3,  0xe8
+};
+
+BOOST_AUTO_TEST_CASE (Decode)
+{
+  boost::iostreams::stream<boost::iostreams::array_source> is (reinterpret_cast<const char *>(Interest1), sizeof(Interest1));
+  
+  Block interestBlock(is);
+
+  ndn::Interest i;
+  BOOST_REQUIRE_NO_THROW(i.wireDecode(interestBlock));
+
+  BOOST_REQUIRE_EQUAL(i.getName().toUri(), "/local/ndn/prefix");
+  BOOST_REQUIRE_EQUAL(i.getScope(), 1);
+  BOOST_REQUIRE_EQUAL(i.getInterestLifetime(), 1000);
+  BOOST_REQUIRE_EQUAL(i.getMinSuffixComponents(), 1);
+  BOOST_REQUIRE_EQUAL(i.getMaxSuffixComponents(), 1);
+  BOOST_REQUIRE_EQUAL(i.getChildSelector(), 1);
+  BOOST_REQUIRE_EQUAL(i.getMustBeFresh(), false);
+  BOOST_REQUIRE_EQUAL(i.getExclude().toUri(), "alex,xxxx,*,yyyy");
+  BOOST_REQUIRE_EQUAL(i.getNonce(), 1);
+}
+
+BOOST_AUTO_TEST_SUITE_END()