data: recognize Data in Packet Format v0.3

Data::wireDecode accepts both v0.2 and v0.3 formats,
but Data::wireEncode only encodes into v0.2 format.

refs #4568

Change-Id: I287d12c599f44d802a2a2cd2f13132c9f98a842a
diff --git a/src/data.cpp b/src/data.cpp
index 6b50dca..090b82d 100644
--- a/src/data.cpp
+++ b/src/data.cpp
@@ -49,8 +49,8 @@
 {
   // Data ::= DATA-TLV TLV-LENGTH
   //            Name
-  //            MetaInfo
-  //            Content
+  //            MetaInfo?
+  //            Content?
   //            SignatureInfo
   //            SignatureValue
 
@@ -121,26 +121,75 @@
 void
 Data::wireDecode(const Block& wire)
 {
-  m_fullName.clear();
   m_wire = wire;
   m_wire.parse();
+  bool hasName = false, hasSigInfo = false;
+  m_name.clear();
+  m_metaInfo = MetaInfo();
+  m_content = Block(tlv::Content);
+  m_signature = Signature();
+  m_fullName.clear();
 
-  // Name
-  m_name.wireDecode(m_wire.get(tlv::Name));
+  int lastEle = 0; // last recognized element index, in spec order
+  for (const Block& ele : m_wire.elements()) {
+    switch (ele.type()) {
+      case tlv::Name: {
+        if (lastEle >= 1) {
+          BOOST_THROW_EXCEPTION(Error("Name element is out of order"));
+        }
+        hasName = true;
+        m_name.wireDecode(ele);
+        lastEle = 1;
+        break;
+      }
+      case tlv::MetaInfo: {
+        if (lastEle >= 2) {
+          BOOST_THROW_EXCEPTION(Error("MetaInfo element is out of order"));
+        }
+        m_metaInfo.wireDecode(ele);
+        lastEle = 2;
+        break;
+      }
+      case tlv::Content: {
+        if (lastEle >= 3) {
+          BOOST_THROW_EXCEPTION(Error("Content element is out of order"));
+        }
+        m_content = ele;
+        lastEle = 3;
+        break;
+      }
+      case tlv::SignatureInfo: {
+        if (lastEle >= 4) {
+          BOOST_THROW_EXCEPTION(Error("SignatureInfo element is out of order"));
+        }
+        hasSigInfo = true;
+        m_signature.setInfo(ele);
+        lastEle = 4;
+        break;
+      }
+      case tlv::SignatureValue: {
+        if (lastEle >= 5) {
+          BOOST_THROW_EXCEPTION(Error("SignatureValue element is out of order"));
+        }
+        m_signature.setValue(ele);
+        lastEle = 5;
+        break;
+      }
+      default: {
+        if (tlv::isCriticalType(ele.type())) {
+          BOOST_THROW_EXCEPTION(Error("unrecognized element of critical type " +
+                                      to_string(ele.type())));
+        }
+        break;
+      }
+    }
+  }
 
-  // MetaInfo
-  m_metaInfo.wireDecode(m_wire.get(tlv::MetaInfo));
-
-  // Content
-  m_content = m_wire.get(tlv::Content);
-
-  // 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);
+  if (!hasName) {
+    BOOST_THROW_EXCEPTION(Error("Name element is missing"));
+  }
+  if (!hasSigInfo) {
+    BOOST_THROW_EXCEPTION(Error("SignatureInfo element is missing"));
   }
 }