security: Add transformation sink/source

Change-Id: I2698f79f639c2bd7c3ce2e00f48be634dc4c983d
Refs: #3009
diff --git a/src/security/transform/bool-sink.cpp b/src/security/transform/bool-sink.cpp
new file mode 100644
index 0000000..1c45c76
--- /dev/null
+++ b/src/security/transform/bool-sink.cpp
@@ -0,0 +1,58 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "bool-sink.hpp"
+
+namespace ndn {
+namespace security {
+namespace transform {
+
+BoolSink::BoolSink(bool& value)
+  : m_hasValue(false)
+  , m_value(value)
+{
+}
+
+size_t
+BoolSink::doWrite(const uint8_t* buf, size_t size)
+{
+  if (!m_hasValue && size > 0) {
+    m_value = (buf[0] != 0);
+    m_hasValue = true;
+  }
+  return size;
+}
+
+void
+BoolSink::doEnd()
+{
+  // nothing to do.
+}
+
+unique_ptr<Sink>
+boolSink(bool& value)
+{
+  return make_unique<BoolSink>(value);
+}
+
+} // namespace transform
+} // namespace security
+} // namespace ndn
diff --git a/src/security/transform/bool-sink.hpp b/src/security/transform/bool-sink.hpp
new file mode 100644
index 0000000..12e62c9
--- /dev/null
+++ b/src/security/transform/bool-sink.hpp
@@ -0,0 +1,73 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_CXX_SECURITY_TRANSFORM_BOOL_SINK_HPP
+#define NDN_CXX_SECURITY_TRANSFORM_BOOL_SINK_HPP
+
+#include "transform-base.hpp"
+
+namespace ndn {
+namespace security {
+namespace transform {
+
+/**
+ * @brief A sink which outputs only one boolean value.
+ *
+ * It checks the first byte that is ever written into the sink,
+ * and set output true if the byte is non-zero, otherwise false.
+ */
+class BoolSink : public Sink
+{
+public:
+  /**
+   * @brief Create a bool sink whose output will be stored in @p value.
+   */
+  explicit
+  BoolSink(bool& value);
+
+private:
+  /**
+   * @brief Check the first byte that is ever received and set the boolean variable.
+   *
+   * @return the same value as @p size.
+   */
+  virtual size_t
+  doWrite(const uint8_t* buf, size_t size) final;
+
+  /**
+   * @brief Finalize sink processing
+   */
+  virtual void
+  doEnd() final;
+
+private:
+  bool m_hasValue;
+  bool& m_value;
+};
+
+unique_ptr<Sink>
+boolSink(bool& value);
+
+} // namespace transform
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_CXX_SECURITY_TRANSFORM_BOOL_SINK_HPP
diff --git a/src/security/transform/buffer-source.cpp b/src/security/transform/buffer-source.cpp
new file mode 100644
index 0000000..b47e855
--- /dev/null
+++ b/src/security/transform/buffer-source.cpp
@@ -0,0 +1,65 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "buffer-source.hpp"
+
+namespace ndn {
+namespace security {
+namespace transform {
+
+BufferSource::BufferSource(const uint8_t* buf, size_t size)
+  : m_buf(buf)
+  , m_size(size)
+{
+}
+
+BufferSource::BufferSource(const std::string& string)
+  : m_buf(reinterpret_cast<const uint8_t*>(string.data()))
+  , m_size(string.size())
+{
+}
+
+BufferSource::BufferSource(const Buffer& buffer)
+  : m_buf(buffer.buf())
+  , m_size(buffer.size())
+{
+}
+
+void
+BufferSource::doPump()
+{
+  BOOST_ASSERT(m_next != nullptr);
+
+  const uint8_t* buf = m_buf;
+  size_t size = m_size;
+
+  while (0 < size) {
+    size_t nBytesWritten = m_next->write(buf, size);
+    buf += nBytesWritten;
+    size -= nBytesWritten;
+  }
+
+  m_next->end();
+}
+
+} // namespace transform
+} // namespace security
+} // namespace ndn
diff --git a/src/security/transform/buffer-source.hpp b/src/security/transform/buffer-source.hpp
new file mode 100644
index 0000000..0833a0f
--- /dev/null
+++ b/src/security/transform/buffer-source.hpp
@@ -0,0 +1,79 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_CXX_SECURITY_TRANSFORM_BUFFER_SOURCE_HPP
+#define NDN_CXX_SECURITY_TRANSFORM_BUFFER_SOURCE_HPP
+
+#include "transform-base.hpp"
+#include "../../encoding/buffer.hpp"
+
+namespace ndn {
+namespace security {
+namespace transform {
+
+/**
+ * @brief A source taking a memory buffer as input
+ */
+class BufferSource : public Source
+{
+public:
+  /**
+   * @brief Take a buffer @p buf with size of @p size as input.
+   *
+   * Caller must not destroy the buffer before transformation is done
+   */
+  BufferSource(const uint8_t* buf, size_t size);
+
+  /**
+   * @brief Take @p string as input.
+   *
+   * Caller must not destroy the string before transformation is done
+   */
+  explicit
+  BufferSource(const std::string& string);
+
+  /**
+   * @brief Take @p buffer as input.
+   *
+   * Caller must not destroy the buffer before transformation is done
+   */
+  explicit
+  BufferSource(const Buffer& buffer);
+
+private:
+  /**
+   * @brief Write the whole buffer into the next module.
+   */
+  virtual void
+  doPump() final;
+
+private:
+  const uint8_t* m_buf;
+  size_t m_size;
+};
+
+typedef BufferSource bufferSource;
+
+} // namespace transform
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_CXX_SECURITY_TRANSFORM_BUFFER_SOURCE_HPP
diff --git a/src/security/transform/step-source.cpp b/src/security/transform/step-source.cpp
new file mode 100644
index 0000000..432ebd9
--- /dev/null
+++ b/src/security/transform/step-source.cpp
@@ -0,0 +1,48 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "step-source.hpp"
+
+namespace ndn {
+namespace security {
+namespace transform {
+
+size_t
+StepSource::write(const uint8_t* buf, size_t size)
+{
+  return m_next->write(buf, size);
+}
+
+void
+StepSource::end()
+{
+  m_next->end();
+}
+
+
+void
+StepSource::doPump()
+{
+}
+
+} // namespace transform
+} // namespace security
+} // namespace ndn
diff --git a/src/security/transform/step-source.hpp b/src/security/transform/step-source.hpp
new file mode 100644
index 0000000..76388f7
--- /dev/null
+++ b/src/security/transform/step-source.hpp
@@ -0,0 +1,82 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_CXX_SECURITY_TRANSFORM_STEP_SOURCE_HPP
+#define NDN_CXX_SECURITY_TRANSFORM_STEP_SOURCE_HPP
+
+#include "transform-base.hpp"
+
+namespace ndn {
+namespace security {
+namespace transform {
+
+/**
+ * @brief A source that can accept input step by step, and can close input explicitly.
+ *
+ * This source will not send data into the transformation chain when the chain is constructed.
+ * Input will be explicitly sent into the chain using write(...) and will be closed explicitly
+ * using end().
+ *
+ *   StepSource ss;
+ *   ss >> transform1() >> transform2() >> sinkStream(...);
+ *   ss.write(...);
+ *   ...
+ *   ss.write(...);
+ *   ss.end();
+ */
+class StepSource : public Source
+{
+public:
+  /**
+   * @brief Accept input data and directly write input into next transformation module.
+   *
+   * One can keep calling this method to until end() is called, which
+   * indicates the end of input.  After that, calling this method will cause Error.
+   *
+   * @return number of bytes that has been written into next module
+   */
+  size_t
+  write(const uint8_t* buf, size_t size);
+
+  /**
+   * @brief Close the input interface and directly notify the next module the end of input
+   */
+  void
+  end();
+
+private:
+  /**
+   * @brief This method intentionally does nothing
+   *
+   * use write() and end() method explicitly to input data.
+   */
+  virtual void
+  doPump() final;
+
+};
+
+typedef StepSource stepSource;
+
+} // namespace transform
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_CXX_SECURITY_TRANSFORM_STEP_SOURCE_HPP
diff --git a/src/security/transform/stream-sink.cpp b/src/security/transform/stream-sink.cpp
new file mode 100644
index 0000000..58208c0
--- /dev/null
+++ b/src/security/transform/stream-sink.cpp
@@ -0,0 +1,59 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "stream-sink.hpp"
+
+namespace ndn {
+namespace security {
+namespace transform {
+
+StreamSink::StreamSink(std::ostream& os)
+  : m_os(os)
+{
+}
+
+size_t
+StreamSink::doWrite(const uint8_t* buf, size_t size)
+{
+  m_os.write(reinterpret_cast<const char*>(buf), size);
+
+  if (m_os.bad())
+    BOOST_THROW_EXCEPTION(Error(getIndex(), "Fail to write data into output stream"));
+
+  return size;
+}
+
+void
+StreamSink::doEnd()
+{
+  m_os.flush();
+}
+
+unique_ptr<Sink>
+streamSink(std::ostream& os)
+{
+  return make_unique<StreamSink>(os);
+}
+
+
+} // namespace transform
+} // namespace security
+} // namespace ndn
diff --git a/src/security/transform/stream-sink.hpp b/src/security/transform/stream-sink.hpp
new file mode 100644
index 0000000..ed41cbd
--- /dev/null
+++ b/src/security/transform/stream-sink.hpp
@@ -0,0 +1,70 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_CXX_SECURITY_TRANSFORM_STREAM_SINK_HPP
+#define NDN_CXX_SECURITY_TRANSFORM_STREAM_SINK_HPP
+
+#include "transform-base.hpp"
+#include <iostream>
+
+namespace ndn {
+namespace security {
+namespace transform {
+
+/**
+ * @brief A sink which directs output to an std::ostream.
+ */
+class StreamSink : public Sink
+{
+public:
+  /**
+   * @brief Create a stream sink which outputs to @p os
+   */
+  explicit
+  StreamSink(std::ostream& os);
+
+private:
+  /**
+   * @brief Write data into the stream
+   *
+   * @return number of bytes that have been written into the stream
+   */
+  virtual size_t
+  doWrite(const uint8_t* buf, size_t size) final;
+
+  /**
+   * @brief Finalize sink processing
+   */
+  virtual void
+  doEnd() final;
+
+private:
+  std::ostream& m_os;
+};
+
+unique_ptr<Sink>
+streamSink(std::ostream& os);
+
+} // namespace transform
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_CXX_SECURITY_TRANSFORM_STREAM_SINK_HPP
diff --git a/src/security/transform/stream-source.cpp b/src/security/transform/stream-source.cpp
new file mode 100644
index 0000000..5248646
--- /dev/null
+++ b/src/security/transform/stream-source.cpp
@@ -0,0 +1,70 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "stream-source.hpp"
+#include <vector>
+
+namespace ndn {
+namespace security {
+namespace transform {
+
+const std::size_t StreamSource::DEFAULT_BUFFER_LEN = 1024;
+
+StreamSource::StreamSource(std::istream& is, size_t bufferSize)
+  : Source()
+  , m_is(is)
+  , m_bufferSize(bufferSize)
+{
+  BOOST_ASSERT(bufferSize > 0);
+}
+
+void
+StreamSource::doPump()
+{
+  BOOST_ASSERT(m_next != nullptr);
+
+  std::vector<uint8_t> buffer(m_bufferSize);
+  size_t dataOffset = 0;
+  size_t dataLen = 0;
+
+  while (dataLen > 0 || !m_is.eof()) {
+    if (dataLen > 0) {
+      // we have some leftover, handle them first
+      size_t nBytesWritten = m_next->write(&buffer[dataOffset], dataLen);
+
+      dataOffset += nBytesWritten;
+      dataLen -= nBytesWritten;
+    }
+    else if (m_is.bad()) {
+      BOOST_THROW_EXCEPTION(Error(getIndex(), "Input stream in bad state"));
+    }
+    else if (m_is.good()) {
+      m_is.read(reinterpret_cast<char*>(&buffer.front()), buffer.size());
+      dataOffset = 0;
+      dataLen = m_is.gcount();
+    }
+  }
+  m_next->end();
+}
+
+} // namespace transform
+} // namespace security
+} // namespace ndn
diff --git a/src/security/transform/stream-source.hpp b/src/security/transform/stream-source.hpp
new file mode 100644
index 0000000..b818fe7
--- /dev/null
+++ b/src/security/transform/stream-source.hpp
@@ -0,0 +1,69 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_CXX_SECURITY_TRANSFORM_STREAM_SOURCE_HPP
+#define NDN_CXX_SECURITY_TRANSFORM_STREAM_SOURCE_HPP
+
+#include "transform-base.hpp"
+#include <iostream>
+
+namespace ndn {
+namespace security {
+namespace transform {
+
+/**
+ * @brief A source taking an std::istream as input
+ */
+class StreamSource : public Source
+{
+public:
+  /**
+   * @brief Construst a source using @p is as input.
+   *
+   * @param is The input stream
+   * @param bufLen The internal buffer size. The default size is 1024.
+   * @pre bufLen must be larger than 0.
+   */
+  explicit
+  StreamSource(std::istream& is, size_t bufLen = DEFAULT_BUFFER_LEN);
+
+private:
+  /**
+   * @brief Read bytes from the input stream until EOF is reached and write them into the next module.
+   */
+  virtual void
+  doPump() final;
+
+public:
+  static const std::size_t DEFAULT_BUFFER_LEN;
+
+private:
+  std::istream& m_is;
+  size_t m_bufferSize;
+};
+
+typedef StreamSource streamSource;
+
+} // namespace transform
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_CXX_SECURITY_TRANSFORM_STREAM_SOURCE_HPP
diff --git a/src/security/transform/transform-base.cpp b/src/security/transform/transform-base.cpp
new file mode 100644
index 0000000..85df6b9
--- /dev/null
+++ b/src/security/transform/transform-base.cpp
@@ -0,0 +1,110 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "transform-base.hpp"
+
+namespace ndn {
+namespace security {
+namespace transform {
+
+Error::Error(size_t index, const std::string& what)
+  : std::runtime_error("Error in module " + std::to_string(index) + ": " + what)
+  , m_index(index)
+{
+}
+
+Downstream::Downstream()
+  : m_isEnd(false)
+{
+}
+
+size_t
+Downstream::write(const uint8_t* buf, size_t size)
+{
+  if (m_isEnd)
+    BOOST_THROW_EXCEPTION(Error(getIndex(), "Module is closed, no more input"));
+
+  size_t nBytesWritten = doWrite(buf, size);
+  BOOST_ASSERT(nBytesWritten <= size);
+  return nBytesWritten;
+}
+
+void
+Downstream::end()
+{
+  if (m_isEnd)
+    return;
+
+  m_isEnd = true;
+  return doEnd();
+}
+
+Upstream::Upstream()
+  : m_next(nullptr)
+{
+}
+
+void
+Upstream::appendChain(unique_ptr<Downstream> tail)
+{
+  if (m_next == nullptr) {
+    m_next = std::move(tail);
+  }
+  else {
+    BOOST_ASSERT(dynamic_cast<Transform*>(m_next.get()) != nullptr);
+    static_cast<Transform*>(m_next.get())->appendChain(std::move(tail));
+  }
+}
+
+Source::Source()
+  : m_nModules(1) // source per se is counted as one module
+{
+}
+
+void
+Source::pump()
+{
+  doPump();
+}
+
+Source&
+Source::operator>>(unique_ptr<Transform> transform)
+{
+  transform->setIndex(m_nModules);
+  m_nModules++;
+  this->appendChain(std::move(transform));
+
+  return *this;
+}
+
+void
+Source::operator>>(unique_ptr<Sink> sink)
+{
+  sink->setIndex(m_nModules);
+  m_nModules++;
+  this->appendChain(std::move(sink));
+
+  this->pump();
+}
+
+} // namespace transform
+} // namespace security
+} // namespace ndn
diff --git a/src/security/transform/transform-base.hpp b/src/security/transform/transform-base.hpp
new file mode 100644
index 0000000..7f64145
--- /dev/null
+++ b/src/security/transform/transform-base.hpp
@@ -0,0 +1,249 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2016 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_CXX_SECURITY_TRANSFORM_BASE_HPP
+#define NDN_CXX_SECURITY_TRANSFORM_BASE_HPP
+
+#include "../../common.hpp"
+
+namespace ndn {
+namespace security {
+namespace transform {
+
+/**
+ * @file transform-base.hpp
+ *
+ * There are three types of module in a transformation chain: Source, Transform, and Sink.
+ * The ideal usage of the transformation would be:
+ *
+ *   source(...) >> transform1(...) >> transform2(...) >> sink(...);
+ *
+ * When error happens in a module, the module will throw out a transform::Error, one
+ * can get the location of the module through the getIndex() method of transform::Error.
+ */
+
+/**
+ * @brief Base class of transformation error
+ */
+class Error : public std::runtime_error
+{
+public:
+  Error(size_t index, const std::string& what);
+
+  size_t
+  getIndex() const
+  {
+    return m_index;
+  }
+
+private:
+  size_t m_index;
+};
+
+/**
+ * @brief The downstream interface of a transformation module
+ *
+ * A module can accept input through this interface
+ */
+class Downstream
+{
+public:
+  /**
+   * @brief Accept input data and perform transformation.
+   *
+   * An upstream module should call this method to write data into this module.
+   * The written data will be transformed and the result will be written into the next
+   * downstream module.
+   *
+   * An upstream module can keep calling this method to until end() is called, which
+   * indicates the end of input.  After that, calling this method will cause Error.
+   *
+   * If a Downstream implementation expects structured input (e.g., hex decoding requires byte-pair),
+   * it should not return less than size if final portion of input is not a complete record.
+   *
+   * @return number of bytes that has been written into this module
+   * @throws Error if this module is closed or transformation error happens.
+   */
+  size_t
+  write(const uint8_t* buf, size_t size);
+
+  /**
+   * @brief Close the input interface of a module.
+   *
+   * This method will notify this module that there is no more input and that the module
+   * should finalize transformation.
+   *
+   * Although end() can be invoked multiple times, only the first invocation takes effect.
+   */
+  void
+  end();
+
+  /**
+   * @brief Check if the input interface of a module is closed.
+   */
+  bool
+  isEnd() const
+  {
+    return m_isEnd;
+  }
+
+  /**
+   * @brief Set the module index.
+   */
+  void
+  setIndex(size_t index)
+  {
+    m_index = index;
+  }
+
+  /**
+   * @brief Get the module index.
+   */
+  size_t
+  getIndex() const
+  {
+    return m_index;
+  }
+
+protected:
+  Downstream();
+
+private:
+  /**
+   * @brief Internal implementation of write method
+   */
+  virtual size_t
+  doWrite(const uint8_t* buf, size_t size) = 0;
+
+  /**
+   * @brief Internal implementation of end method
+   */
+  virtual void
+  doEnd() = 0;
+
+private:
+  bool m_isEnd;
+  size_t m_index;
+};
+
+/**
+ * @brief The upstream interface of a transformation module
+ *
+ * A module can construct subsequent transformation chain through this interface.
+ */
+class Upstream
+{
+protected:
+  Upstream();
+
+protected:
+  /**
+   * @brief connect to next transformation module
+   */
+  void
+  appendChain(unique_ptr<Downstream> tail);
+
+  Downstream*
+  getNext()
+  {
+    return m_next.get();
+  }
+
+protected:
+  unique_ptr<Downstream> m_next;
+};
+
+/**
+ * @brief Abstraction of an intermediate transformation module
+ */
+class Transform : public Upstream,
+                  public Downstream,
+                  noncopyable
+{
+};
+
+/**
+ * @brief Abstraction of the transformation sink module
+ *
+ * This module does not have next module and can only accept input data
+ */
+class Sink : public Downstream,
+             noncopyable
+{
+};
+
+/**
+ * @brief Abstraction of the transformation source module
+ *
+ * This module can only accept input data from constructor
+ */
+class Source : public Upstream,
+               noncopyable
+{
+public:
+  /**
+   * @brief Connect to an intermediate transformation module.
+   */
+  Source&
+  operator>>(unique_ptr<Transform> transform);
+
+  /**
+   * @brief Connect to the last transformation module.
+   *
+   * This method will trigger the source to pump data into the transformation pipeline.
+   */
+  void
+  operator>>(unique_ptr<Sink> sink);
+
+protected:
+  Source();
+
+  /**
+   * @brief Pump all data into next transformation module.
+   */
+  void
+  pump();
+
+  /**
+   * @brief Get the source module index (should always be 0).
+   */
+  size_t
+  getIndex() const
+  {
+    return 0;
+  }
+
+private:
+  /**
+   * @brief Internal implementation of pump().
+   */
+  virtual void
+  doPump() = 0;
+
+private:
+  size_t m_nModules; // count of modules in the chain starting from this Source
+};
+
+} // namespace transform
+} // namespace security
+} // namespace ndn
+
+#endif // NDN_CXX_SECURITY_TRANSFORM_BASE_HPP