encoding: Block::fromStream properly handles TLV-LENGTH=0
Block::fromStream implementation is also optimized to reduce
memory copying.
refs #4180
Change-Id: I7cc073330b9ec4a9af4863db62e6c108d220066b
diff --git a/src/encoding/block.cpp b/src/encoding/block.cpp
index 768b624..3aa2701 100644
--- a/src/encoding/block.cpp
+++ b/src/encoding/block.cpp
@@ -22,7 +22,6 @@
*/
#include "block.hpp"
-#include "block-helpers.hpp"
#include "buffer-stream.hpp"
#include "encoding-buffer.hpp"
#include "tlv.hpp"
@@ -120,7 +119,7 @@
// pos now points to TLV-VALUE
if (length > static_cast<uint64_t>(end - pos)) {
- BOOST_THROW_EXCEPTION(tlv::Error("Not enough data in the buffer to fully parse TLV"));
+ BOOST_THROW_EXCEPTION(Error("Not enough bytes in the buffer to fully parse TLV"));
}
size_t typeLengthSize = pos - buf;
m_size = typeLengthSize + length;
@@ -172,28 +171,28 @@
uint32_t type = tlv::readType(begin, end);
uint64_t length = tlv::readVarNumber(begin, end);
-
- if (length == 0) {
- // XXX An extra octet is incorrectly consumed from istream (#4180)
- return Block(type);
+ if (begin != end) {
+ is.putback(*begin);
}
- if (length > MAX_SIZE_OF_BLOCK_FROM_STREAM) {
- BOOST_THROW_EXCEPTION(tlv::Error("TLV-LENGTH from stream exceeds limit"));
+ size_t tlSize = tlv::sizeOfVarNumber(type) + tlv::sizeOfVarNumber(length);
+ if (tlSize + length > MAX_SIZE_OF_BLOCK_FROM_STREAM) {
+ BOOST_THROW_EXCEPTION(Error("TLV-LENGTH from stream exceeds limit"));
}
- // We may still have some problem here, if some exception happens,
- // we may completely lose all the bytes extracted from the stream.
-
- char buf[MAX_SIZE_OF_BLOCK_FROM_STREAM];
- buf[0] = *begin;
- is.read(buf + 1, length - 1);
-
- if (length != static_cast<uint64_t>(is.gcount()) + 1) {
- BOOST_THROW_EXCEPTION(tlv::Error("Not enough data in the buffer to fully parse TLV"));
+ EncodingBuffer eb(tlSize + length, length);
+ uint8_t* valueBuf = eb.buf();
+ is.read(reinterpret_cast<char*>(valueBuf), length);
+ if (length != static_cast<uint64_t>(is.gcount())) {
+ BOOST_THROW_EXCEPTION(Error("Not enough bytes from stream to fully parse TLV"));
}
- return makeBinaryBlock(type, buf, length);
+ eb.prependVarNumber(length);
+ eb.prependVarNumber(type);
+
+ // TLV-VALUE is directly written into eb.buf(), eb.end() is not incremented, but eb.getBuffer()
+ // has the correct layout.
+ return Block(eb.getBuffer());
}
std::tuple<bool, Block>
diff --git a/src/encoding/block.hpp b/src/encoding/block.hpp
index a5f1e1a..91ab51c 100644
--- a/src/encoding/block.hpp
+++ b/src/encoding/block.hpp
@@ -38,7 +38,8 @@
namespace ndn {
-/** @brief Class representing a wire element of NDN-TLV packet format
+/** @brief Represents a TLV element of NDN packet format
+ * @sa https://named-data.net/doc/ndn-tlv/tlv.html
*/
class Block
{
@@ -144,6 +145,8 @@
Block(uint32_t type, const Block& value);
/** @brief Parse Block from an input stream
+ * @throw tlv::Error TLV-LENGTH is zero or exceeds upper bound
+ * @warning If decoding fails, bytes are still consumed from the input stream.
*/
static Block
fromStream(std::istream& is);