block: Add constructor to create sub-blocks using the underlying buffer
Change-Id: Ic25f82526228dbe7aa3222bc6b1e68ac0e35cea1
Refs: #3100
diff --git a/src/encoding/block.cpp b/src/encoding/block.cpp
index 624439d..7306276 100644
--- a/src/encoding/block.cpp
+++ b/src/encoding/block.cpp
@@ -112,13 +112,36 @@
m_type = tlv::readType(m_value_begin, m_value_end);
uint64_t length = tlv::readVarNumber(m_value_begin, m_value_end);
- if (verifyLength)
- {
- if (length != static_cast<uint64_t>(m_value_end - m_value_begin))
- {
- BOOST_THROW_EXCEPTION(tlv::Error("TLV length doesn't match buffer length"));
- }
+ if (verifyLength) {
+ if (length != static_cast<uint64_t>(std::distance(m_value_begin, m_value_end))) {
+ BOOST_THROW_EXCEPTION(tlv::Error("TLV length doesn't match buffer length"));
}
+ }
+}
+
+Block::Block(const Block& block,
+ const Buffer::const_iterator& begin, const Buffer::const_iterator& end,
+ bool verifyLength/* = true*/)
+ : m_buffer(block.m_buffer)
+ , m_begin(begin)
+ , m_end(end)
+ , m_size(m_end - m_begin)
+{
+ if (!(m_buffer->begin() <= begin && begin <= m_buffer->end()) ||
+ !(m_buffer->begin() <= end && end <= m_buffer->end())) {
+ BOOST_THROW_EXCEPTION(Error("begin/end iterators do not point to the underlying buffer of the block"));
+ }
+
+ m_value_begin = m_begin;
+ m_value_end = m_end;
+
+ m_type = tlv::readType(m_value_begin, m_value_end);
+ uint64_t length = tlv::readVarNumber(m_value_begin, m_value_end);
+ if (verifyLength) {
+ if (length != static_cast<uint64_t>(std::distance(m_value_begin, m_value_end))) {
+ BOOST_THROW_EXCEPTION(tlv::Error("TLV length doesn't match buffer length"));
+ }
+ }
}
Block::Block(const uint8_t* buffer, size_t maxlength)
diff --git a/src/encoding/block.hpp b/src/encoding/block.hpp
index 0552755..0c83149 100644
--- a/src/encoding/block.hpp
+++ b/src/encoding/block.hpp
@@ -81,6 +81,15 @@
const Buffer::const_iterator& begin, const Buffer::const_iterator& end,
bool verifyLength = true);
+ /** @brief Create a Block from existing block (reusing the underlying buffer), directly
+ * specifying boundaries of the block within the buffer
+ *
+ * This overload will automatically detect type and position of the value within the block
+ */
+ Block(const Block& block,
+ const Buffer::const_iterator& begin, const Buffer::const_iterator& end,
+ bool verifyLength = true);
+
/** @brief Create a Block from the raw buffer with Type-Length parsing
*/
Block(const uint8_t* buffer, size_t maxlength);
diff --git a/tests/unit-tests/encoding/block.t.cpp b/tests/unit-tests/encoding/block.t.cpp
index cc90ede..3ae6aa1 100644
--- a/tests/unit-tests/encoding/block.t.cpp
+++ b/tests/unit-tests/encoding/block.t.cpp
@@ -167,6 +167,25 @@
BOOST_AUTO_TEST_SUITE_END() // Basic
+BOOST_AUTO_TEST_CASE(BlockFromBlock)
+{
+ static uint8_t buffer[] = {0x80, 0x06, 0x81, 0x01, 0x01, 0x82, 0x01, 0x01};
+ Block block(buffer, sizeof(buffer));
+
+ Block derivedBlock(block, block.begin(), block.end());
+ BOOST_CHECK_EQUAL(derivedBlock.wire(), block.wire()); // pointers should match
+ BOOST_CHECK(derivedBlock == block); // blocks should match
+
+ derivedBlock = Block(block, block.begin() + 2, block.begin() + 5);
+ BOOST_CHECK(derivedBlock.begin() == block.begin() + 2);
+ BOOST_CHECK(derivedBlock == Block(buffer + 2, 3));
+
+ Buffer otherBuffer(buffer, sizeof(buffer));
+ BOOST_CHECK_THROW(Block(block, otherBuffer.begin(), block.end()), Block::Error);
+ BOOST_CHECK_THROW(Block(block, block.begin(), otherBuffer.end()), Block::Error);
+ BOOST_CHECK_THROW(Block(block, otherBuffer.begin(), otherBuffer.end()), Block::Error);
+}
+
BOOST_AUTO_TEST_CASE(EncodingBufferToBlock)
{
uint8_t value[4];