data: Implementing FinalBlockId in Data packet's MetaInfo section

Change-Id: I4768aa0d7465f498b220910269db5e2aa69bbe51
diff --git a/src/data.hpp b/src/data.hpp
index d6aba80..f1b64a3 100644
--- a/src/data.hpp
+++ b/src/data.hpp
@@ -92,6 +92,12 @@
   
   inline void 
   setFreshnessPeriod(Milliseconds freshnessPeriod);
+
+  inline const name::Component&
+  getFinalBlockId() const;
+
+  inline void
+  setFinalBlockId(const name::Component& finalBlockId);
   
   /**
    * @brief Get content Block
@@ -222,6 +228,19 @@
   metaInfo_.setFreshnessPeriod(freshnessPeriod);
 }
 
+inline const name::Component&
+Data::getFinalBlockId() const
+{
+  return metaInfo_.getFinalBlockId();
+}
+
+inline void
+Data::setFinalBlockId(const name::Component& finalBlockId)
+{
+  onChanged();
+  metaInfo_.setFinalBlockId(finalBlockId);
+}
+
 inline const Block& 
 Data::getContent() const
 {
diff --git a/src/encoding/block.hpp b/src/encoding/block.hpp
index 32523a5..2afd154 100644
--- a/src/encoding/block.hpp
+++ b/src/encoding/block.hpp
@@ -375,18 +375,12 @@
 inline Buffer::const_iterator
 Block::value_begin() const
 {
-  if (!hasValue())
-      throw Error("(Block::value_begin) Underlying value buffer is empty");
-
   return m_value_begin;
 }
 
 inline Buffer::const_iterator
 Block::value_end() const
 {
-  if (!hasValue())
-      throw Error("(Block::value_end) Underlying value buffer is empty");
-
   return m_value_end;
 }
 
diff --git a/src/encoding/tlv.hpp b/src/encoding/tlv.hpp
index 1ea0936..890ea84 100644
--- a/src/encoding/tlv.hpp
+++ b/src/encoding/tlv.hpp
@@ -49,6 +49,7 @@
   SignatureType = 22,
   KeyLocator    = 23,
   KeyLocatorDigest = 24,
+  FinalBlockId  = 25,
 
   AppPrivateBlock1 = 128,
   AppPrivateBlock2 = 32767
diff --git a/src/meta-info.hpp b/src/meta-info.hpp
index 1c78cc7..fc5458e 100644
--- a/src/meta-info.hpp
+++ b/src/meta-info.hpp
@@ -8,6 +8,8 @@
 #ifndef NDN_META_INFO_HPP
 #define NDN_META_INFO_HPP
 
+#include "encoding/encoding-buffer.hpp"
+
 namespace ndn {
 
 /**
@@ -22,91 +24,176 @@
   };
   
   MetaInfo()
-    : type_(TYPE_DEFAULT)
-    , freshnessPeriod_(-1)
+    : m_type(TYPE_DEFAULT)
+    , m_freshnessPeriod(-1)
   {   
   }
+
+  MetaInfo(const Block& block)
+  {
+    wireDecode(block);
+  }
   
   uint32_t 
   getType() const
-  { return type_; }
+  {
+    return m_type;
+  }
   
-  void 
+  MetaInfo&
   setType(uint32_t type)
-  { type_ = type; }
+  {
+    m_wire.reset();
+    m_type = type;
+    return *this;
+  }
   
   Milliseconds 
   getFreshnessPeriod() const
-  { return freshnessPeriod_; }
+  {
+    return m_freshnessPeriod;
+  }
   
-  void 
+  MetaInfo&
   setFreshnessPeriod(Milliseconds freshnessPeriod)
-  { freshnessPeriod_ = freshnessPeriod; }
+  {
+    m_wire.reset();
+    m_freshnessPeriod = freshnessPeriod;
+    return *this;
+  }
 
-  inline const Block& 
+  const name::Component&
+  getFinalBlockId() const
+  {
+    return m_finalBlockId;
+  }
+
+  MetaInfo&
+  setFinalBlockId(const name::Component& finalBlockId)
+  {
+    m_wire.reset();
+    m_finalBlockId = finalBlockId;
+    return *this;
+  }
+  
+  template<bool T>
+  size_t
+  wireEncode(EncodingImpl<T> &block) const;
+
+  const Block& 
   wireEncode() const;
   
-  inline void
+  void
   wireDecode(const Block &wire);  
   
 private:
-  uint32_t type_;
-  Milliseconds freshnessPeriod_;
+  uint32_t m_type;
+  Milliseconds m_freshnessPeriod;
+  name::Component m_finalBlockId;
 
-  mutable Block wire_;
+  mutable Block m_wire;
 };
 
+template<bool T>
+inline size_t
+MetaInfo::wireEncode(EncodingImpl<T>& blk) const
+{
+  // MetaInfo ::= META-INFO-TYPE TLV-LENGTH
+  //                ContentType?
+  //                FreshnessPeriod?
+  //                FinalBlockId?
+  
+  size_t total_len = 0;
+
+  // FinalBlockId
+  if (!m_finalBlockId.empty())
+    {
+      size_t var_len = m_finalBlockId.wireEncode (blk);
+      total_len += var_len;
+      total_len += blk.prependVarNumber (var_len);
+      total_len += blk.prependVarNumber (Tlv::FinalBlockId);
+    }
+  
+  // FreshnessPeriod
+  if (m_freshnessPeriod >= 0)
+    {
+      size_t var_len = blk.prependNonNegativeInteger (m_freshnessPeriod);
+      total_len += var_len;
+      total_len += blk.prependVarNumber (var_len);
+      total_len += blk.prependVarNumber (Tlv::FreshnessPeriod);
+    }
+
+  // ContentType
+  if (m_type != TYPE_DEFAULT)
+    {
+      size_t var_len = blk.prependNonNegativeInteger (m_type);
+      total_len += var_len;
+      total_len += blk.prependVarNumber (var_len);
+      total_len += blk.prependVarNumber (Tlv::ContentType);
+    }
+
+  total_len += blk.prependVarNumber (total_len);
+  total_len += blk.prependVarNumber (Tlv::MetaInfo);
+  return total_len;
+}
+
 inline const Block& 
 MetaInfo::wireEncode() const
 {
-  if (wire_.hasWire())
-    return wire_;
+  if (m_wire.hasWire ())
+    return m_wire;
 
-  // MetaInfo ::= META-INFO-TYPE TLV-LENGTH
-  //                ContentType?
-  //                FreshnessPeriod?
+  EncodingEstimator estimator;
+  size_t estimatedSize = wireEncode(estimator);
   
-  wire_ = Block(Tlv::MetaInfo);
+  EncodingBuffer buffer(estimatedSize, 0);
+  wireEncode(buffer);
 
-  // ContentType
-  if (type_ != TYPE_DEFAULT) {
-    wire_.push_back
-      (nonNegativeIntegerBlock(Tlv::ContentType, type_));
-  }
-
-  // FreshnessPeriod
-  if (freshnessPeriod_ >= 0) {
-    wire_.push_back
-      (nonNegativeIntegerBlock(Tlv::FreshnessPeriod, freshnessPeriod_));
-  }
-  
-  wire_.encode();
-  return wire_;  
+  m_wire = buffer.block();
+  return m_wire;
 }
   
 inline void
 MetaInfo::wireDecode(const Block &wire)
 {
-  wire_ = wire;
-  wire_.parse();
+  m_wire = wire;
+  m_wire.parse();
 
   // MetaInfo ::= META-INFO-TYPE TLV-LENGTH
   //                ContentType?
   //                FreshnessPeriod?
   
   // ContentType
-  Block::element_const_iterator val = wire_.find(Tlv::ContentType);
-  if (val != wire_.elements().end())
+  Block::element_const_iterator val = m_wire.find(Tlv::ContentType);
+  if (val != m_wire.elements().end())
     {
-      type_ = readNonNegativeInteger(*val);
+      m_type = readNonNegativeInteger(*val);
     }
+  else
+    m_type = TYPE_DEFAULT;
 
   // FreshnessPeriod
-  val = wire_.find(Tlv::FreshnessPeriod);
-  if (val != wire_.elements().end())
+  val = m_wire.find(Tlv::FreshnessPeriod);
+  if (val != m_wire.elements().end())
     {
-      freshnessPeriod_ = readNonNegativeInteger(*val);
+      m_freshnessPeriod = readNonNegativeInteger(*val);
     }
+  else
+    m_freshnessPeriod = -1;
+
+  // FinalBlockId
+  val = m_wire.find(Tlv::FinalBlockId);
+  if (val != m_wire.elements().end())
+    {
+      m_finalBlockId = val->blockFromValue();
+      if (m_finalBlockId.type() != Tlv::NameComponent)
+        {
+          /// @todo May or may not throw exception later...
+          m_finalBlockId.reset();
+        }
+    }
+  else
+    m_finalBlockId.reset();
 }
 
 inline std::ostream&
@@ -119,6 +206,11 @@
   if (info.getFreshnessPeriod() >= 0) {
     os << ", FreshnessPeriod: " << info.getFreshnessPeriod();
   }
+
+  if (!info.getFinalBlockId().empty()) {
+    os << ", FinalBlockId: ";
+    info.getFinalBlockId().toUri(os);
+  }
   return os;
 }