encoding: Optimized Data packet encoding, preparation for memory-efficient signing operation

Change-Id: I6eb1f8acef917970790d1f228ade6212c45181fa
refs: #1172
diff --git a/src/data.hpp b/src/data.hpp
index f1b64a3..4c09811 100644
--- a/src/data.hpp
+++ b/src/data.hpp
@@ -37,25 +37,32 @@
   Data(const Name& name);
   
   /**
-   * @brief The virtual destructor.
+   * @brief The destructor
    */
-  inline virtual
+  inline
   ~Data();
   
   /**
-   * @brief Encode this Data for a wire format.
-   * @return The encoded byte array.
+   * @brief Fast encoding or block size estimation
    */
-  const Block& 
-  wireEncode() const;
+  template<bool T>
+  inline size_t
+  wireEncode(EncodingImpl<T> &block, bool unsignedPortion = false) const;
   
   /**
-   * @brief Decode the input using a particular wire format and update this Data. 
-   * @param input The input byte array to be decoded.
+   * @brief Encode to a wire format
    */
-  void
+  inline const Block&
+  wireEncode() const;
+
+  /**
+   * @brief Decode from the wire format
+   */
+  inline void 
   wireDecode(const Block &wire);
 
+  ////////////////////////////////////////////////////////////////////  
+  
   inline const Name& 
   getName() const;
   
@@ -68,6 +75,8 @@
   inline void
   setName(const Name& name);
 
+  //
+  
   inline const MetaInfo& 
   getMetaInfo() const;
   
@@ -79,13 +88,20 @@
   inline void
   setMetaInfo(const MetaInfo& metaInfo);
 
+  //
+  
+  ///////////////////////////////////////////////////////////////
+  ///////////////////////////////////////////////////////////////
   ///////////////////////////////////////////////////////////////
   // MetaInfo proxy methods
+
   inline uint32_t 
   getContentType() const;
   
   inline void 
   setContentType(uint32_t type);
+
+  //
   
   inline Milliseconds 
   getFreshnessPeriod() const;
@@ -93,11 +109,18 @@
   inline void 
   setFreshnessPeriod(Milliseconds freshnessPeriod);
 
+  //
+
   inline const name::Component&
   getFinalBlockId() const;
 
   inline void
   setFinalBlockId(const name::Component& finalBlockId);
+
+  //
+  ///////////////////////////////////////////////////////////////
+  ///////////////////////////////////////////////////////////////
+  ///////////////////////////////////////////////////////////////
   
   /**
    * @brief Get content Block
@@ -121,6 +144,8 @@
 
   inline void
   setContent(const ConstBufferPtr &contentValue);
+
+  //
   
   inline const Signature&
   getSignature() const;
@@ -131,10 +156,12 @@
    */
   inline void
   setSignature(const Signature& signature);
-
+  
   inline void
   setSignatureValue(const Block &value);
 
+  ///////////////////////////////////////////////////////////////
+  
   inline uint64_t
   getIncomingFaceId() const;
 
@@ -149,25 +176,25 @@
   onChanged();
 
 private:
-  Name name_;
-  MetaInfo metaInfo_;
-  mutable Block content_;
-  Signature signature_;
+  Name m_name;
+  MetaInfo m_metaInfo;
+  mutable Block m_content;
+  Signature m_signature;
 
-  mutable Block wire_;
+  mutable Block m_wire;
 
   uint64_t m_incomingFaceId;
 };
 
 inline
 Data::Data()
-  : content_(Tlv::Content) // empty content
+  : m_content(Tlv::Content) // empty content
 {
 }
 
 inline
 Data::Data(const Name& name)
-  : name_(name)
+  : m_name(name)
 {
 }
 
@@ -176,80 +203,179 @@
 {
 }
 
+template<bool T>
+inline size_t
+Data::wireEncode(EncodingImpl<T> &block, bool unsignedPortion/* = false*/) const
+{
+  size_t total_len = 0;
+
+  // Data ::= DATA-TLV TLV-LENGTH
+  //            Name
+  //            MetaInfo
+  //            Content
+  //            Signature
+
+  // (reverse encoding)
+
+  if (!unsignedPortion && !m_signature)
+    {
+      throw Error("Requested wire format, but data packet has not been signed yet");
+    }
+
+  if (!unsignedPortion)
+    {
+      // SignatureValue
+      total_len += prependBlock(block, m_signature.getValue());
+    }
+
+  // SignatureInfo
+  total_len += prependBlock(block, m_signature.getInfo());
+  
+  // Content
+  total_len += prependBlock(block, getContent());
+  
+  // MetaInfo
+  total_len += getMetaInfo().wireEncode(block);
+
+  // Name
+  total_len += getName().wireEncode(block);
+
+  if (!unsignedPortion)
+    {
+      total_len += block.prependVarNumber (total_len);
+      total_len += block.prependVarNumber (Tlv::Data);
+    }
+  return total_len;
+}
+
+inline const Block &
+Data::wireEncode() const
+{
+  if (m_wire.hasWire())
+    return m_wire;
+
+  EncodingEstimator estimator;
+  size_t estimatedSize = wireEncode(estimator);
+  
+  EncodingBuffer buffer(estimatedSize, 0);
+  wireEncode(buffer);
+
+  const_cast<Data*>(this)->wireDecode(buffer.block());
+  return m_wire;
+}
+  
+/**
+ * Decode the input using a particular wire format and update this Data. 
+ * @param input The input byte array to be decoded.
+ */
+void
+Data::wireDecode(const Block &wire)
+{
+  m_wire = wire;
+  m_wire.parse();
+
+  // Data ::= DATA-TLV TLV-LENGTH
+  //            Name
+  //            MetaInfo
+  //            Content
+  //            Signature
+    
+  // Name
+  m_name.wireDecode(m_wire.get(Tlv::Name));
+
+  // MetaInfo
+  m_metaInfo.wireDecode(m_wire.get(Tlv::MetaInfo));
+
+  // Content
+  m_content = m_wire.get(Tlv::Content);
+
+  ///////////////
+  // Signature //
+  ///////////////
+  
+  // SignatureInfo
+  m_signature.setInfo(m_wire.get(Tlv::SignatureInfo));
+  
+  // SignatureValue
+  Block::element_const_iterator val = m_wire.find(Tlv::SignatureValue);
+  if (val != m_wire.elements_end())
+    m_signature.setValue(*val);
+}
+
 inline const Name& 
 Data::getName() const
 {
-  return name_;
+  return m_name;
 }
   
 inline void
 Data::setName(const Name& name)
 { 
   onChanged();
-  name_ = name; 
+  m_name = name; 
 }
   
 inline const MetaInfo& 
 Data::getMetaInfo() const
 {
-  return metaInfo_;
+  return m_metaInfo;
 }
   
 inline void
 Data::setMetaInfo(const MetaInfo& metaInfo) 
 { 
   onChanged();
-  metaInfo_ = metaInfo; 
+  m_metaInfo = metaInfo; 
 }
 
 inline uint32_t 
 Data::getContentType() const
 {
-  return metaInfo_.getType();
+  return m_metaInfo.getType();
 }
   
 inline void 
 Data::setContentType(uint32_t type)
 {
   onChanged();
-  metaInfo_.setType(type);
+  m_metaInfo.setType(type);
 }
   
 inline Milliseconds 
 Data::getFreshnessPeriod() const
 {
-  return metaInfo_.getFreshnessPeriod();
+  return m_metaInfo.getFreshnessPeriod();
 }
   
 inline void 
 Data::setFreshnessPeriod(Milliseconds freshnessPeriod)
 {
   onChanged();
-  metaInfo_.setFreshnessPeriod(freshnessPeriod);
+  m_metaInfo.setFreshnessPeriod(freshnessPeriod);
 }
 
 inline const name::Component&
 Data::getFinalBlockId() const
 {
-  return metaInfo_.getFinalBlockId();
+  return m_metaInfo.getFinalBlockId();
 }
 
 inline void
 Data::setFinalBlockId(const name::Component& finalBlockId)
 {
   onChanged();
-  metaInfo_.setFinalBlockId(finalBlockId);
+  m_metaInfo.setFinalBlockId(finalBlockId);
 }
 
 inline const Block& 
 Data::getContent() const
 {
-  if (content_.empty())
-    content_ = dataBlock(Tlv::Content, reinterpret_cast<const uint8_t*>(0), 0);
+  if (m_content.empty())
+    m_content = dataBlock(Tlv::Content, reinterpret_cast<const uint8_t*>(0), 0);
 
-  if (!content_.hasWire())
-      content_.encode();
-  return content_;
+  if (!m_content.hasWire())
+      m_content.encode();
+  return m_content;
 }
 
 inline void
@@ -257,7 +383,7 @@
 {
   onChanged();
 
-  content_ = dataBlock(Tlv::Content, content, contentLength);
+  m_content = dataBlock(Tlv::Content, content, contentLength);
 }
 
 inline void
@@ -265,7 +391,7 @@
 {
   onChanged();
 
-  content_ = Block(Tlv::Content, contentValue); // not real a wire encoding yet
+  m_content = Block(Tlv::Content, contentValue); // not real a wire encoding yet
 }
   
 inline void
@@ -274,30 +400,30 @@
   onChanged();
 
   if (content.type() == Tlv::Content)
-    content_ = content;
+    m_content = content;
   else {
-    content_ = Block(Tlv::Content, content);
+    m_content = Block(Tlv::Content, content);
   }
 }
 
 inline const Signature&
 Data::getSignature() const
 {
-  return signature_;
+  return m_signature;
 }
   
 inline void
 Data::setSignature(const Signature& signature) 
 {
   onChanged();
-  signature_ = signature;
+  m_signature = signature;
 }
 
 inline void
 Data::setSignatureValue(const Block &value)
 {
   onChanged();
-  signature_.setValue(value);
+  m_signature.setValue(value);
 }
 
 inline uint64_t
@@ -320,11 +446,21 @@
   // !!!Note!!! Signature is not invalidated and it is responsibility of
   // the application to do proper re-signing if necessary
   
-  wire_.reset();
+  m_wire.reset();
 }
 
-std::ostream&
-operator << (std::ostream &os, const Data &data);
+inline std::ostream&
+operator << (std::ostream &os, const Data &data)
+{
+  os << "Name: " << data.getName() << "\n";
+  os << "MetaInfo: " << data.getMetaInfo() << "\n";
+  os << "Content: (size: " << data.getContent().value_size() << ")\n";
+  os << "Signature: (type: " << data.getSignature().getType() <<
+    ", value_length: "<< data.getSignature().getValue().value_size() << ")";
+  os << std::endl;
+
+  return os;
+}
 
 } // namespace ndn