name: recognize ParametersSha256DigestComponent

refs #4658, #4570

Change-Id: I8001f6aa7a406e9e8eb10fc365bd84bc711cda07
diff --git a/src/detail/name-component-types.hpp b/src/detail/name-component-types.hpp
index 8d074fd..0f98920 100644
--- a/src/detail/name-component-types.hpp
+++ b/src/detail/name-component-types.hpp
@@ -180,15 +180,33 @@
   {
   }
 
+  bool
+  match(const Component& comp) const
+  {
+    return comp.type() == m_type && comp.value_size() == util::Sha256::DIGEST_SIZE;
+  }
+
   void
   check(const Component& comp) const final
   {
-    if (comp.value_size() != util::Sha256::DIGEST_SIZE) {
+    if (!match(comp)) {
       BOOST_THROW_EXCEPTION(Error(m_typeName + " TLV-LENGTH must be " +
                                   to_string(util::Sha256::DIGEST_SIZE)));
     }
   }
 
+  Component
+  create(ConstBufferPtr value) const
+  {
+    return Component(Block(m_type, std::move(value)));
+  }
+
+  Component
+  create(const uint8_t* value, size_t valueSize) const
+  {
+    return Component(makeBinaryBlock(m_type, value, valueSize));
+  }
+
   std::pair<bool, Component>
   getSuccessor(const Component& comp) const final
   {
@@ -204,7 +222,7 @@
   const std::vector<uint8_t>&
   getMinValue() const final
   {
-    static std::vector<uint8_t> value(16);
+    static std::vector<uint8_t> value(util::Sha256::DIGEST_SIZE);
     return value;
   }
 
@@ -240,6 +258,22 @@
   std::string m_uriPrefix;
 };
 
+inline const Sha256ComponentType&
+getComponentType1()
+{
+  static Sha256ComponentType ct1(tlv::ImplicitSha256DigestComponent,
+                                 "ImplicitSha256DigestComponent", "sha256digest");
+  return ct1;
+}
+
+inline const Sha256ComponentType&
+getComponentType2()
+{
+  static Sha256ComponentType ct2(tlv::ParametersSha256DigestComponent,
+                                 "ParametersSha256DigestComponent", "params-sha256");
+  return ct2;
+}
+
 /** \brief Rules regarding NameComponent types.
  */
 class ComponentTypeTable : noncopyable
@@ -286,6 +320,7 @@
   std::unordered_map<std::string, const ComponentType*> m_uriPrefixes;
 };
 
+inline
 ComponentTypeTable::ComponentTypeTable()
 {
   m_table.fill(nullptr);
@@ -293,14 +328,13 @@
   static GenericNameComponentType ct8;
   set(tlv::GenericNameComponent, ct8);
 
-  static Sha256ComponentType ct1(tlv::ImplicitSha256DigestComponent,
-                                 "ImplicitSha256DigestComponent", "sha256digest");
-  set(tlv::ImplicitSha256DigestComponent, ct1);
+  set(tlv::ImplicitSha256DigestComponent, getComponentType1());
+  set(tlv::ParametersSha256DigestComponent, getComponentType2());
 }
 
 /** \brief Get the global ComponentTypeTable.
  */
-const ComponentTypeTable&
+inline const ComponentTypeTable&
 getComponentTypeTable()
 {
   static ComponentTypeTable ctt;
diff --git a/src/encoding/tlv.hpp b/src/encoding/tlv.hpp
index d4abdc1..f7b7240 100644
--- a/src/encoding/tlv.hpp
+++ b/src/encoding/tlv.hpp
@@ -59,30 +59,31 @@
  *  @sa https://named-data.net/doc/NDN-packet-spec/current/types.html
  */
 enum {
-  Interest                      = 5,
-  Data                          = 6,
-  Name                          = 7,
-  GenericNameComponent          = 8,
-  ImplicitSha256DigestComponent = 1,
-  CanBePrefix                   = 33,
-  MustBeFresh                   = 18,
-  ForwardingHint                = 30,
-  Nonce                         = 10,
-  InterestLifetime              = 12,
-  HopLimit                      = 34,
-  Parameters                    = 35,
-  MetaInfo                      = 20,
-  Content                       = 21,
-  SignatureInfo                 = 22,
-  SignatureValue                = 23,
-  ContentType                   = 24,
-  FreshnessPeriod               = 25,
-  FinalBlockId                  = 26,
-  SignatureType                 = 27,
-  KeyLocator                    = 28,
-  KeyDigest                     = 29,
-  LinkDelegation                = 31,
-  LinkPreference                = 30,
+  Interest                        = 5,
+  Data                            = 6,
+  Name                            = 7,
+  GenericNameComponent            = 8,
+  ImplicitSha256DigestComponent   = 1,
+  ParametersSha256DigestComponent = 2,
+  CanBePrefix                     = 33,
+  MustBeFresh                     = 18,
+  ForwardingHint                  = 30,
+  Nonce                           = 10,
+  InterestLifetime                = 12,
+  HopLimit                        = 34,
+  Parameters                      = 35,
+  MetaInfo                        = 20,
+  Content                         = 21,
+  SignatureInfo                   = 22,
+  SignatureValue                  = 23,
+  ContentType                     = 24,
+  FreshnessPeriod                 = 25,
+  FinalBlockId                    = 26,
+  SignatureType                   = 27,
+  KeyLocator                      = 28,
+  KeyDigest                       = 29,
+  LinkDelegation                  = 31,
+  LinkPreference                  = 30,
 
   NameComponentMin = 1,
   NameComponentMax = 65535,
diff --git a/src/name-component.cpp b/src/name-component.cpp
index 6ac6f31..66cf247 100644
--- a/src/name-component.cpp
+++ b/src/name-component.cpp
@@ -307,28 +307,37 @@
 bool
 Component::isImplicitSha256Digest() const
 {
-  return type() == tlv::ImplicitSha256DigestComponent &&
-         value_size() == util::Sha256::DIGEST_SIZE;
+  return detail::getComponentType1().match(*this);
 }
 
 Component
 Component::fromImplicitSha256Digest(ConstBufferPtr digest)
 {
-  if (digest->size() != util::Sha256::DIGEST_SIZE)
-    BOOST_THROW_EXCEPTION(Error("Cannot create ImplicitSha256DigestComponent (input digest must be " +
-                                to_string(util::Sha256::DIGEST_SIZE) + " octets)"));
-
-  return Block(tlv::ImplicitSha256DigestComponent, std::move(digest));
+  return detail::getComponentType1().create(digest);
 }
 
 Component
 Component::fromImplicitSha256Digest(const uint8_t* digest, size_t digestSize)
 {
-  if (digestSize != util::Sha256::DIGEST_SIZE)
-    BOOST_THROW_EXCEPTION(Error("Cannot create ImplicitSha256DigestComponent (input digest must be " +
-                                to_string(util::Sha256::DIGEST_SIZE) + " octets)"));
+  return detail::getComponentType1().create(digest, digestSize);
+}
 
-  return makeBinaryBlock(tlv::ImplicitSha256DigestComponent, digest, digestSize);
+bool
+Component::isParametersSha256Digest() const
+{
+  return detail::getComponentType2().match(*this);
+}
+
+Component
+Component::fromParametersSha256Digest(ConstBufferPtr digest)
+{
+  return detail::getComponentType2().create(digest);
+}
+
+Component
+Component::fromParametersSha256Digest(const uint8_t* digest, size_t digestSize)
+{
+  return detail::getComponentType2().create(digest, digestSize);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/src/name-component.hpp b/src/name-component.hpp
index 9340176..908efe1 100644
--- a/src/name-component.hpp
+++ b/src/name-component.hpp
@@ -462,6 +462,24 @@
   static Component
   fromImplicitSha256Digest(const uint8_t* digest, size_t digestSize);
 
+  /**
+   * @brief Check if the component is ParametersSha256DigestComponent
+   */
+  bool
+  isParametersSha256Digest() const;
+
+  /**
+   * @brief Create ParametersSha256DigestComponent component
+   */
+  static Component
+  fromParametersSha256Digest(ConstBufferPtr digest);
+
+  /**
+   * @brief Create ParametersSha256DigestComponent component
+   */
+  static Component
+  fromParametersSha256Digest(const uint8_t* digest, size_t digestSize);
+
 public: // operators
   bool
   empty() const
@@ -578,7 +596,12 @@
    * - successor of `sha256digest=0000000000000000000000000000000000000000000000000000000000000000`
    *   is `sha256digest=0000000000000000000000000000000000000000000000000000000000000001`.
    * - successor of `sha256digest=ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff`
-   *   is `2=...`.
+   *   is `params-sha256=0000000000000000000000000000000000000000000000000000000000000000`.
+   * - successor of `params-sha256=0000000000000000000000000000000000000000000000000000000000000000`
+   *   is `params-sha256=0000000000000000000000000000000000000000000000000000000000000001`.
+   * - successor of `params-sha256=ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff`
+   *   is `3=...`.
+   * - successor of `...` is `%00`.
    * - successor of `A` is `B`.
    * - successor of `%FF` is `%00%00`.
    */
diff --git a/tests/unit-tests/name-component.t.cpp b/tests/unit-tests/name-component.t.cpp
index 0c9b447..ddd7629 100644
--- a/tests/unit-tests/name-component.t.cpp
+++ b/tests/unit-tests/name-component.t.cpp
@@ -21,9 +21,11 @@
 
 #include "name-component.hpp"
 #include "name.hpp"
+#include "util/string-helper.hpp"
 
 #include "block-literal.hpp"
 #include "boost-test.hpp"
+#include <boost/algorithm/string/case_conv.hpp>
 #include <boost/mpl/vector.hpp>
 
 namespace ndn {
@@ -81,26 +83,39 @@
   BOOST_CHECK_THROW(Component::fromEscapedString(".."), Component::Error);
 }
 
-BOOST_AUTO_TEST_CASE(Digest)
+static void
+testSha256(uint32_t type, const std::string& uriPrefix)
 {
-  std::string uriPrefix = "sha256digest=";
   std::string hexLower = "28bad4b5275bd392dbb670c75cf0b66f13f7942b21e80f55c0e86b374753a548";
-  std::string hexUpper = "28BAD4B5275BD392DBB670C75CF0B66F13F7942B21E80F55C0E86B374753A548";
-  std::string hexPct = "%28%BA%D4%B5%27%5B%D3%92%DB%B6%70%C7%5C%F0%B6%6F"
-                       "%13%F7%94%2B%21%E8%0F%55%C0%E8%6B%37%47%53%A5%48";
+  std::string hexUpper = boost::to_upper_copy(hexLower);
+  std::string hexPct;
+  for (size_t i = 0; i < hexUpper.size(); i += 2) {
+    hexPct += "%" + hexUpper.substr(i, 2);
+  }
 
-  Component comp("0120 28BAD4B5275BD392DBB670C75CF0B66F13F7942B21E80F55C0E86B374753A548"_block);
+  Component comp(Block(type, fromHex(hexLower)));
+  BOOST_CHECK_EQUAL(comp.type(), type);
   BOOST_CHECK_EQUAL(comp.toUri(), uriPrefix + hexLower);
   BOOST_CHECK_EQUAL(Component::fromEscapedString(uriPrefix + hexLower), comp);
   BOOST_CHECK_EQUAL(Component::fromEscapedString(uriPrefix + hexUpper), comp);
-  BOOST_CHECK_EQUAL(Component::fromEscapedString("1=" + hexPct), comp);
+  BOOST_CHECK_EQUAL(Component::fromEscapedString(to_string(type) + "=" + hexPct), comp);
 
-  BOOST_CHECK_THROW(comp.wireDecode("0108 A791806951F25C4D"_block), Component::Error);
+  BOOST_CHECK_THROW(comp.wireDecode(Block(type, fromHex("A791806951F25C4D"))), Component::Error);
   BOOST_CHECK_THROW(Component::fromEscapedString(uriPrefix), Component::Error);
-  BOOST_CHECK_THROW(Component::fromEscapedString(uriPrefix + "=a791806951f25c4d"),
+  BOOST_CHECK_THROW(Component::fromEscapedString(uriPrefix + "a791806951f25c4d"),
                     Component::Error);
-  BOOST_CHECK_THROW(Component::fromEscapedString("1=" + hexLower), Component::Error);
-  BOOST_CHECK_THROW(Component::fromEscapedString("SHA256DIGEST=" + hexLower), Component::Error);
+  BOOST_CHECK_THROW(Component::fromEscapedString(boost::to_upper_copy(uriPrefix) + hexLower),
+                    Component::Error);
+}
+
+BOOST_AUTO_TEST_CASE(Digest)
+{
+  testSha256(tlv::ImplicitSha256DigestComponent, "sha256digest=");
+}
+
+BOOST_AUTO_TEST_CASE(Params)
+{
+  testSha256(tlv::ParametersSha256DigestComponent, "params-sha256=");
 }
 
 BOOST_AUTO_TEST_CASE(OtherType)
@@ -140,7 +155,7 @@
   BOOST_CHECK_THROW(Component::fromEscapedString("0x1=A"), Component::Error);
   BOOST_CHECK_THROW(Component::fromEscapedString("Z=A"), Component::Error);
   BOOST_CHECK_THROW(Component::fromEscapedString("09=A"), Component::Error);
-  BOOST_CHECK_THROW(Component::fromEscapedString("0x2=A"), Component::Error);
+  BOOST_CHECK_THROW(Component::fromEscapedString("0x3=A"), Component::Error);
   BOOST_CHECK_THROW(Component::fromEscapedString("+9=A"), Component::Error);
   BOOST_CHECK_THROW(Component::fromEscapedString(" 9=A"), Component::Error);
   BOOST_CHECK_THROW(Component::fromEscapedString("9 =A"), Component::Error);
@@ -156,10 +171,13 @@
     Component("0120 0000000000000000000000000000000000000000000000000000000000000000"_block),
     Component("0120 0000000000000000000000000000000000000000000000000000000000000001"_block),
     Component("0120 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"_block),
-    Component(0x02),
-    Component("0201 44"_block),
-    Component("0201 46"_block),
-    Component("0202 4141"_block),
+    Component("0220 0000000000000000000000000000000000000000000000000000000000000000"_block),
+    Component("0220 0000000000000000000000000000000000000000000000000000000000000001"_block),
+    Component("0220 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"_block),
+    Component(0x03),
+    Component("0301 44"_block),
+    Component("0301 46"_block),
+    Component("0302 4141"_block),
     Component(),
     Component("D"),
     Component("F"),
diff --git a/tests/unit-tests/name.t.cpp b/tests/unit-tests/name.t.cpp
index 52efb80..061fd56 100644
--- a/tests/unit-tests/name.t.cpp
+++ b/tests/unit-tests/name.t.cpp
@@ -290,7 +290,11 @@
   BOOST_CHECK_EQUAL(Name("/sha256digest=0000000000000000000000000000000000000000000000000000000000000000").getSuccessor(),
                     "/sha256digest=0000000000000000000000000000000000000000000000000000000000000001");
   BOOST_CHECK_EQUAL(Name("/sha256digest=ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").getSuccessor(),
-                    "/2=...");
+                    "/params-sha256=0000000000000000000000000000000000000000000000000000000000000000");
+  BOOST_CHECK_EQUAL(Name("/params-sha256=0000000000000000000000000000000000000000000000000000000000000000").getSuccessor(),
+                    "/params-sha256=0000000000000000000000000000000000000000000000000000000000000001");
+  BOOST_CHECK_EQUAL(Name("/params-sha256=ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").getSuccessor(),
+                    "/3=...");
   BOOST_CHECK_EQUAL(Name("/P/A").getSuccessor(), "/P/B");
   BOOST_CHECK_EQUAL(Name("/P/AAA").getSuccessor(), "/P/AAB");
   BOOST_CHECK_EQUAL(Name("/Q/...").getSuccessor(), "/Q/%00");
@@ -309,19 +313,22 @@
 {
   BOOST_CHECK(Name("/").isPrefixOf("/"));
   BOOST_CHECK(Name("/").isPrefixOf("/sha256digest=0000000000000000000000000000000000000000000000000000000000000000"));
-  BOOST_CHECK(Name("/").isPrefixOf("/2=D"));
+  BOOST_CHECK(Name("/").isPrefixOf("/params-sha256=ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
+  BOOST_CHECK(Name("/").isPrefixOf("/3=D"));
   BOOST_CHECK(Name("/").isPrefixOf("/F"));
   BOOST_CHECK(Name("/").isPrefixOf("/21426=AA"));
 
   BOOST_CHECK(Name("/B").isPrefixOf("/B"));
   BOOST_CHECK(Name("/B").isPrefixOf("/B/sha256digest=0000000000000000000000000000000000000000000000000000000000000000"));
-  BOOST_CHECK(Name("/B").isPrefixOf("/B/2=D"));
+  BOOST_CHECK(Name("/").isPrefixOf("/B/params-sha256=ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
+  BOOST_CHECK(Name("/B").isPrefixOf("/B/3=D"));
   BOOST_CHECK(Name("/B").isPrefixOf("/B/F"));
   BOOST_CHECK(Name("/B").isPrefixOf("/B/21426=AA"));
 
   BOOST_CHECK(!Name("/C").isPrefixOf("/"));
   BOOST_CHECK(!Name("/C").isPrefixOf("/sha256digest=0000000000000000000000000000000000000000000000000000000000000000"));
-  BOOST_CHECK(!Name("/C").isPrefixOf("/2=D"));
+  BOOST_CHECK(Name("/").isPrefixOf("/params-sha256=ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
+  BOOST_CHECK(!Name("/C").isPrefixOf("/3=D"));
   BOOST_CHECK(!Name("/C").isPrefixOf("/F"));
   BOOST_CHECK(!Name("/C").isPrefixOf("/21426=AA"));
 }
@@ -333,19 +340,25 @@
     Name("/sha256digest=0000000000000000000000000000000000000000000000000000000000000000"),
     Name("/sha256digest=0000000000000000000000000000000000000000000000000000000000000001"),
     Name("/sha256digest=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"),
-    Name("/2=..."),
-    Name("/2=D"),
-    Name("/2=F"),
-    Name("/2=AA"),
+    Name("/params-sha256=0000000000000000000000000000000000000000000000000000000000000000"),
+    Name("/params-sha256=0000000000000000000000000000000000000000000000000000000000000001"),
+    Name("/params-sha256=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"),
+    Name("/3=..."),
+    Name("/3=D"),
+    Name("/3=F"),
+    Name("/3=AA"),
     Name("/..."),
     Name("/D"),
     Name("/D/sha256digest=0000000000000000000000000000000000000000000000000000000000000000"),
     Name("/D/sha256digest=0000000000000000000000000000000000000000000000000000000000000001"),
     Name("/D/sha256digest=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"),
-    Name("/D/2=..."),
-    Name("/D/2=D"),
-    Name("/D/2=F"),
-    Name("/D/2=AA"),
+    Name("/D/params-sha256=0000000000000000000000000000000000000000000000000000000000000000"),
+    Name("/D/params-sha256=0000000000000000000000000000000000000000000000000000000000000001"),
+    Name("/D/params-sha256=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"),
+    Name("/D/3=..."),
+    Name("/D/3=D"),
+    Name("/D/3=F"),
+    Name("/D/3=AA"),
     Name("/D/..."),
     Name("/D/D"),
     Name("/D/F"),