tools: Adding tlvdump app that visualizes TLV encoding stored in files

Change-Id: Iae29f56d5ab567653055dbbb8005f4bc10ae0dc0
diff --git a/.gitignore b/.gitignore
index ae3de42..9da7ccd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -72,3 +72,6 @@
 # Tests using Boost's unit test framework
 tests_boost/unit-tests
 
+# Tools
+tools/tlvdump
+
diff --git a/Makefile.am b/Makefile.am
index 57ac38d..767081d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -12,7 +12,7 @@
 lib_LTLIBRARIES = libndn-c.la libndn-cpp.la
 
 # "make install" will also install the include headers.
-SUBDIRS = include .
+SUBDIRS = include . tools
 
 if COMPILE_TESTS
   SUBDIRS += tests
diff --git a/configure.ac b/configure.ac
index 1bac2be..9a67273 100644
--- a/configure.ac
+++ b/configure.ac
@@ -155,6 +155,7 @@
 
 AC_CONFIG_FILES([Makefile
                  include/Makefile
+                 tools/Makefile
                  tests/Makefile
                  tests_boost/Makefile])
 AC_OUTPUT
diff --git a/tools/Makefile.am b/tools/Makefile.am
new file mode 100644
index 0000000..a1a0094
--- /dev/null
+++ b/tools/Makefile.am
@@ -0,0 +1,6 @@
+
+bin_PROGRAMS=tlvdump
+
+tlvdump_SOURCES = tlvdump.cpp
+
+tlvdump_LDADD = ../libndn-cpp.la @BOOST_SYSTEM_LIB@
diff --git a/tools/tlvdump.cpp b/tools/tlvdump.cpp
new file mode 100644
index 0000000..0c5f4bb
--- /dev/null
+++ b/tools/tlvdump.cpp
@@ -0,0 +1,160 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/**
+ * Copyright (C) 2013 Regents of the University of California.
+ * @author: Jeff Thompson <jefft0@remap.ucla.edu>
+ * See COPYING for copyright and distribution information.
+ */
+
+#include <ndn-cpp/face.hpp>
+#include <ndn-cpp/encoding/block.hpp>
+
+#include <iomanip>
+#include <fstream>
+
+const int TLV_DICT_SIZE = 25;
+
+const std::string TLV_DICT[TLV_DICT_SIZE] = {
+  "RESERVED", //      = 0
+  "Interest", //      = 1,
+  "Data", //          = 2,
+  "Name", //          = 3,
+  "NameComponent", // = 4,
+  "Selectors", //     = 5,
+  "Nonce", //         = 6,
+  "Scope", //         = 7,
+  "InterestLifetime", //          = 8,
+  "MinSuffixComponents", //       = 9,
+  "MaxSuffixComponents", //       = 10,
+  "PublisherPublicKeyLocator", // = 11,
+  "Exclude", //       = 12,
+  "ChildSelector", // = 13,
+  "MustBeFresh", //   = 14,
+  "Any", //           = 15,
+  "MetaInfo", //      = 16,
+  "Content", //       = 17,
+  "SignatureInfo", // = 18,
+  "SignatureValue", // = 19,
+  "ContentType", //   = 20,
+  "FreshnessPeriod", // = 21,
+  "SignatureType", // = 22,
+  "KeyLocator", //    = 23,
+  "KeyLocatorDigest", // = 24
+};
+
+void
+printTypeInfo(uint32_t type)
+{
+  std::cout << type << " (";
+
+  if (type < TLV_DICT_SIZE) {
+    std::cout << TLV_DICT[type];
+  }
+  else if (TLV_DICT_SIZE <= type && type < 128) {
+    std::cout << "RESERVED_1";
+  }
+  else if (128 <= type && type < 253) {
+    std::cout << "APP_TAG_1";
+  }
+  else if (253 <= type && type < 32767) {
+    std::cout << "RESERVED_3";
+  }
+  else {
+    std::cout << "APP_TAG_3";
+  }
+  std::cout << ")";
+}
+
+  
+void
+BlockPrinter(ndn::Block &block, const std::string &indent="")
+{
+  std::cout << indent;
+  printTypeInfo(block.type());
+  std::cout << " (size: " << block.value_size() << ")";
+
+  try {
+    // if (block.type() != ndn::Tlv::Content && block.type() != ndn::Tlv::SignatureValue)
+    block.parse();
+  }
+  catch(ndn::Tlv::Error &e) {
+    // pass (e.g., leaf block reached)
+
+    // @todo: Figure how to deterministically figure out that value is not recursive TLV block
+  }
+
+  if (block.getAll().empty())
+    {
+      std::cout << " [[";
+      ndn::Name::toEscapedString(block.value(), block.value_size(), std::cout);
+      std::cout<< "]]";
+    }
+  std::cout << std::endl;
+  
+  for(ndn::Block::element_iterator i = block.getAll().begin();
+      i != block.getAll().end();
+      ++i)
+    {
+      BlockPrinter(*i, indent+"  ");
+    }
+}
+
+void
+HexPrinter(ndn::Block &block, const std::string &indent="")
+{
+  std::cout << indent;
+  for (ndn::Buffer::const_iterator i = block.begin (); i != block.value_begin(); ++i)
+    {
+      std::cout << "0x" << std::noshowbase << std::hex << std::setw(2) << std::setfill('0') << (int)*i;
+      std::cout << ", ";
+    }
+  std::cout << "\n";
+  
+  if (block.getAll().size() == 0 && block.value_size() > 0)
+    {
+      std::cout << indent << "    ";
+      for (ndn::Buffer::const_iterator i = block.value_begin (); i != block.value_end(); ++i)
+      {
+        std::cout << "0x" << std::noshowbase << std::hex << std::setw(2) << std::setfill('0') << (int)*i;
+        std::cout << ", ";
+      }
+      std::cout << "\n";
+    }
+  else
+    {
+      for(ndn::Block::element_iterator i = block.getAll().begin();
+          i != block.getAll().end();
+          ++i)
+        {
+          HexPrinter(*i, indent+"    ");
+        }
+    }
+}
+
+int main(int argc, const char *argv[])
+{
+  unsigned char buf[9000];
+  std::streamsize s = 0;
+  if (argc == 1 ||
+      (argc == 2 && std::string(argv[1]) == "-"))
+    {
+      std::cin.read(reinterpret_cast<char*>(buf), 9000);
+      s = std::cin.gcount();
+    }
+  else
+    {
+      std::ifstream file(argv[1]);
+      file.read(reinterpret_cast<char*>(buf), 9000);
+      s = file.gcount();
+    }
+
+  try {
+    ndn::Block block(buf, s);
+    BlockPrinter(block, "");
+    // HexPrinter(block, "");
+  }
+  catch(std::exception &e) {
+    std::cerr << "ERROR: "<< e.what() << std::endl;
+  }
+  
+  return 0;
+}