model: Enabling serialization/deserialization of Exclude filter in ndnSIM wire format

Refs #1009 (http://redmine.named-data.net/issues/1009)
diff --git a/docs/source/ndnsim-packet-formats.rst b/docs/source/ndnsim-packet-formats.rst
index cde727b..666eca0 100644
--- a/docs/source/ndnsim-packet-formats.rst
+++ b/docs/source/ndnsim-packet-formats.rst
@@ -170,11 +170,31 @@
 
 ::
 
-	Selectors ::= Length (Selector)*
+	Selectors ::= Length (SelectorType Selector)*
+
+        SelectorType ::= uint8_t
 
 	Selector ::= MinSuffixComponents | MaxSuffixComponents | Publisher | Exclude | ChildSelector | AnswerOriginKind
 
-All selectors are for now undefined
+Currently, ndnSIM defines following SelectorTypes:
+
+- 0x01: Exclude
+
+Other types are currently undefined
+
+Exclude
+~~~~~~~
+
+::
+
+	Exclude ::= Length (ExcludeComponent)*
+
+        ExcludeComponent ::= ExcludeNameType NameComponent ExcludeAnyType? |
+                             ExcludeAnyType
+
+        ExcludeNameType ::= uint8_t  (==0x01)
+
+        ExcludeAnyType ::= uint8_t   (==0x02)
 
 Options
 ~~~~~~~
diff --git a/model/ndn-interest.cc b/model/ndn-interest.cc
index 5d76362..3b09fde 100644
--- a/model/ndn-interest.cc
+++ b/model/ndn-interest.cc
@@ -35,6 +35,7 @@
   , m_interestLifetime (Seconds (0))
   , m_nonce (0)
   , m_nackType (NORMAL_INTEREST)
+  , m_exclude (0)
   , m_payload (payload)
   , m_wire (0)
 {
@@ -50,6 +51,7 @@
   , m_interestLifetime (interest.m_interestLifetime)
   , m_nonce            (interest.m_nonce)
   , m_nackType         (interest.m_nackType)
+  , m_exclude          (interest.m_exclude ? Create<Exclude> (*interest.GetExclude ()) : 0)
   , m_payload          (interest.GetPayload ()->Copy ())
   , m_wire             (0)
 {
@@ -136,6 +138,19 @@
 }
 
 void
+Interest::SetExclude (Ptr<Exclude> exclude)
+{
+  m_exclude = exclude;
+  m_wire = 0;
+}
+
+Ptr<const Exclude>
+Interest::GetExclude () const
+{
+  return m_exclude;
+}
+
+void
 Interest::SetPayload (Ptr<Packet> payload)
 {
   m_payload = payload;
diff --git a/model/ndn-interest.h b/model/ndn-interest.h
index 16e8fc3..748e2d9 100644
--- a/model/ndn-interest.h
+++ b/model/ndn-interest.h
@@ -27,7 +27,8 @@
 #include "ns3/packet.h"
 #include "ns3/ptr.h"
 
-#include <ns3/ndn-name.h>
+#include <ns3/ndnSIM/ndn.cxx/name.h>
+#include <ns3/ndnSIM/ndn.cxx/exclude.h>
 
 namespace ns3 {
 
@@ -178,7 +179,21 @@
   GetNack () const;
 
   /**
-   * @brief Get virtual "payload" of interest packet
+   * @brief Set exclude filter of interest packet
+   *
+   * Empty or 0 means no exclude filter
+   */
+  void
+  SetExclude (Ptr<Exclude> exclude);
+
+  /**
+   * @brief Get exclude filter of interest packet
+   */
+  Ptr<const Exclude>
+  GetExclude () const;
+  
+  /**
+   * @brief Set virtual "payload" of interest packet
    *
    * This payload can carry packet tags
    */
@@ -186,7 +201,7 @@
   SetPayload (Ptr<Packet> payload);
 
   /**
-   * @brief Set virtual "payload" to interest packet
+   * @brief Get virtual "payload" to interest packet
    *
    * This payload can carry packet tags
    */
@@ -224,6 +239,8 @@
   Time  m_interestLifetime; ///< @brief InterestLifetime
   uint32_t m_nonce;         ///< @brief Nonce. not used if zero
   uint8_t  m_nackType;      ///< @brief Negative Acknowledgement type
+
+  Ptr<Exclude> m_exclude;   ///< @brief Exclude filter
   Ptr<Packet> m_payload;    ///< @brief virtual payload
 
   mutable Ptr<const Packet> m_wire;
diff --git a/model/wire/ndnsim.cc b/model/wire/ndnsim.cc
index 75aaf1e..1c2d778 100644
--- a/model/wire/ndnsim.cc
+++ b/model/wire/ndnsim.cc
@@ -104,7 +104,11 @@
     1/*version*/ + 1 /*type*/ + 2/*length*/ +
     (4/*nonce*/ + 1/*scope*/ + 1/*nack type*/ + 2/*timestamp*/ +
      NdnSim::SerializedSizeName (m_interest->GetName ()) +
-     (2 + 0)/* selectors */ +
+
+     (2 +
+      (m_interest->GetExclude () == 0 ? 0 : (1 + NdnSim::SerializedSizeExclude (*m_interest->GetExclude ())))
+      )/* selectors */ +
+     
      (2 + 0)/* options */);
   
   NS_LOG_INFO ("Serialize size = " << size);
@@ -130,8 +134,18 @@
   start.WriteU16 (static_cast<uint16_t> (m_interest->GetInterestLifetime ().ToInteger (Time::S)));
 
   NdnSim::SerializeName (start, m_interest->GetName ());
+
+  if (m_interest->GetExclude () == 0)
+    {
+      start.WriteU16 (0); // no selectors
+    }
+  else
+    {
+      start.WriteU16 (1 + NdnSim::SerializedSizeExclude (*m_interest->GetExclude ()));
+      start.WriteU8 (0x01);
+      NdnSim::SerializeExclude (start, *m_interest->GetExclude ());
+    }
   
-  start.WriteU16 (0); // no selectors
   start.WriteU16 (0); // no options
 }
 
@@ -156,7 +170,14 @@
 
   m_interest->SetName (NdnSim::DeserializeName (i));
   
-  i.ReadU16 ();
+  uint32_t selectorsLen = i.ReadU16 ();
+  if (selectorsLen > 0)
+    {
+      if (i.ReadU8 () != 0x01) // exclude filter only
+        throw InterestException ();
+
+      m_interest->SetExclude (NdnSim::DeserializeExclude (i));
+    }
   i.ReadU16 ();
 
   NS_ASSERT (GetSerializedSize () == (i.GetDistanceFrom (start)));
diff --git a/model/wire/ndnsim/wire-ndnsim.cc b/model/wire/ndnsim/wire-ndnsim.cc
index 66c2c44..013d78d 100644
--- a/model/wire/ndnsim/wire-ndnsim.cc
+++ b/model/wire/ndnsim/wire-ndnsim.cc
@@ -73,6 +73,103 @@
   return name;
 }
 
+
+size_t
+NdnSim::SerializeExclude (Buffer::Iterator &i, const Exclude &exclude)
+{
+  Buffer::Iterator start = i;
+
+  i.WriteU16 (static_cast<uint16_t> (SerializedSizeExclude (exclude)-2));
+
+  for (Exclude::const_reverse_iterator item = exclude.rbegin ();
+       item != exclude.rend ();
+       item++)
+    {
+      if (!item->first.empty ())
+        {
+          i.WriteU8 (ExcludeNameType);
+          i.WriteU16 (static_cast<uint16_t> (item->first.size ()));
+          i.Write (reinterpret_cast<const uint8_t*> (item->first.buf ()), item->first.size ());
+        }
+      if (item->second)
+        {
+          i.WriteU8 (ExcludeAnyType);
+        }
+    }
+  return i.GetDistanceFrom (start);
+}
+
+size_t
+NdnSim::SerializedSizeExclude (const Exclude &exclude)
+{
+  size_t excludeSerializedSize = 2;
+
+  for (Exclude::const_reverse_iterator item = exclude.rbegin ();
+       item != exclude.rend ();
+       item++)
+    {
+      if (!item->first.empty ())
+        {
+          excludeSerializedSize += 1 + 2 + item->first.size ();
+        }
+      if (item->second)
+        {
+          excludeSerializedSize += 1;
+        }
+    }
+
+  return excludeSerializedSize;
+}
+
+Ptr<Exclude>
+NdnSim::DeserializeExclude (Buffer::Iterator &i)
+{
+  Ptr<Exclude> exclude = Create<Exclude> ();
+
+  uint16_t excludeLength = i.ReadU16 ();
+  while (excludeLength > 0)
+    {
+      uint8_t type = i.ReadU8 ();
+      excludeLength --;
+      
+      if (type == ExcludeAnyType)
+        {
+          exclude->appendExclude (name::Component (), true);
+        }
+      else if (type == ExcludeNameType)
+        {
+          uint16_t length = i.ReadU16 ();
+          excludeLength = excludeLength - 2 - length;
+
+          uint8_t tmp[length];
+          i.Read (tmp, length);
+
+          bool any = false;
+          if (excludeLength > 0)
+            {
+              uint8_t type = i.ReadU8 ();
+              if (type != ExcludeAnyType)
+                {
+                  i.Prev ();
+                }
+              else
+                {
+                  any = true;
+                  excludeLength --;
+                }
+            }
+
+          exclude->appendExclude (name::Component (tmp, length), any);
+        }
+      else
+        {
+          NS_FATAL_ERROR ("Incorrect format of Exclude filter");
+        }
+    }
+  return exclude;
+}
+
+
 } // wire
 
 NDN_NAMESPACE_END
diff --git a/model/wire/ndnsim/wire-ndnsim.h b/model/wire/ndnsim/wire-ndnsim.h
index 6e4b1e5..4ddfb3e 100644
--- a/model/wire/ndnsim/wire-ndnsim.h
+++ b/model/wire/ndnsim/wire-ndnsim.h
@@ -16,7 +16,8 @@
 #include "ns3/buffer.h"
 
 #include "ns3/ndn-common.h"
-#include "ns3/ndn-name.h"
+#include "ns3/ndnSIM/ndn.cxx/name.h"
+#include "ns3/ndnSIM/ndn.cxx/exclude.h"
 
 NDN_NAMESPACE_BEGIN
 
@@ -53,6 +54,42 @@
    */
   static Ptr<Name>
   DeserializeName (Buffer::Iterator &start);
+
+
+  enum Selectors {
+    SelectorExclude = 0x01
+  };
+
+  enum ExcludeTypes {
+    ExcludeNameType = 0x01,
+    ExcludeAnyType = 0x02
+  };
+  
+  /**
+   * @brief Append Exclude in ndnSIM encoding
+   * @param start Buffer to store serialized Interest
+   * @param exclude constant reference to Exclude object
+   *
+   * @returns written length
+   */
+  static size_t
+  SerializeExclude (Buffer::Iterator &start, const Exclude &exclude);
+
+  /**
+   * @brief Estimate size of Exclude in ndnSIM encoding
+   * @param exclude constant reference to Exclude object
+   * @returns estimated length
+   */
+  static size_t
+  SerializedSizeExclude (const Exclude &exclude);
+
+  /**
+   * @brief Deserialize Exclude from ndnSIM encodeing
+   * @param start Buffer that stores serialized Interest
+   * @param exclude Exclude object
+   */
+  static Ptr<Exclude>
+  DeserializeExclude (Buffer::Iterator &start);
 }; // NdnSim
 
 } // wire
diff --git a/ndn.cxx/exclude.h b/ndn.cxx/exclude.h
index 70b8f54..8315f34 100644
--- a/ndn.cxx/exclude.h
+++ b/ndn.cxx/exclude.h
@@ -11,8 +11,9 @@
 #ifndef NDN_EXCLUDE_H
 #define NDN_EXCLUDE_H
 
-#include "name-component.h"
+#include <ns3/simple-ref-count.h>
 
+#include "name-component.h"
 #include <map>
 
 NDN_NAMESPACE_BEGIN
@@ -20,7 +21,7 @@
 /**
  * @brief Class to represent Exclude component in NDN interests
  */
-class Exclude
+class Exclude : public SimpleRefCount<Exclude>
 {
 public:
   typedef std::map< name::Component, bool /*any*/, std::greater<name::Component> > exclude_type;
@@ -35,6 +36,8 @@
    */
   Exclude ();
 
+  // no need for explicit copy constructor
+
   /**
    * @brief Check if name component is excluded
    * @param comp Name component to check against exclude filter
diff --git a/test/ndnSIM-serialization.cc b/test/ndnSIM-serialization.cc
index 4ed2bda..70a10a7 100644
--- a/test/ndnSIM-serialization.cc
+++ b/test/ndnSIM-serialization.cc
@@ -68,6 +68,33 @@
   NS_TEST_ASSERT_MSG_EQ (source->GetInterestLifetime (), target->GetInterestLifetime (), "source/target interest lifetime failed");
   NS_TEST_ASSERT_MSG_EQ (source->GetNonce ()           , target->GetNonce ()           , "source/target nonce failed");
   NS_TEST_ASSERT_MSG_EQ (source->GetNack ()            , target->GetNack ()            , "source/target NACK failed");
+
+  NS_TEST_ASSERT_MSG_EQ (source->GetExclude ()         , 0, "exclude should be empty");
+  NS_TEST_ASSERT_MSG_EQ (target->GetExclude ()         , 0, "exclude should be empty");
+  
+  Ptr<Exclude> exclude = Create<Exclude> ();
+  exclude->excludeAfter (name::Component ());
+  source->SetExclude (exclude);
+  
+  NS_TEST_ASSERT_MSG_EQ (boost::lexical_cast<std::string> (*source->GetExclude ()),
+                         " ----> ", "exclude should contain only <ANY/>");
+
+  exclude->appendExclude (name::Component ("alex"), false);
+  exclude->excludeAfter (name::Component ("zhenkai"));
+
+  source->SetExclude (exclude);  
+  NS_TEST_ASSERT_MSG_EQ (boost::lexical_cast<std::string> (*source->GetExclude ()),
+                         " ----> alex zhenkai ----> ", "exclude should contain only <ANY/>");
+
+  NS_TEST_ASSERT_MSG_EQ (source->GetWire (), 0, "Wire should be empty");
+  NS_TEST_ASSERT_MSG_NE (source->GetPayload (), 0, "Payload should not be empty");
+
+  packet = wire::ndnSIM::Interest::ToWire (source);
+  target = wire::ndnSIM::Interest::FromWire (packet);
+  NS_TEST_ASSERT_MSG_NE (target->GetExclude (), 0, "exclude should not be empty");
+
+  NS_TEST_ASSERT_MSG_EQ (boost::lexical_cast<std::string> (*target->GetExclude ()),
+                         " ----> alex zhenkai ----> ", "exclude should contain only <ANY/>");
 }
 
 void