model: Returning back support for CCNb wire format

Refs #1008 (http://redmine.named-data.net/)
diff --git a/model/wire/ccnb/wire-ccnb-data.cc b/model/wire/ccnb/wire-ccnb-data.cc
new file mode 100644
index 0000000..767d57b
--- /dev/null
+++ b/model/wire/ccnb/wire-ccnb-data.cc
@@ -0,0 +1,505 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2011 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Ilya Moiseenko <iliamo@cs.ucla.edu>
+ *         Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "../ccnb.h"
+
+#include "wire-ccnb.h"
+
+#include "ns3/log.h"
+
+#include "ccnb-parser/common.h"
+#include "ccnb-parser/visitors/void-depth-first-visitor.h"
+#include "ccnb-parser/visitors/name-visitor.h"
+#include "ccnb-parser/visitors/non-negative-integer-visitor.h"
+#include "ccnb-parser/visitors/timestamp-visitor.h"
+#include "ccnb-parser/visitors/string-visitor.h"
+#include "ccnb-parser/visitors/uint32t-blob-visitor.h"
+#include "ccnb-parser/visitors/content-type-visitor.h"
+
+#include "ccnb-parser/syntax-tree/block.h"
+#include "ccnb-parser/syntax-tree/dtag.h"
+
+#include <boost/foreach.hpp>
+
+NS_LOG_COMPONENT_DEFINE ("ndn.wire.Ccnb.Data");
+
+NDN_NAMESPACE_BEGIN
+
+namespace wire {
+namespace ccnb {
+
+// const std::string DefaultDigestAlgorithm = "2.16.840.1.101.3.4.2.1";
+
+class DataTrailer : public Trailer
+{
+public:
+  DataTrailer ()
+  {
+  }
+
+  static TypeId GetTypeId ()
+  {
+    static TypeId tid = TypeId ("ns3::ndn::Data::Ccnb::Closer")
+      .SetGroupName ("Ndn")
+      .SetParent<Trailer> ()
+      .AddConstructor<DataTrailer> ()
+      ;
+    return tid;
+  }
+
+  virtual TypeId GetInstanceTypeId (void) const
+  {
+    return GetTypeId ();
+  }
+
+  virtual void Print (std::ostream &os) const
+  {
+  }
+
+  virtual uint32_t GetSerializedSize (void) const
+  {
+    return 2;
+  }
+
+  virtual void Serialize (Buffer::Iterator end) const
+  {
+    Buffer::Iterator i = end;
+    i.Prev (2); // Trailer interface requires us to go backwards
+
+    i.WriteU8 (0x00); // </Content>
+    i.WriteU8 (0x00); // </ContentObject>
+  }
+
+  virtual uint32_t Deserialize (Buffer::Iterator end)
+  {
+    Buffer::Iterator i = end;
+    i.Prev (2); // Trailer interface requires us to go backwards
+
+    uint8_t closing_tag_content = i.ReadU8 ();
+    NS_ASSERT_MSG (closing_tag_content==0, "Should be a closing tag </Content> (0x00)");
+
+    uint8_t closing_tag_content_object = i.ReadU8 ();
+    NS_ASSERT_MSG (closing_tag_content_object==0, "Should be a closing tag </ContentObject> (0x00)");
+
+    return 2;
+  }
+};
+
+NS_OBJECT_ENSURE_REGISTERED (Data);
+NS_OBJECT_ENSURE_REGISTERED (DataTrailer);
+
+TypeId
+Data::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::ndn::Data::Ccnb")
+    .SetGroupName ("Ndn")
+    .SetParent<Header> ()
+    .AddConstructor<Data> ()
+    ;
+  return tid;
+}
+
+TypeId
+Data::GetInstanceTypeId (void) const
+{
+  return GetTypeId ();
+}
+
+Data::Data ()
+  : m_data (Create<ndn::ContentObject> ())
+{
+}
+
+Data::Data (Ptr<ndn::ContentObject> data)
+  : m_data (data)
+{
+}
+
+Ptr<ndn::ContentObject>
+Data::GetData ()
+{
+  return m_data;
+}
+
+Ptr<Packet>
+Data::ToWire (Ptr<const ndn::ContentObject> data)
+{
+  static DataTrailer trailer;
+
+  Ptr<const Packet> p = data->GetWire ();
+  if (!p)
+    {
+      Ptr<Packet> packet = Create<Packet> (*data->GetPayload ());
+      Data wireEncoding (ConstCast<ndn::ContentObject> (data));
+      packet->AddHeader (wireEncoding);
+      packet->AddTrailer (trailer);
+      data->SetWire (packet);
+
+      p = packet;
+    }
+
+  return p->Copy ();
+}
+
+Ptr<ndn::ContentObject>
+Data::FromWire (Ptr<Packet> packet)
+{
+  static DataTrailer trailer;
+
+  Ptr<ndn::ContentObject> data = Create<ndn::ContentObject> ();
+  data->SetWire (packet->Copy ());
+
+  Data wireEncoding (data);
+  packet->RemoveHeader (wireEncoding);
+  packet->RemoveTrailer (trailer);
+
+  data->SetPayload (packet);
+
+  return data;
+}
+
+void
+Data::Serialize (Buffer::Iterator start) const
+{
+  Ccnb::AppendBlockHeader (start, CcnbParser::CCN_DTAG_ContentObject, CcnbParser::CCN_DTAG); // <ContentObject>
+
+  // fake signature
+  Ccnb::AppendBlockHeader (start, CcnbParser::CCN_DTAG_Signature, CcnbParser::CCN_DTAG); // <Signature>
+  // Signature ::= √DigestAlgorithm?
+  //               Witness?
+  //               √SignatureBits
+  // if (GetSignature ().GetDigestAlgorithm () != Signature::DefaultDigestAlgorithm)
+  //   {
+  //     Ccnb::AppendString (start, CcnbParser::CCN_DTAG_DigestAlgorithm, GetSignature ().GetDigestAlgorithm ());
+  //   }
+  Ccnb::AppendTaggedBlob (start, CcnbParser::CCN_DTAG_SignatureBits, m_data->GetSignature ()); // <SignatureBits />
+  Ccnb::AppendCloser (start);                                    // </Signature>
+
+  Ccnb::AppendBlockHeader (start, CcnbParser::CCN_DTAG_Name, CcnbParser::CCN_DTAG);    // <Name>
+  Ccnb::AppendName (start, m_data->GetName()); //   <Component>...</Component>...
+  Ccnb::AppendCloser (start);                                  // </Name>
+
+  // fake signature
+  Ccnb::AppendBlockHeader (start, CcnbParser::CCN_DTAG_SignedInfo, CcnbParser::CCN_DTAG); // <SignedInfo>
+  // SignedInfo ::= √PublisherPublicKeyDigest
+  //                √Timestamp
+  //                √Type?
+  //                √FreshnessSeconds?
+  //                FinalBlockID?
+  //                KeyLocator?
+  // Ccnb::AppendTaggedBlob (start, CcnbParser::CCN_DTAG_PublisherPublicKeyDigest,         // <PublisherPublicKeyDigest>...
+  //                         GetSignedInfo ().GetPublisherPublicKeyDigest ());
+
+  Ccnb::AppendBlockHeader (start, CcnbParser::CCN_DTAG_Timestamp, CcnbParser::CCN_DTAG);            // <Timestamp>...
+  Ccnb::AppendTimestampBlob (start, m_data->GetTimestamp ());
+  Ccnb::AppendCloser (start);
+
+  // if (GetSignedInfo ().GetContentType () != DATA)
+  //   {
+  //     uint8_t type[3];
+  //     type[0] = (GetSignedInfo ().GetContentType () >> 16) & 0xFF;
+  //     type[1] = (GetSignedInfo ().GetContentType () >> 8 ) & 0xFF;
+  //     type[2] = (GetSignedInfo ().GetContentType ()      ) & 0xFF;
+
+  //     Ccnb::AppendTaggedBlob (start, CCN_DTAG_Type, type, 3);
+  //   }
+  if (m_data->GetFreshness () > Seconds(0))
+    {
+      Ccnb::AppendBlockHeader (start, CcnbParser::CCN_DTAG_FreshnessSeconds, CcnbParser::CCN_DTAG);
+      Ccnb::AppendNumber (start, m_data->GetFreshness ().ToInteger (Time::S));
+      Ccnb::AppendCloser (start);
+    }
+  if (m_data->GetKeyLocator () != 0)
+    {
+      Ccnb::AppendBlockHeader (start, CcnbParser::CCN_DTAG_KeyLocator, CcnbParser::CCN_DTAG); // <KeyLocator>
+      {
+        Ccnb::AppendBlockHeader (start, CcnbParser::CCN_DTAG_KeyName, CcnbParser::CCN_DTAG);    // <KeyName>
+        {
+          Ccnb::AppendBlockHeader (start, CcnbParser::CCN_DTAG_Name, CcnbParser::CCN_DTAG);       // <Name>
+          Ccnb::AppendName (start, *m_data->GetKeyLocator ());   //   <Component>...</Component>...
+          Ccnb::AppendCloser (start);                                     // </Name>
+        }
+        Ccnb::AppendCloser (start);                                     // </KeyName>
+      }
+      Ccnb::AppendCloser (start);                                     // </KeyLocator>
+    }
+
+  Ccnb::AppendCloser (start);                                     // </SignedInfo>
+
+  Ccnb::AppendBlockHeader (start, CcnbParser::CCN_DTAG_Content, CcnbParser::CCN_DTAG); // <Content>
+
+  // there are no closing tags !!!
+  // The closing tag is handled by ContentObjectTail
+}
+
+uint32_t
+Data::GetSerializedSize () const
+{
+  size_t written = 0;
+  written += Ccnb::EstimateBlockHeader (CcnbParser::CCN_DTAG_ContentObject); // <ContentObject>
+
+  // fake signature
+  written += Ccnb::EstimateBlockHeader (CcnbParser::CCN_DTAG_Signature); // <Signature>
+  // Signature ::= DigestAlgorithm?
+  //               Witness?
+  //               SignatureBits
+  // if (GetSignature ().GetDigestAlgorithm () != Signature::DefaultDigestAlgorithm)
+  //   {
+  //     written += Ccnb::EstimateString (CcnbParser::CCN_DTAG_DigestAlgorithm, GetSignature ().GetDigestAlgorithm ());
+  //   }
+  written += Ccnb::EstimateTaggedBlob (CcnbParser::CCN_DTAG_SignatureBits,
+                                       sizeof (m_data->GetSignature ()));      // <SignatureBits />
+  written += 1;                                    // </Signature>
+
+  written += Ccnb::EstimateBlockHeader (CcnbParser::CCN_DTAG_Name);    // <Name>
+  written += Ccnb::EstimateName (m_data->GetName ()); //   <Component>...</Component>...
+  written += 1;                                  // </Name>
+
+  // fake signature
+  written += Ccnb::EstimateBlockHeader (CcnbParser::CCN_DTAG_SignedInfo); // <SignedInfo>
+  // SignedInfo ::= √PublisherPublicKeyDigest
+  //                √Timestamp
+  //                √Type?
+  //                √FreshnessSeconds?
+  //                FinalBlockID?
+  //                KeyLocator?
+
+  // written += Ccnb::EstimateTaggedBlob (CCN_DTAG_PublisherPublicKeyDigest,                          // <PublisherPublicKeyDigest>...
+  //                                      sizeof (GetSignedInfo ().GetPublisherPublicKeyDigest ()));
+
+  written += Ccnb::EstimateBlockHeader (CcnbParser::CCN_DTAG_Timestamp);                  // <Timestamp>...
+  written += Ccnb::EstimateTimestampBlob (m_data->GetTimestamp ());
+  written += 1;
+
+  // if (GetSignedInfo ().GetContentType () != DATA)
+  //   {
+  //     written += Ccnb::EstimateTaggedBlob (CcnbParser::CCN_DTAG_Type, 3);
+  //   }
+  if (m_data->GetFreshness () > Seconds(0))
+    {
+      written += Ccnb::EstimateBlockHeader (CcnbParser::CCN_DTAG_FreshnessSeconds);
+      written += Ccnb::EstimateNumber (m_data->GetFreshness ().ToInteger (Time::S));
+      written += 1;
+    }
+
+  if (m_data->GetKeyLocator () != 0)
+    {
+      written += Ccnb::EstimateBlockHeader (CcnbParser::CCN_DTAG_KeyLocator); // <KeyLocator>
+      {
+        written += Ccnb::EstimateBlockHeader (CcnbParser::CCN_DTAG_KeyName);    // <KeyName>
+        {
+          written += Ccnb::EstimateBlockHeader (CcnbParser::CCN_DTAG_Name);       // <Name>
+          written += Ccnb::EstimateName (*m_data->GetKeyLocator ());        //   <Component>...</Component>...
+          written += 1;                                               // </Name>
+        }
+        written += 1;                                               // </KeyName>
+      }
+      written += 1;                                               // </KeyLocator>
+    }
+
+  written += 1; // </SignedInfo>
+
+  written += Ccnb::EstimateBlockHeader (CcnbParser::CCN_DTAG_Content); // <Content>
+
+  // there are no closing tags !!!
+  // The closing tag is handled by ContentObjectTail
+  return written;
+}
+
+class ContentObjectVisitor : public CcnbParser::VoidDepthFirstVisitor
+{
+public:
+  virtual void visit (CcnbParser::Dtag &n, boost::any param/*should be ContentObject* */)
+  {
+    // uint32_t n.m_dtag;
+    // std::list< Ptr<CcnbParser::Block> > n.m_nestedBlocks;
+    static CcnbParser::NameVisitor nameVisitor;
+    static CcnbParser::NonNegativeIntegerVisitor nonNegativeIntegerVisitor;
+    static CcnbParser::TimestampVisitor          timestampVisitor;
+    static CcnbParser::StringVisitor      stringVisitor;
+    static CcnbParser::Uint32tBlobVisitor uint32tBlobVisitor;
+    static CcnbParser::ContentTypeVisitor contentTypeVisitor;
+
+    ndn::ContentObject &contentObject = *(boost::any_cast<ndn::ContentObject*> (param));
+
+    switch (n.m_dtag)
+      {
+      case CcnbParser::CCN_DTAG_ContentObject:
+        // process nested blocks
+        BOOST_FOREACH (Ptr<CcnbParser::Block> block, n.m_nestedTags)
+          {
+            block->accept (*this, param);
+          }
+        break;
+      case CcnbParser::CCN_DTAG_Name:
+        {
+          // process name components
+          Ptr<Name> name = Create<Name> ();
+
+          BOOST_FOREACH (Ptr<CcnbParser::Block> block, n.m_nestedTags)
+            {
+              block->accept (nameVisitor, &(*name));
+            }
+          contentObject.SetName (name);
+          break;
+        }
+
+      case CcnbParser::CCN_DTAG_Signature:
+        // process nested blocks
+        BOOST_FOREACH (Ptr<CcnbParser::Block> block, n.m_nestedTags)
+          {
+            block->accept (*this, param);
+          }
+        break;
+
+      // case CCN_DTAG_DigestAlgorithm:
+      //   NS_LOG_DEBUG ("DigestAlgorithm");
+      //   if (n.m_nestedTags.size ()!=1) // should be exactly one UDATA inside this tag
+      //     throw CcnbParser::CcnbDecodingException ();
+
+      //   contentObject.GetSignature ().SetDigestAlgorithm
+      //     (boost::any_cast<std::string> ((*n.m_nestedTags.begin())->accept
+      //                                    (stringVisitor)));
+      //   break;
+
+      case CcnbParser::CCN_DTAG_SignatureBits:
+        NS_LOG_DEBUG ("SignatureBits");
+        if (n.m_nestedTags.size ()!=1) // should be only one nested tag
+          throw CcnbParser::CcnbDecodingException ();
+
+        contentObject.SetSignature
+          (boost::any_cast<uint32_t> ((*n.m_nestedTags.begin())->accept
+                                      (uint32tBlobVisitor)));
+        break;
+
+      case CcnbParser::CCN_DTAG_SignedInfo:
+        // process nested blocks
+        BOOST_FOREACH (Ptr<CcnbParser::Block> block, n.m_nestedTags)
+          {
+            block->accept (*this, param);
+          }
+        break;
+
+      // case CCN_DTAG_PublisherPublicKeyDigest:
+      //   NS_LOG_DEBUG ("PublisherPublicKeyDigest");
+      //   if (n.m_nestedTags.size ()!=1) // should be only one nested tag
+      //     throw CcnbParser::CcnbDecodingException ();
+
+      //   contentObject.GetSignedInfo ().SetPublisherPublicKeyDigest
+      //     (boost::any_cast<uint32_t> ((*n.m_nestedTags.begin())->accept
+      //                                 (uint32tBlobVisitor)));
+      //   break;
+
+      case CcnbParser::CCN_DTAG_Timestamp:
+        NS_LOG_DEBUG ("Timestamp");
+        if (n.m_nestedTags.size()!=1) // should be exactly one nested tag
+          throw CcnbParser::CcnbDecodingException ();
+
+        contentObject.SetTimestamp
+          (boost::any_cast<Time> ((*n.m_nestedTags.begin())->accept
+                                  (timestampVisitor)));
+        break;
+
+      // case CCN_DTAG_Type:
+      //   NS_LOG_DEBUG ("Type");
+      //   if (n.m_nestedTags.size ()!=1) // should be only one nested tag
+      //     throw CcnbParser::CcnbDecodingException ();
+
+      //   contentObject.GetSignedInfo ().SetContentType
+      //     (static_cast<Data::ContentType>
+      //      (boost::any_cast<uint32_t> ((*n.m_nestedTags.begin())->accept
+      //                                  (contentTypeVisitor))));
+      //   break;
+
+      case CcnbParser::CCN_DTAG_FreshnessSeconds:
+        NS_LOG_DEBUG ("FreshnessSeconds");
+
+        if (n.m_nestedTags.size()!=1) // should be exactly one nested tag
+          throw CcnbParser::CcnbDecodingException ();
+
+        contentObject.SetFreshness
+          (Seconds
+           (boost::any_cast<uint32_t> ((*n.m_nestedTags.begin())->accept
+                                       (nonNegativeIntegerVisitor))));
+        break;
+
+      case CcnbParser::CCN_DTAG_KeyLocator:
+        // process nested blocks
+        BOOST_FOREACH (Ptr<CcnbParser::Block> block, n.m_nestedTags)
+          {
+            block->accept (*this, param);
+          }
+        break;
+
+      case CcnbParser::CCN_DTAG_KeyName:
+        {
+          if (n.m_nestedTags.size ()!=1) // should be exactly one nested tag
+            throw CcnbParser::CcnbDecodingException ();
+
+          Ptr<CcnbParser::BaseTag> nameTag = DynamicCast<CcnbParser::BaseTag>(n.m_nestedTags.front ());
+          if (nameTag == 0)
+            throw CcnbParser::CcnbDecodingException ();
+
+          // process name components
+          Ptr<Name> name = Create<Name> ();
+
+          BOOST_FOREACH (Ptr<CcnbParser::Block> block, nameTag->m_nestedTags)
+            {
+              block->accept (nameVisitor, &(*name));
+            }
+          contentObject.SetKeyLocator (name);
+          break;
+        }
+
+      case CcnbParser::CCN_DTAG_Content: // !!! HACK
+        // This hack was necessary for memory optimizations (i.e., content is virtual payload)
+        NS_ASSERT_MSG (n.m_nestedTags.size() == 0, "Parser should have stopped just after processing <Content> tag");
+        break;
+
+      default: // ignore all other stuff
+        break;
+      }
+  }
+};
+
+uint32_t
+Data::Deserialize (Buffer::Iterator start)
+{
+  static ContentObjectVisitor contentObjectVisitor;
+
+  Buffer::Iterator i = start;
+  Ptr<CcnbParser::Block> root = CcnbParser::Block::ParseBlock (i);
+  root->accept (contentObjectVisitor, GetPointer (m_data));
+
+  return i.GetDistanceFrom (start);
+}
+
+void
+Data::Print (std::ostream &os) const
+{
+  os << "D: " << m_data->GetName ();
+  // os << "<ContentObject><Name>" << GetName () << "</Name><Content>";
+}
+
+} // ccnb
+} // wire
+
+NDN_NAMESPACE_END