blob: 21130646dd570cc9b07c1b43f8e6b4dc69b9c2cf [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Junxiao Shidb7464d2017-07-13 03:11:17 +00002/*
Junxiao Shi72c0c642018-04-20 15:41:09 +00003 * Copyright (c) 2013-2018 Regents of the University of California.
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -08004 *
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07005 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -08006 *
Alexander Afanasyevc169a812014-05-20 20:37:29 -04007 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -070020 *
21 * @author Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080022 */
23
Alexander Afanasyeve2dcdfd2014-02-07 15:53:28 -080024#include "block.hpp"
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070025#include "buffer-stream.hpp"
Junxiao Shidb7464d2017-07-13 03:11:17 +000026#include "encoding-buffer.hpp"
27#include "tlv.hpp"
Junxiao Shi72c0c642018-04-20 15:41:09 +000028#include "../util/string-helper.hpp"
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070029
Alexander Afanasyev6a05b4b2014-07-18 17:23:00 -070030#include <boost/asio/buffer.hpp>
Junxiao Shid2777fa2017-07-27 18:35:34 +000031#include <boost/range/adaptor/reversed.hpp>
Davide Pesaventoe245b052017-10-31 13:00:44 -040032#include <cstring>
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080033
34namespace ndn {
35
Junxiao Shidc4277a2017-07-17 11:34:02 +000036BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Block>));
Junxiao Shi88681402015-06-30 09:58:53 -070037#if NDN_CXX_HAVE_IS_NOTHROW_MOVE_CONSTRUCTIBLE
38static_assert(std::is_nothrow_move_constructible<Block>::value,
39 "Block must be MoveConstructible with noexcept");
40#endif // NDN_CXX_HAVE_IS_NOTHROW_MOVE_CONSTRUCTIBLE
Junxiao Shi81a6c5d2014-11-30 00:14:42 -070041
Junxiao Shi88681402015-06-30 09:58:53 -070042#if NDN_CXX_HAVE_IS_NOTHROW_MOVE_ASSIGNABLE
43static_assert(std::is_nothrow_move_assignable<Block>::value,
44 "Block must be MoveAssignable with noexcept");
45#endif // NDN_CXX_HAVE_IS_NOTHROW_MOVE_ASSIGNABLE
Junxiao Shi81a6c5d2014-11-30 00:14:42 -070046
susmit8b156552016-01-12 13:10:55 -070047const size_t MAX_SIZE_OF_BLOCK_FROM_STREAM = MAX_NDN_PACKET_SIZE;
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070048
Junxiao Shidb7464d2017-07-13 03:11:17 +000049// ---- constructor, creation, assignment ----
50
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080051Block::Block()
52 : m_type(std::numeric_limits<uint32_t>::max())
Junxiao Shidb7464d2017-07-13 03:11:17 +000053 , m_size(0)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080054{
55}
56
Alexander Afanasyev15151312014-02-16 00:53:51 -080057Block::Block(const EncodingBuffer& buffer)
Junxiao Shidb7464d2017-07-13 03:11:17 +000058 : Block(const_cast<EncodingBuffer&>(buffer).getBuffer(), buffer.begin(), buffer.end(), true)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080059{
60}
61
Alexander Afanasyeva465e972014-03-22 17:21:49 -070062Block::Block(const ConstBufferPtr& buffer)
Junxiao Shidb7464d2017-07-13 03:11:17 +000063 : Block(buffer, buffer->begin(), buffer->end(), true)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080064{
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080065}
66
Junxiao Shidb7464d2017-07-13 03:11:17 +000067Block::Block(ConstBufferPtr buffer, Buffer::const_iterator begin, Buffer::const_iterator end,
68 bool verifyLength)
69 : m_buffer(std::move(buffer))
Alexander Afanasyev187bc482014-02-06 15:04:04 -080070 , m_begin(begin)
71 , m_end(end)
Junxiao Shidb7464d2017-07-13 03:11:17 +000072 , m_valueBegin(m_begin)
73 , m_valueEnd(m_end)
Alexander Afanasyev380420b2014-02-09 20:52:29 -080074 , m_size(m_end - m_begin)
Alexander Afanasyev187bc482014-02-06 15:04:04 -080075{
Junxiao Shidb7464d2017-07-13 03:11:17 +000076 if (m_buffer->size() == 0) {
77 BOOST_THROW_EXCEPTION(std::invalid_argument("buffer is empty"));
78 }
Alexander Afanasyev380420b2014-02-09 20:52:29 -080079
Junxiao Shidb7464d2017-07-13 03:11:17 +000080 const uint8_t* bufferBegin = &m_buffer->front();
81 const uint8_t* bufferEnd = bufferBegin + m_buffer->size();
82 if (&*begin < bufferBegin || &*begin > bufferEnd ||
83 &*end < bufferBegin || &*end > bufferEnd) {
84 BOOST_THROW_EXCEPTION(std::invalid_argument("begin/end iterators points out of the buffer"));
85 }
86
87 m_type = tlv::readType(m_valueBegin, m_valueEnd);
88 uint64_t length = tlv::readVarNumber(m_valueBegin, m_valueEnd);
89 // m_valueBegin now points to TLV-VALUE
90
91 if (verifyLength && length != static_cast<uint64_t>(m_valueEnd - m_valueBegin)) {
92 BOOST_THROW_EXCEPTION(Error("TLV-LENGTH doesn't match buffer size"));
Alexander Afanasyev4448d292015-08-09 20:11:37 -070093 }
94}
95
Junxiao Shidb7464d2017-07-13 03:11:17 +000096Block::Block(const Block& block, Buffer::const_iterator begin, Buffer::const_iterator end,
97 bool verifyLength)
98 : Block(block.m_buffer, begin, end, verifyLength)
99{
100}
101
102Block::Block(ConstBufferPtr buffer, uint32_t type,
103 Buffer::const_iterator begin, Buffer::const_iterator end,
104 Buffer::const_iterator valueBegin, Buffer::const_iterator valueEnd)
105 : m_buffer(std::move(buffer))
Alexander Afanasyev4448d292015-08-09 20:11:37 -0700106 , m_begin(begin)
107 , m_end(end)
Junxiao Shidb7464d2017-07-13 03:11:17 +0000108 , m_valueBegin(valueBegin)
109 , m_valueEnd(valueEnd)
110 , m_type(type)
Alexander Afanasyev4448d292015-08-09 20:11:37 -0700111 , m_size(m_end - m_begin)
112{
Alexander Afanasyev187bc482014-02-06 15:04:04 -0800113}
114
Junxiao Shidb7464d2017-07-13 03:11:17 +0000115Block::Block(const uint8_t* buf, size_t bufSize)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800116{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000117 const uint8_t* pos = buf;
118 const uint8_t* const end = buf + bufSize;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700119
Junxiao Shidb7464d2017-07-13 03:11:17 +0000120 m_type = tlv::readType(pos, end);
121 uint64_t length = tlv::readVarNumber(pos, end);
122 // pos now points to TLV-VALUE
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700123
Junxiao Shidb7464d2017-07-13 03:11:17 +0000124 if (length > static_cast<uint64_t>(end - pos)) {
Junxiao Shi760cc7b2017-07-22 19:17:49 +0000125 BOOST_THROW_EXCEPTION(Error("Not enough bytes in the buffer to fully parse TLV"));
Junxiao Shidb7464d2017-07-13 03:11:17 +0000126 }
127 size_t typeLengthSize = pos - buf;
128 m_size = typeLengthSize + length;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800129
Junxiao Shidb7464d2017-07-13 03:11:17 +0000130 m_buffer = make_shared<Buffer>(buf, m_size);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800131 m_begin = m_buffer->begin();
Junxiao Shidb7464d2017-07-13 03:11:17 +0000132 m_end = m_valueEnd = m_buffer->end();
133 m_valueBegin = m_begin + typeLengthSize;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800134}
135
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800136Block::Block(uint32_t type)
137 : m_type(type)
Junxiao Shidb7464d2017-07-13 03:11:17 +0000138 , m_size(tlv::sizeOfVarNumber(m_type) + tlv::sizeOfVarNumber(0))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800139{
140}
141
Junxiao Shidb7464d2017-07-13 03:11:17 +0000142Block::Block(uint32_t type, ConstBufferPtr value)
143 : m_buffer(std::move(value))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800144 , m_begin(m_buffer->end())
145 , m_end(m_buffer->end())
Junxiao Shidb7464d2017-07-13 03:11:17 +0000146 , m_valueBegin(m_buffer->begin())
147 , m_valueEnd(m_buffer->end())
148 , m_type(type)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800149{
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600150 m_size = tlv::sizeOfVarNumber(m_type) + tlv::sizeOfVarNumber(value_size()) + value_size();
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800151}
152
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700153Block::Block(uint32_t type, const Block& value)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800154 : m_buffer(value.m_buffer)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800155 , m_begin(m_buffer->end())
156 , m_end(m_buffer->end())
Junxiao Shidb7464d2017-07-13 03:11:17 +0000157 , m_valueBegin(value.begin())
158 , m_valueEnd(value.end())
159 , m_type(type)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800160{
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600161 m_size = tlv::sizeOfVarNumber(m_type) + tlv::sizeOfVarNumber(value_size()) + value_size();
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800162}
163
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700164Block
165Block::fromStream(std::istream& is)
166{
Junxiao Shif0da7892015-04-04 22:16:16 -0700167 std::istream_iterator<uint8_t> begin(is >> std::noskipws);
168 std::istream_iterator<uint8_t> end;
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700169
Junxiao Shif0da7892015-04-04 22:16:16 -0700170 uint32_t type = tlv::readType(begin, end);
171 uint64_t length = tlv::readVarNumber(begin, end);
Junxiao Shi760cc7b2017-07-22 19:17:49 +0000172 if (begin != end) {
173 is.putback(*begin);
Junxiao Shif0da7892015-04-04 22:16:16 -0700174 }
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700175
Junxiao Shi760cc7b2017-07-22 19:17:49 +0000176 size_t tlSize = tlv::sizeOfVarNumber(type) + tlv::sizeOfVarNumber(length);
177 if (tlSize + length > MAX_SIZE_OF_BLOCK_FROM_STREAM) {
178 BOOST_THROW_EXCEPTION(Error("TLV-LENGTH from stream exceeds limit"));
Junxiao Shidb7464d2017-07-13 03:11:17 +0000179 }
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700180
Junxiao Shi760cc7b2017-07-22 19:17:49 +0000181 EncodingBuffer eb(tlSize + length, length);
182 uint8_t* valueBuf = eb.buf();
183 is.read(reinterpret_cast<char*>(valueBuf), length);
184 if (length != static_cast<uint64_t>(is.gcount())) {
185 BOOST_THROW_EXCEPTION(Error("Not enough bytes from stream to fully parse TLV"));
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700186 }
187
Junxiao Shi760cc7b2017-07-22 19:17:49 +0000188 eb.prependVarNumber(length);
189 eb.prependVarNumber(type);
190
191 // TLV-VALUE is directly written into eb.buf(), eb.end() is not incremented, but eb.getBuffer()
192 // has the correct layout.
193 return Block(eb.getBuffer());
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700194}
195
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700196std::tuple<bool, Block>
197Block::fromBuffer(ConstBufferPtr buffer, size_t offset)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700198{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000199 const Buffer::const_iterator begin = buffer->begin() + offset;
200 Buffer::const_iterator pos = begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700201
Junxiao Shidb7464d2017-07-13 03:11:17 +0000202 uint32_t type = 0;
203 bool isOk = tlv::readType(pos, buffer->end(), type);
204 if (!isOk) {
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700205 return std::make_tuple(false, Block());
Junxiao Shidb7464d2017-07-13 03:11:17 +0000206 }
207 uint64_t length = 0;
208 isOk = tlv::readVarNumber(pos, buffer->end(), length);
209 if (!isOk) {
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700210 return std::make_tuple(false, Block());
Junxiao Shidb7464d2017-07-13 03:11:17 +0000211 }
212 // pos now points to TLV-VALUE
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700213
Junxiao Shidb7464d2017-07-13 03:11:17 +0000214 if (length > static_cast<uint64_t>(buffer->end() - pos)) {
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700215 return std::make_tuple(false, Block());
Junxiao Shidb7464d2017-07-13 03:11:17 +0000216 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700217
Junxiao Shidb7464d2017-07-13 03:11:17 +0000218 return std::make_tuple(true, Block(buffer, type, begin, pos + length, pos, pos + length));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700219}
220
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700221std::tuple<bool, Block>
Junxiao Shidb7464d2017-07-13 03:11:17 +0000222Block::fromBuffer(const uint8_t* buf, size_t bufSize)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700223{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000224 const uint8_t* pos = buf;
225 const uint8_t* const end = buf + bufSize;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700226
Mickey Sweatt632e0572014-04-20 00:36:32 -0700227 uint32_t type = 0;
Junxiao Shidb7464d2017-07-13 03:11:17 +0000228 bool isOk = tlv::readType(pos, end, type);
229 if (!isOk) {
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700230 return std::make_tuple(false, Block());
Junxiao Shidb7464d2017-07-13 03:11:17 +0000231 }
232 uint64_t length = 0;
233 isOk = tlv::readVarNumber(pos, end, length);
234 if (!isOk) {
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700235 return std::make_tuple(false, Block());
Junxiao Shidb7464d2017-07-13 03:11:17 +0000236 }
237 // pos now points to TLV-VALUE
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700238
Junxiao Shidb7464d2017-07-13 03:11:17 +0000239 if (length > static_cast<uint64_t>(end - pos)) {
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700240 return std::make_tuple(false, Block());
Junxiao Shidb7464d2017-07-13 03:11:17 +0000241 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700242
Junxiao Shidb7464d2017-07-13 03:11:17 +0000243 size_t typeLengthSize = pos - buf;
244 auto b = make_shared<Buffer>(buf, pos + length);
245 return std::make_tuple(true, Block(b, type, b->begin(), b->end(),
246 b->begin() + typeLengthSize, b->end()));
247}
248
249// ---- wire format ----
250
251bool
252Block::hasWire() const
253{
254 return m_buffer != nullptr && m_begin != m_end;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700255}
256
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800257void
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700258Block::reset()
259{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000260 this->resetWire();
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700261
262 m_type = std::numeric_limits<uint32_t>::max();
Junxiao Shidb7464d2017-07-13 03:11:17 +0000263 m_elements.clear();
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700264}
265
266void
267Block::resetWire()
268{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000269 m_buffer.reset(); // discard underlying buffer by resetting shared_ptr
270 m_begin = m_end = m_valueBegin = m_valueEnd = Buffer::const_iterator();
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400271}
272
273Buffer::const_iterator
274Block::begin() const
275{
276 if (!hasWire())
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700277 BOOST_THROW_EXCEPTION(Error("Underlying wire buffer is empty"));
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400278
279 return m_begin;
280}
281
282Buffer::const_iterator
283Block::end() const
284{
285 if (!hasWire())
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700286 BOOST_THROW_EXCEPTION(Error("Underlying wire buffer is empty"));
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400287
288 return m_end;
289}
290
291const uint8_t*
292Block::wire() const
293{
294 if (!hasWire())
Junxiao Shidb7464d2017-07-13 03:11:17 +0000295 BOOST_THROW_EXCEPTION(Error("Underlying wire buffer is empty"));
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400296
297 return &*m_begin;
298}
299
300size_t
301Block::size() const
302{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000303 if (empty()) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700304 BOOST_THROW_EXCEPTION(Error("Block size cannot be determined (undefined block size)"));
Junxiao Shidb7464d2017-07-13 03:11:17 +0000305 }
306
307 return m_size;
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400308}
309
Junxiao Shidb7464d2017-07-13 03:11:17 +0000310// ---- value ----
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400311
312const uint8_t*
313Block::value() const
314{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000315 return hasValue() ? &*m_valueBegin : nullptr;
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400316}
317
318size_t
319Block::value_size() const
320{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000321 return hasValue() ? m_valueEnd - m_valueBegin : 0;
322}
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400323
Junxiao Shidb7464d2017-07-13 03:11:17 +0000324Block
325Block::blockFromValue() const
326{
327 if (!hasValue())
328 BOOST_THROW_EXCEPTION(Error("Block has no TLV-VALUE"));
329
330 return Block(*this, m_valueBegin, m_valueEnd, true);
331}
332
333// ---- sub elements ----
334
335void
336Block::parse() const
337{
338 if (!m_elements.empty() || value_size() == 0)
339 return;
340
341 Buffer::const_iterator begin = value_begin();
342 Buffer::const_iterator end = value_end();
343
344 while (begin != end) {
345 Buffer::const_iterator pos = begin;
346
347 uint32_t type = tlv::readType(pos, end);
348 uint64_t length = tlv::readVarNumber(pos, end);
349 if (length > static_cast<uint64_t>(end - pos)) {
350 m_elements.clear();
351 BOOST_THROW_EXCEPTION(Error("TLV-LENGTH of sub-element of type " + to_string(type) +
352 " exceeds TLV-VALUE boundary of parent block"));
353 }
354 // pos now points to TLV-VALUE of sub element
355
356 Buffer::const_iterator subEnd = pos + length;
357 m_elements.emplace_back(m_buffer, type, begin, subEnd, pos, subEnd);
358
359 begin = subEnd;
360 }
361}
362
363void
364Block::encode()
365{
366 if (hasWire())
367 return;
368
Junxiao Shid2777fa2017-07-27 18:35:34 +0000369 EncodingEstimator estimator;
370 size_t estimatedSize = encode(estimator);
Junxiao Shidb7464d2017-07-13 03:11:17 +0000371
Junxiao Shid2777fa2017-07-27 18:35:34 +0000372 EncodingBuffer buffer(estimatedSize, 0);
373 encode(buffer);
374}
375
376size_t
377Block::encode(EncodingEstimator& estimator) const
378{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000379 if (hasValue()) {
Junxiao Shid2777fa2017-07-27 18:35:34 +0000380 return m_size;
Junxiao Shidb7464d2017-07-13 03:11:17 +0000381 }
Junxiao Shid2777fa2017-07-27 18:35:34 +0000382
Junxiao Shi72c0c642018-04-20 15:41:09 +0000383 size_t len = encodeValue(estimator);
384 len += estimator.prependVarNumber(len);
385 len += estimator.prependVarNumber(m_type);
386 return len;
387}
388
389size_t
390Block::encodeValue(EncodingEstimator& estimator) const
391{
Junxiao Shid2777fa2017-07-27 18:35:34 +0000392 size_t len = 0;
393 for (const Block& element : m_elements | boost::adaptors::reversed) {
394 len += element.encode(estimator);
395 }
Junxiao Shid2777fa2017-07-27 18:35:34 +0000396 return len;
397}
398
399size_t
400Block::encode(EncodingBuffer& encoder)
401{
402 size_t len = 0;
403 m_end = encoder.begin();
404 if (hasValue()) {
405 len += encoder.prependRange(m_valueBegin, m_valueEnd);
Junxiao Shidb7464d2017-07-13 03:11:17 +0000406 }
407 else {
Junxiao Shid2777fa2017-07-27 18:35:34 +0000408 for (Block& element : m_elements | boost::adaptors::reversed) {
409 len += element.encode(encoder);
Junxiao Shidb7464d2017-07-13 03:11:17 +0000410 }
411 }
Junxiao Shid2777fa2017-07-27 18:35:34 +0000412 m_valueEnd = m_end;
413 m_valueBegin = encoder.begin();
Junxiao Shidb7464d2017-07-13 03:11:17 +0000414
Junxiao Shid2777fa2017-07-27 18:35:34 +0000415 len += encoder.prependVarNumber(len);
416 len += encoder.prependVarNumber(m_type);
417 m_begin = encoder.begin();
Junxiao Shidb7464d2017-07-13 03:11:17 +0000418
Junxiao Shid2777fa2017-07-27 18:35:34 +0000419 m_buffer = encoder.getBuffer();
420 m_size = len;
421 return len;
Junxiao Shidb7464d2017-07-13 03:11:17 +0000422}
423
424const Block&
425Block::get(uint32_t type) const
426{
427 auto it = this->find(type);
428 if (it != m_elements.end()) {
429 return *it;
430 }
431
432 BOOST_THROW_EXCEPTION(Error("No sub-element of type " + to_string(type) +
433 " is found in block of type " + to_string(m_type)));
434}
435
436Block::element_const_iterator
437Block::find(uint32_t type) const
438{
439 return std::find_if(m_elements.begin(), m_elements.end(),
440 [type] (const Block& subBlock) { return subBlock.type() == type; });
441}
442
443void
444Block::remove(uint32_t type)
445{
446 resetWire();
447
448 auto it = std::remove_if(m_elements.begin(), m_elements.end(),
449 [type] (const Block& subBlock) { return subBlock.type() == type; });
450 m_elements.resize(it - m_elements.begin());
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400451}
452
453Block::element_iterator
Joao Pereira7476ebf2015-07-07 14:54:39 -0400454Block::erase(Block::element_const_iterator position)
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400455{
456 resetWire();
Joao Pereira7476ebf2015-07-07 14:54:39 -0400457
458#ifdef NDN_CXX_HAVE_VECTOR_INSERT_ERASE_CONST_ITERATOR
Junxiao Shidb7464d2017-07-13 03:11:17 +0000459 return m_elements.erase(position);
Joao Pereira7476ebf2015-07-07 14:54:39 -0400460#else
Junxiao Shidb7464d2017-07-13 03:11:17 +0000461 element_iterator it = m_elements.begin();
462 std::advance(it, std::distance(m_elements.cbegin(), position));
463 return m_elements.erase(it);
Joao Pereira7476ebf2015-07-07 14:54:39 -0400464#endif
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400465}
466
467Block::element_iterator
Joao Pereira7476ebf2015-07-07 14:54:39 -0400468Block::erase(Block::element_const_iterator first, Block::element_const_iterator last)
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400469{
470 resetWire();
Joao Pereira7476ebf2015-07-07 14:54:39 -0400471
472#ifdef NDN_CXX_HAVE_VECTOR_INSERT_ERASE_CONST_ITERATOR
Junxiao Shidb7464d2017-07-13 03:11:17 +0000473 return m_elements.erase(first, last);
Joao Pereira7476ebf2015-07-07 14:54:39 -0400474#else
Junxiao Shidb7464d2017-07-13 03:11:17 +0000475 element_iterator itStart = m_elements.begin();
476 element_iterator itEnd = m_elements.begin();
477 std::advance(itStart, std::distance(m_elements.cbegin(), first));
478 std::advance(itEnd, std::distance(m_elements.cbegin(), last));
479 return m_elements.erase(itStart, itEnd);
Joao Pereira7476ebf2015-07-07 14:54:39 -0400480#endif
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400481}
482
483void
484Block::push_back(const Block& element)
485{
486 resetWire();
Junxiao Shidb7464d2017-07-13 03:11:17 +0000487 m_elements.push_back(element);
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400488}
489
Joao Pereira7476ebf2015-07-07 14:54:39 -0400490Block::element_iterator
491Block::insert(Block::element_const_iterator pos, const Block& element)
492{
493 resetWire();
494
495#ifdef NDN_CXX_HAVE_VECTOR_INSERT_ERASE_CONST_ITERATOR
Junxiao Shidb7464d2017-07-13 03:11:17 +0000496 return m_elements.insert(pos, element);
Joao Pereira7476ebf2015-07-07 14:54:39 -0400497#else
Junxiao Shidb7464d2017-07-13 03:11:17 +0000498 element_iterator it = m_elements.begin();
499 std::advance(it, std::distance(m_elements.cbegin(), pos));
500 return m_elements.insert(it, element);
Joao Pereira7476ebf2015-07-07 14:54:39 -0400501#endif
502}
503
Junxiao Shidb7464d2017-07-13 03:11:17 +0000504// ---- misc ----
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400505
Junxiao Shidb7464d2017-07-13 03:11:17 +0000506Block::operator boost::asio::const_buffer() const
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400507{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000508 return boost::asio::const_buffer(wire(), size());
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400509}
510
511bool
Junxiao Shidb7464d2017-07-13 03:11:17 +0000512operator==(const Block& lhs, const Block& rhs)
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400513{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000514 return lhs.type() == rhs.type() &&
515 lhs.value_size() == rhs.value_size() &&
Davide Pesaventoe245b052017-10-31 13:00:44 -0400516 (lhs.value_size() == 0 ||
517 std::memcmp(lhs.value(), rhs.value(), lhs.value_size()) == 0);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700518}
519
Junxiao Shi72c0c642018-04-20 15:41:09 +0000520std::ostream&
521operator<<(std::ostream& os, const Block& block)
522{
523 auto oldFmt = os.flags(std::ios_base::dec);
524
525 if (block.empty()) {
526 os << "[invalid]";
527 }
528 else if (!block.m_elements.empty()) {
529 EncodingEstimator estimator;
530 size_t tlvLength = block.encodeValue(estimator);
531 os << block.type() << '[' << tlvLength << "]={";
532 std::copy(block.elements_begin(), block.elements_end(), make_ostream_joiner(os, ','));
533 os << '}';
534 }
535 else if (block.value_size() > 0) {
536 os << block.type() << '[' << block.value_size() << "]=";
537 printHex(os, block.value(), block.value_size(), true);
538 }
539 else {
540 os << block.type() << "[empty]";
541 }
542
543 os.flags(oldFmt);
544 return os;
545}
546
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800547} // namespace ndn