decoding+transport: Exception-safe Block parsing

Change-Id: I3e83b6ca4c8ca42b8bb1ddc8dc50c52ee366c55c
Refs: #1291
diff --git a/src/encoding/tlv.hpp b/src/encoding/tlv.hpp
index 8a2b3fc..2ef008c 100644
--- a/src/encoding/tlv.hpp
+++ b/src/encoding/tlv.hpp
@@ -69,7 +69,39 @@
 /**
  * @brief Read VAR-NUMBER in NDN-TLV encoding
  *
- * This call will throw ndn::Tlv::Error (aka std::runtime_error) if number cannot be read
+ * @param [in]  begin  Begin (pointer or iterator) of the buffer
+ * @param [in]  end    End (pointer or iterator) of the buffer
+ * @param [out] number Read number
+ *
+ * @throws This call never throws exception
+ *
+ * @return true if number successfully read from input, false otherwise
+ */
+template<class InputIterator>
+inline bool
+readVarNumber(InputIterator &begin, const InputIterator &end, uint64_t& number);
+
+/**
+ * @brief Read TLV Type
+ *
+ * @param [in]  begin  Begin (pointer or iterator) of the buffer
+ * @param [in]  end    End (pointer or iterator) of the buffer
+ * @param [out] number Read type number
+ *
+ * @throws This call never throws exception
+ *
+ * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
+ * is larger than 2^32-1 (type in this library is implemented as uint32_t)
+ */
+template<class InputIterator>
+inline bool
+readType(InputIterator &begin, const InputIterator &end, uint32_t& type);
+
+
+/**
+ * @brief Read VAR-NUMBER in NDN-TLV encoding
+ *
+ * @throws This call will throw ndn::Tlv::Error (aka std::runtime_error) if number cannot be read
  *
  * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
  */
@@ -80,6 +112,8 @@
 /**
  * @brief Read TLV Type
  *
+ * @throws This call will throw ndn::Tlv::Error (aka std::runtime_error) if number cannot be read
+ *
  * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
  * is larger than 2^32-1 (type in this library is implemented as uint32_t)
  */
@@ -136,12 +170,72 @@
 /////////////////////////////////////////////////////////////////////////////////
 
 template<class InputIterator>
+inline bool
+readVarNumber(InputIterator &begin, const InputIterator &end, uint64_t& number)
+{
+  if (begin == end)
+    return false;
+
+  uint8_t value = *begin;
+  ++begin;
+  if (value < 253)
+    {
+      number = value;
+    }
+  else if (value == 253)
+    {
+      if (end - begin < 2)
+        return false;
+
+      uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin); // kind of dangerous... but should be efficient
+      begin += 2;
+      number = be16toh(value);
+    }
+  else if (value == 254)
+    {
+      if (end - begin < 4)
+        return false;
+
+      uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin); // kind of dangerous... but should be efficient
+      begin += 4;
+      number = be32toh(value);
+    }
+  else // if (value == 255)
+    {
+      if (end - begin < 8)
+        return false;
+
+      uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
+      begin += 8;
+
+      number = be64toh(value);
+    }
+
+  return true;
+}
+
+template<class InputIterator>
+inline bool
+readType(InputIterator &begin, const InputIterator &end, uint32_t& type)
+{
+  uint64_t number;
+  bool ok = readVarNumber(begin, end, number);
+  if (number > std::numeric_limits<uint32_t>::max())
+    {
+      return false;
+    }
+
+  type = static_cast<uint64_t> (number);
+  return true;
+}
+
+template<class InputIterator>
 inline uint64_t
 readVarNumber(InputIterator &begin, const InputIterator &end)
 {
   if (begin == end)
     throw Error("Empty buffer during TLV processing");
-  
+
   uint8_t value = *begin;
   ++begin;
   if (value < 253)
@@ -152,7 +246,7 @@
     {
       if (end - begin < 2)
         throw Error("Insufficient data during TLV processing");
-      
+
       uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin); // kind of dangerous... but should be efficient
       begin += 2;
       return be16toh(value);
@@ -161,7 +255,7 @@
     {
       if (end - begin < 4)
         throw Error("Insufficient data during TLV processing");
-      
+
       uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin); // kind of dangerous... but should be efficient
       begin += 4;
       return be32toh(value);
@@ -170,7 +264,7 @@
     {
       if (end - begin < 8)
         throw Error("Insufficient data during TLV processing");
-      
+
       uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
       begin += 8;
 
@@ -180,12 +274,12 @@
 
 template<>
 inline uint64_t
-readVarNumber<std::istream_iterator<uint8_t> >(std::istream_iterator<uint8_t> &begin, 
+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)
@@ -196,7 +290,7 @@
     {
       uint8_t buffer[2];
       int count = 0;
-      
+
       while(begin != end && count < 2){
         buffer[count] = *begin;
         begin++;
@@ -205,15 +299,15 @@
 
       if (count < 2)
         throw Error("Insufficient data during TLV processing");
-      
-      uint16_t value = *reinterpret_cast<const uint16_t*>(buffer); 
+
+      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++;
@@ -222,7 +316,7 @@
 
       if (count < 4)
         throw Error("Insufficient data during TLV processing");
-      
+
       uint32_t value = *reinterpret_cast<const uint32_t*>(buffer);
       return be32toh(value);
     }
@@ -230,7 +324,7 @@
     {
       uint8_t buffer[8];
       int count = 0;
-      
+
       while(begin != end && count < 8){
         buffer[count] = *begin;
         begin++;
@@ -239,7 +333,7 @@
 
       if (count < 8)
         throw Error("Insufficient data during TLV processing");
-      
+
       uint64_t value = *reinterpret_cast<const uint64_t*>(buffer);
       return be64toh(value);
     }
@@ -311,7 +405,7 @@
     {
       if (end - begin < 1)
         throw Error("Insufficient data during TLV processing");
-      
+
       uint8_t value = *begin;
       begin++;
       return value;
@@ -320,7 +414,7 @@
     {
       if (end - begin < 2)
         throw Error("Insufficient data during TLV processing");
-      
+
       uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin); // kind of dangerous... but should be efficient
       begin += 2;
       return be16toh(value);
@@ -329,7 +423,7 @@
     {
       if (end - begin < 4)
         throw Error("Insufficient data during TLV processing");
-      
+
       uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin); // kind of dangerous... but should be efficient
       begin += 4;
       return be32toh(value);
@@ -338,7 +432,7 @@
     {
       if (end - begin < 8)
         throw Error("Insufficient data during TLV processing");
-      
+
       uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
       begin += 8;
       return be64toh(value);
@@ -349,8 +443,8 @@
 
 template<>
 inline uint64_t
-readNonNegativeInteger<std::istream_iterator<uint8_t> >(size_t size, 
-                                                        std::istream_iterator<uint8_t> &begin, 
+readNonNegativeInteger<std::istream_iterator<uint8_t> >(size_t size,
+                                                        std::istream_iterator<uint8_t> &begin,
                                                         const std::istream_iterator<uint8_t> &end)
 {
   switch (size) {
@@ -358,7 +452,7 @@
     {
       if(begin == end)
         throw Error("Insufficient data during TLV processing");
-      
+
       uint8_t value = *begin;
       begin++;
       return value;
@@ -367,16 +461,16 @@
     {
       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);
     }
@@ -384,7 +478,7 @@
     {
       uint8_t buffer[4];
       int count = 0;
-      
+
       while(begin != end && count < 4){
         buffer[count] = *begin;
         begin++;
@@ -393,7 +487,7 @@
 
       if (count < 4)
         throw Error("Insufficient data during TLV processing");
-      
+
       uint32_t value = *reinterpret_cast<const uint32_t*>(buffer);
       return be32toh(value);
     }
@@ -401,7 +495,7 @@
     {
       uint8_t buffer[8];
       int count = 0;
-      
+
       while(begin != end && count < 8){
         buffer[count] = *begin;
         begin++;
@@ -410,7 +504,7 @@
 
       if (count < 8)
         throw Error("Insufficient data during TLV processing");
-      
+
       uint64_t value = *reinterpret_cast<const uint64_t*>(buffer);
       return be64toh(value);
     }