encoding: Add TLV-related definitions, data structures, abstraction, and functions

Change-Id: I2dbdd5ae17f1f60cdd65b7e46e5b43b25c7f025c
diff --git a/include/ndn-cpp/encoding/block.hpp b/include/ndn-cpp/encoding/block.hpp
new file mode 100644
index 0000000..6d104b1
--- /dev/null
+++ b/include/ndn-cpp/encoding/block.hpp
@@ -0,0 +1,377 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_BLOCK_HPP
+#define NDN_BLOCK_HPP
+
+#include <ndn-cpp/common.hpp>
+
+#include <list>
+#include <exception>
+
+#include "buffer.hpp"
+#include "tlv.hpp"
+
+#include <boost/lexical_cast.hpp>
+
+namespace ndn {
+
+/**
+ * @brief Class representing wire element of the NDN packet
+ */
+class Block
+{
+public:
+  typedef std::list<Block>::iterator element_iterator;
+  typedef std::list<Block>::const_iterator element_const_iterator;
+
+  /// @brief Error that can be thrown from the block
+  struct Error : public std::runtime_error { Error(const std::string &what) : std::runtime_error(what) {} };
+  
+  /**
+   * @brief Default constructor to create an empty Block
+   */
+  Block();
+
+  /**
+   * @brief A helper version of a constructor to create Block from the raw buffer (type and value-length parsing)
+   */
+  Block(const ConstBufferPtr &buffer);
+
+  /**
+   * @brief A helper version of a constructor to create Block from the raw buffer (type and value-length parsing)
+   */
+  Block(const uint8_t *buffer, size_t maxlength);
+
+  Block(const void *buffer, size_t maxlength);
+  
+  /**
+   * @brief Create Block from the wire buffer (no parsing)
+   *
+   * This version of the constructor does not do any parsing
+   */
+  Block(const ConstBufferPtr &wire,
+        uint32_t type,
+        const Buffer::const_iterator &begin, Buffer::const_iterator &end,
+        const Buffer::const_iterator &valueBegin, Buffer::const_iterator &valueEnd);
+
+  /**
+   * @brief Create Block of a specific type with empty wire buffer
+   */
+  Block(uint32_t type);
+
+  /**
+   * @brief Create Block of a specific type with the specified value
+   *
+   * The underlying buffer hold only value, additional operations are needed
+   * to construct wire encoding, one need to prepend the wire buffer with type
+   * and value-length VAR-NUMBERs
+   */
+  Block(uint32_t type, const ConstBufferPtr &value);
+
+  /**
+   * @brief Create nested Block of a specific type with the specified value
+   *
+   * The underlying buffer hold only value, additional operations are needed
+   * to construct wire encoding, one need to prepend the wire buffer with type
+   * and value-length VAR-NUMBERs
+   */
+  Block(uint32_t type, const Block &value);
+  
+  /**
+   * @brief Check if the Block has fully encoded wire
+   */
+  inline bool
+  hasWire() const;
+
+  /**
+   * @brief Check if the Block has value block (no type and length are encoded)
+   */
+  inline bool
+  hasValue() const;
+  
+  /**
+   * @brief Reset wire buffer of the element
+   */
+  inline void
+  reset();
+
+  void
+  parse();
+
+  void
+  encode();
+  
+  inline uint32_t
+  type() const;
+
+  /**
+   * @brief Get the first subelement of the requested type
+   */
+  inline const Block &
+  get(uint32_t type) const;
+
+  inline Block &
+  get(uint32_t type);
+  
+  inline element_iterator
+  find(uint32_t type);
+
+  inline element_const_iterator
+  find(uint32_t type) const;
+
+  inline void
+  push_back(const Block &element);
+  
+  /**
+   * @brief Get all subelements
+   */
+  inline const std::list<Block>&
+  getAll () const;
+
+  inline std::list<Block>&
+  getAll ();
+  
+  /**
+   * @brief Get all elements of the requested type
+   */
+  std::list<Block>
+  getAll(uint32_t type) const;
+
+  inline Buffer::const_iterator
+  begin() const;
+
+  inline Buffer::const_iterator
+  end() const;
+
+  inline size_t
+  size() const;
+
+  inline Buffer::const_iterator
+  value_begin() const;
+
+  inline Buffer::const_iterator
+  value_end() const;
+
+  inline const uint8_t*
+  wire() const;
+  
+  inline const uint8_t*
+  value() const;
+
+  inline size_t
+  value_size() const;
+
+protected:
+  ConstBufferPtr m_buffer;
+
+  uint32_t m_type;
+  
+  Buffer::const_iterator m_begin;
+  Buffer::const_iterator m_end;
+  uint32_t m_size;
+  
+  Buffer::const_iterator m_value_begin;
+  Buffer::const_iterator m_value_end;
+
+  std::list<Block> m_subBlocks;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+inline bool
+Block::hasWire() const
+{
+  return m_buffer && (m_begin != m_end);
+}
+
+inline bool
+Block::hasValue() const
+{
+  return static_cast<bool>(m_buffer);
+}
+
+inline void
+Block::reset()
+{
+  m_buffer.reset(); // reset of the shared_ptr
+  m_subBlocks.clear(); // remove all parsed subelements
+
+  m_type = std::numeric_limits<uint32_t>::max();
+  m_begin = m_end = m_value_begin = m_value_end = Buffer::const_iterator(); // not really necessary, but for safety
+}
+
+inline uint32_t
+Block::type() const
+{
+  return m_type;
+}
+
+inline const Block &
+Block::get(uint32_t type) const
+{
+  for (element_const_iterator i = m_subBlocks.begin ();
+       i != m_subBlocks.end();
+       i++)
+    {
+      if (i->type () == type)
+        {
+          return *i;
+        }
+    }
+
+  throw Error("(Block::get) Requested a non-existed type [" + boost::lexical_cast<std::string>(type) + "] from Block");
+}
+
+inline Block &
+Block::get(uint32_t type)
+{
+  for (element_iterator i = m_subBlocks.begin ();
+       i != m_subBlocks.end();
+       i++)
+    {
+      if (i->type () == type)
+        {
+          return *i;
+        }
+    }
+
+  throw Error("(Block::get) Requested a non-existed type [" + boost::lexical_cast<std::string>(type) + "] from Block");
+}
+  
+inline Block::element_const_iterator
+Block::find(uint32_t type) const
+{
+  for (element_const_iterator i = m_subBlocks.begin ();
+       i != m_subBlocks.end();
+       i++)
+    {
+      if (i->type () == type)
+        {
+          return i;
+        }
+    }
+  return m_subBlocks.end();
+}
+
+inline Block::element_iterator
+Block::find(uint32_t type)
+{
+  for (element_iterator i = m_subBlocks.begin ();
+       i != m_subBlocks.end();
+       i++)
+    {
+      if (i->type () == type)
+        {
+          return i;
+        }
+    }
+  return m_subBlocks.end();
+}
+
+inline void
+Block::push_back(const Block &element)
+{
+  m_subBlocks.push_back(element);
+}
+
+
+inline const std::list<Block>&
+Block::getAll () const
+{
+  return m_subBlocks;
+}
+
+inline std::list<Block>&
+Block::getAll ()
+{
+  return m_subBlocks;
+}
+
+
+inline Buffer::const_iterator
+Block::begin() const
+{
+  if (!hasWire())
+      throw Error("Underlying wire buffer is empty");
+
+  return m_begin;
+}
+
+inline Buffer::const_iterator
+Block::end() const
+{
+  if (!hasWire())
+      throw Error("Underlying wire buffer is empty");
+
+  return m_end;
+}
+
+inline size_t
+Block::size() const
+{
+  if (hasWire() || hasValue()) {
+    return m_size;
+  }
+  else
+    throw Error("Block size cannot be determined (undefined block size)");
+}
+
+inline Buffer::const_iterator
+Block::value_begin() const
+{
+  if (!hasValue())
+      throw Error("(Block::value_begin) Underlying value buffer is empty");
+
+  return m_value_begin;
+}
+
+inline Buffer::const_iterator
+Block::value_end() const
+{
+  if (!hasValue())
+      throw Error("(Block::value_end) Underlying value buffer is empty");
+
+  return m_value_end;
+}
+
+inline const uint8_t*
+Block::wire() const
+{
+  if (!hasWire())
+      throw Error("(Block::wire) Underlying wire buffer is empty");
+
+  return &*m_begin;
+}
+
+inline const uint8_t*
+Block::value() const
+{
+  if (!hasValue())
+      throw Error("(Block::value) Underlying value buffer is empty");
+  
+  return &*m_value_begin;
+}
+
+inline size_t
+Block::value_size() const
+{
+  if (!hasValue())
+    throw Error("(Block::value_size) Underlying value buffer is empty");
+
+  return m_value_end - m_value_begin;
+}
+
+} // ndn
+
+#include "block-helpers.hpp"
+
+#endif // NDN_BLOCK_HPP