encoding: Construct Block from istream
Change-Id: Iee330e861197e9c347fd7c15a887c2b9fc5552be
diff --git a/include/ndn-cpp-dev/encoding/block.hpp b/include/ndn-cpp-dev/encoding/block.hpp
index 85cdaf5..de8c5a5 100644
--- a/include/ndn-cpp-dev/encoding/block.hpp
+++ b/include/ndn-cpp-dev/encoding/block.hpp
@@ -50,6 +50,11 @@
Block(const uint8_t *buffer, size_t maxlength);
Block(const void *buffer, size_t maxlength);
+
+ /*
+ * @brief A helper version of a constructor to create Block from the stream.
+ */
+ Block(std::istream& is);
/**
* @brief Create Block from the wire buffer (no parsing)
diff --git a/include/ndn-cpp-dev/encoding/tlv.hpp b/include/ndn-cpp-dev/encoding/tlv.hpp
index dfa11fe..3d42402 100644
--- a/include/ndn-cpp-dev/encoding/tlv.hpp
+++ b/include/ndn-cpp-dev/encoding/tlv.hpp
@@ -11,6 +11,7 @@
#define NDN_TLV_HPP
#include <stdexcept>
+#include <iterator>
#include "buffer.hpp"
#include "endian.h"
@@ -176,6 +177,73 @@
}
}
+template<>
+inline uint64_t
+readVarNumber<std::istream_iterator<uint8_t> >(std::istream_iterator<uint8_t> &begin,
+ const std::istream_iterator<uint8_t> &end)
+{
+ if (begin == end)
+ throw Error("Empty buffer during TLV processing");
+
+ uint8_t value = *begin;
+ ++begin;
+ if (value < 253)
+ {
+ return value;
+ }
+ else if (value == 253)
+ {
+ uint8_t buffer[2];
+ int count = 0;
+
+ while(begin != end && count < 2){
+ buffer[count] = *begin;
+ begin++;
+ count++;
+ }
+
+ if (count < 2)
+ throw Error("Insufficient data during TLV processing");
+
+ uint16_t value = *reinterpret_cast<const uint16_t*>(buffer);
+ return be16toh(value);
+ }
+ else if (value == 254)
+ {
+ uint8_t buffer[4];
+ int count = 0;
+
+ while(begin != end && count < 4){
+ buffer[count] = *begin;
+ begin++;
+ count++;
+ }
+
+ if (count < 4)
+ throw Error("Insufficient data during TLV processing");
+
+ uint32_t value = *reinterpret_cast<const uint32_t*>(buffer);
+ return be32toh(value);
+ }
+ else // if (value == 255)
+ {
+ uint8_t buffer[8];
+ int count = 0;
+
+ while(begin != end && count < 8){
+ buffer[count] = *begin;
+ begin++;
+ count++;
+ }
+
+ if (count < 8)
+ throw Error("Insufficient data during TLV processing");
+
+ uint64_t value = *reinterpret_cast<const uint64_t*>(buffer);
+ return be64toh(value);
+ }
+}
+
template<class InputIterator>
inline uint32_t
readType(InputIterator &begin, const InputIterator &end)
@@ -278,6 +346,77 @@
throw Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)");
}
+template<>
+inline uint64_t
+readNonNegativeInteger<std::istream_iterator<uint8_t> >(size_t size,
+ std::istream_iterator<uint8_t> &begin,
+ const std::istream_iterator<uint8_t> &end)
+{
+ switch (size) {
+ case 1:
+ {
+ if(begin == end)
+ throw Error("Insufficient data during TLV processing");
+
+ uint8_t value = *begin;
+ begin++;
+ return value;
+ }
+ case 2:
+ {
+ uint8_t buffer[2];
+ int count = 0;
+
+ while(begin != end && count < 2){
+ buffer[count] = *begin;
+ begin++;
+ count++;
+ }
+
+ if (count < 2)
+ throw Error("Insufficient data during TLV processing");
+
+ uint16_t value = *reinterpret_cast<const uint16_t*>(buffer);
+ return be16toh(value);
+ }
+ case 4:
+ {
+ uint8_t buffer[4];
+ int count = 0;
+
+ while(begin != end && count < 4){
+ buffer[count] = *begin;
+ begin++;
+ count++;
+ }
+
+ if (count < 4)
+ throw Error("Insufficient data during TLV processing");
+
+ uint32_t value = *reinterpret_cast<const uint32_t*>(buffer);
+ return be32toh(value);
+ }
+ case 8:
+ {
+ uint8_t buffer[8];
+ int count = 0;
+
+ while(begin != end && count < 8){
+ buffer[count] = *begin;
+ begin++;
+ count++;
+ }
+
+ if (count < 8)
+ throw Error("Insufficient data during TLV processing");
+
+ uint64_t value = *reinterpret_cast<const uint64_t*>(buffer);
+ return be64toh(value);
+ }
+ }
+ throw Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)");
+}
+
inline size_t
sizeOfNonNegativeInteger(uint64_t varNumber)
{
diff --git a/src/encoding/block.cpp b/src/encoding/block.cpp
index 7fab48f..4b41ebc 100644
--- a/src/encoding/block.cpp
+++ b/src/encoding/block.cpp
@@ -49,6 +49,44 @@
}
}
+Block::Block(std::istream& is)
+{
+ std::istream_iterator<uint8_t> tmp_begin(is);
+ std::istream_iterator<uint8_t> tmp_end;
+
+ m_type = Tlv::readType(tmp_begin, tmp_end);
+ uint64_t length = Tlv::readVarNumber(tmp_begin, tmp_end);
+
+ // We may still have some problem here, if some exception happens in this constructor, we may completely lose all the bytes extracted from the stream.
+
+ OBufferStream os;
+ size_t headerLength = Tlv::writeVarNumber(os, m_type);
+ headerLength += Tlv::writeVarNumber(os, length);
+
+ char* buf = new char[length];
+ buf[0] = *tmp_begin;
+ is.read(buf+1, length-1);
+
+ if(length-1 != is.gcount())
+ {
+ delete [] buf;
+ throw Tlv::Error("Not enough data in the buffer to fully parse TLV");
+ }
+
+ os.write(buf, length);
+ delete [] buf;
+
+ m_buffer = os.buf();
+
+ m_begin = m_buffer->begin();
+ m_end = m_buffer->end();
+ m_size = m_end - m_begin;
+
+ m_value_begin = m_buffer->begin() + headerLength;
+ m_value_end = m_buffer->end();
+}
+
+
Block::Block(const uint8_t *buffer, size_t maxlength)
{
const uint8_t * tmp_begin = buffer;
diff --git a/tests_boost/Makefile.am b/tests_boost/Makefile.am
index dadf1c1..3564e82 100644
--- a/tests_boost/Makefile.am
+++ b/tests_boost/Makefile.am
@@ -7,6 +7,7 @@
test-encode-decode-certificate.cpp \
test-encode-decode-data.cpp \
test-encode-decode-interest.cpp \
- test-encode-decode-forwarding-entry.cpp
+ test-encode-decode-forwarding-entry.cpp \
+ test-encode-decode-block.cpp
unit_tests_LDADD = ../libndn-cpp-dev.la @BOOST_SYSTEM_LIB@ @BOOST_UNIT_TEST_FRAMEWORK_LIB@ @OPENSSL_LIBS@ @CRYPTOPP_LIBS@ @OSX_SECURITY_LIBS@
diff --git a/tests_boost/test-encode-decode-block.cpp b/tests_boost/test-encode-decode-block.cpp
new file mode 100644
index 0000000..f14b83a
--- /dev/null
+++ b/tests_boost/test-encode-decode-block.cpp
@@ -0,0 +1,66 @@
+/**
+ * Copyright (C) 2013 Regents of the University of California.
+ * @author: Jeff Thompson <jefft0@remap.ucla.edu>
+ * See COPYING for copyright and distribution information.
+ */
+
+#include <boost/test/unit_test.hpp>
+
+#include <ndn-cpp-dev/interest.hpp>
+
+using namespace std;
+using namespace ndn;
+
+BOOST_AUTO_TEST_SUITE(TestBlock)
+
+const uint8_t Interest1[] = {
+ 0x1, 0x41, // NDN Interest
+ 0x3, 0x14, // Name
+ 0x4, 0x5, // NameComponent
+ 0x6c, 0x6f, 0x63, 0x61, 0x6c,
+ 0x4, 0x3, // NameComponent
+ 0x6e, 0x64, 0x6e,
+ 0x4, 0x6, // NameComponent
+ 0x70, 0x72, 0x65, 0x66, 0x69, 0x78,
+ 0x5, 0x1f, // Selectors
+ 0x09, 0x1, 0x1, // MinSuffix
+ 0x0a, 0x1, 0x1, // MaxSuffix
+ 0x0c, 0x14, // Exclude
+ 0x4, 0x4, // NameComponent
+ 0x61, 0x6c, 0x65, 0x78,
+ 0x4, 0x4, // NameComponent
+ 0x78, 0x78, 0x78, 0x78,
+ 0xf, 0x0, // Any
+ 0x4, 0x4, // NameComponent
+ 0x79, 0x79, 0x79, 0x79,
+ 0x0d, 0x1, // ChildSelector
+ 0x1,
+ 0x6, 0x1, // Nonce
+ 0x1,
+ 0x7, 0x1, // Scope
+ 0x1,
+ 0x8, // InterestLifetime
+ 0x2, 0x3, 0xe8
+};
+
+BOOST_AUTO_TEST_CASE (Decode)
+{
+ boost::iostreams::stream<boost::iostreams::array_source> is (reinterpret_cast<const char *>(Interest1), sizeof(Interest1));
+
+ Block interestBlock(is);
+
+ ndn::Interest i;
+ BOOST_REQUIRE_NO_THROW(i.wireDecode(interestBlock));
+
+ BOOST_REQUIRE_EQUAL(i.getName().toUri(), "/local/ndn/prefix");
+ BOOST_REQUIRE_EQUAL(i.getScope(), 1);
+ BOOST_REQUIRE_EQUAL(i.getInterestLifetime(), 1000);
+ BOOST_REQUIRE_EQUAL(i.getMinSuffixComponents(), 1);
+ BOOST_REQUIRE_EQUAL(i.getMaxSuffixComponents(), 1);
+ BOOST_REQUIRE_EQUAL(i.getChildSelector(), 1);
+ BOOST_REQUIRE_EQUAL(i.getMustBeFresh(), false);
+ BOOST_REQUIRE_EQUAL(i.getExclude().toUri(), "alex,xxxx,*,yyyy");
+ BOOST_REQUIRE_EQUAL(i.getNonce(), 1);
+}
+
+BOOST_AUTO_TEST_SUITE_END()