data: Optimize Data signing

As of this commit, KeyChain::sign pre-allocates EncodingBuffer, requests
unsigned portion of Data using Data::wireEncode(EncodingBuffer, true),
and then appends the resulting signature and prepends Data packet
header.  This way there is no extra memory allocation after Data packet
is signed.

Change-Id: I670e9a2f1d6f5e9b049f41b47f011af384f32c95
diff --git a/src/data.hpp b/src/data.hpp
index b82533a..9338258 100644
--- a/src/data.hpp
+++ b/src/data.hpp
@@ -83,17 +83,20 @@
    * Otherwise, Data::shared_from_this() will throw an exception.
    */
   explicit
-  Data(const Block& wire)
-  {
-    wireDecode(wire);
-  }
+  Data(const Block& wire);
 
   /**
    * @brief Fast encoding or block size estimation
+   *
+   * @param block                   EncodingEstimator or EncodingBuffer instance
+   * @param wantUnsignedPortionOnly Request only unsigned portion to be encoded in block.
+   *                                If true, only Name, MetaInfo, Content, and SignatureInfo
+   *                                blocks will be encoded into the block. Note that there
+   *                                will be no outer TLV header of the Data packet.
    */
   template<bool T>
   size_t
-  wireEncode(EncodingImpl<T>& block, bool unsignedPortion = false) const;
+  wireEncode(EncodingImpl<T>& block, bool wantUnsignedPortionOnly = false) const;
 
   /**
    * @brief Encode to a wire format
@@ -102,6 +105,28 @@
   wireEncode() const;
 
   /**
+   * @brief Finalize Data packet encoding with the specified SignatureValue
+   *
+   * @param encoder        EncodingBuffer instance, containing Name, MetaInfo, Content, and
+   *                       SignatureInfo (without outer TLV header of the Data packet).
+   * @param signatureValue SignatureValue block to be added to Data packet to finalize
+   *                       the wire encoding
+   *
+   * This method is intended to be used in concert with Data::wireEncode(EncodingBuffer&, true)
+   * method to optimize Data packet wire format creation:
+   *
+   *     Data data;
+   *     ...
+   *     EncodingBuffer encoder;
+   *     data.wireEncode(encoder, true);
+   *     ...
+   *     Block signatureValue = <sign_over_unsigned_portion>(encoder.buf(), encoder.size());
+   *     data.wireEncode(encoder, signatureValue)
+   */
+  const Block&
+  wireEncode(EncodingBuffer& encoder, const Block& signatureValue) const;
+
+  /**
    * @brief Decode from the wire format
    */
   void
@@ -286,112 +311,6 @@
   friend class nfd::LocalControlHeader;
 };
 
-inline
-Data::Data()
-  : m_content(Tlv::Content) // empty content
-{
-}
-
-inline
-Data::Data(const Name& name)
-  : m_name(name)
-{
-}
-
-template<bool T>
-inline size_t
-Data::wireEncode(EncodingImpl<T>& block, bool unsignedPortion/* = false*/) const
-{
-  size_t totalLength = 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
-      totalLength += prependBlock(block, m_signature.getValue());
-    }
-
-  // SignatureInfo
-  totalLength += prependBlock(block, m_signature.getInfo());
-
-  // Content
-  totalLength += prependBlock(block, getContent());
-
-  // MetaInfo
-  totalLength += getMetaInfo().wireEncode(block);
-
-  // Name
-  totalLength += getName().wireEncode(block);
-
-  if (!unsignedPortion)
-    {
-      totalLength += block.prependVarNumber (totalLength);
-      totalLength += block.prependVarNumber (Tlv::Data);
-    }
-  return totalLength;
-}
-
-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;
-}
-
-inline 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 bool
 Data::hasWire() const
@@ -405,146 +324,36 @@
   return m_name;
 }
 
-inline Data&
-Data::setName(const Name& name)
-{
-  onChanged();
-  m_name = name;
-
-  return *this;
-}
-
 inline const MetaInfo&
 Data::getMetaInfo() const
 {
   return m_metaInfo;
 }
 
-inline Data&
-Data::setMetaInfo(const MetaInfo& metaInfo)
-{
-  onChanged();
-  m_metaInfo = metaInfo;
-
-  return *this;
-}
-
 inline uint32_t
 Data::getContentType() const
 {
   return m_metaInfo.getType();
 }
 
-inline Data&
-Data::setContentType(uint32_t type)
-{
-  onChanged();
-  m_metaInfo.setType(type);
-
-  return *this;
-}
-
 inline const time::milliseconds&
 Data::getFreshnessPeriod() const
 {
   return m_metaInfo.getFreshnessPeriod();
 }
 
-inline Data&
-Data::setFreshnessPeriod(const time::milliseconds& freshnessPeriod)
-{
-  onChanged();
-  m_metaInfo.setFreshnessPeriod(freshnessPeriod);
-
-  return *this;
-}
-
 inline const name::Component&
 Data::getFinalBlockId() const
 {
   return m_metaInfo.getFinalBlockId();
 }
 
-inline Data&
-Data::setFinalBlockId(const name::Component& finalBlockId)
-{
-  onChanged();
-  m_metaInfo.setFinalBlockId(finalBlockId);
-
-  return *this;
-}
-
-inline const Block&
-Data::getContent() const
-{
-  if (m_content.empty())
-    m_content = dataBlock(Tlv::Content, reinterpret_cast<const uint8_t*>(0), 0);
-
-  if (!m_content.hasWire())
-      m_content.encode();
-  return m_content;
-}
-
-inline Data&
-Data::setContent(const uint8_t* content, size_t contentLength)
-{
-  onChanged();
-
-  m_content = dataBlock(Tlv::Content, content, contentLength);
-
-  return *this;
-}
-
-inline Data&
-Data::setContent(const ConstBufferPtr& contentValue)
-{
-  onChanged();
-
-  m_content = Block(Tlv::Content, contentValue); // not real a wire encoding yet
-
-  return *this;
-}
-
-inline Data&
-Data::setContent(const Block& content)
-{
-  onChanged();
-
-  if (content.type() == Tlv::Content)
-    m_content = content;
-  else {
-    m_content = Block(Tlv::Content, content);
-  }
-
-  return *this;
-}
-
 inline const Signature&
 Data::getSignature() const
 {
   return m_signature;
 }
 
-inline Data&
-Data::setSignature(const Signature& signature)
-{
-  onChanged();
-  m_signature = signature;
-
-  return *this;
-}
-
-inline Data&
-Data::setSignatureValue(const Block& value)
-{
-  onChanged();
-  m_signature.setValue(value);
-
-  return *this;
-}
-
-//
-
 inline nfd::LocalControlHeader&
 Data::getLocalControlHeader()
 {
@@ -563,53 +372,6 @@
   return getLocalControlHeader().getIncomingFaceId();
 }
 
-inline Data&
-Data::setIncomingFaceId(uint64_t incomingFaceId)
-{
-  getLocalControlHeader().setIncomingFaceId(incomingFaceId);
-  // ! do not reset Data's wire !
-
-  return *this;
-}
-
-inline void
-Data::onChanged()
-{
-  // The values have changed, so the wire format is invalidated
-
-  // !!!Note!!! Signature is not invalidated and it is responsibility of
-  // the application to do proper re-signing if necessary
-
-  m_wire.reset();
-}
-
-inline bool
-Data::operator==(const Data& other) const
-{
-  return getName() == other.getName() &&
-    getMetaInfo() == other.getMetaInfo() &&
-    getContent() == other.getContent() &&
-    getSignature() == other.getSignature();
-}
-
-inline bool
-Data::operator!=(const Data& other) const
-{
-  return !(*this == other);
-}
-
-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