blob: fc9a0dc20489f58da95183ce47b8976badd5eb97 [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 Shi81a6c5d2014-11-30 00:14:42 -070037
susmit8b156552016-01-12 13:10:55 -070038const size_t MAX_SIZE_OF_BLOCK_FROM_STREAM = MAX_NDN_PACKET_SIZE;
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070039
Junxiao Shidb7464d2017-07-13 03:11:17 +000040// ---- constructor, creation, assignment ----
41
Davide Pesavento3a3e1882018-07-17 14:49:15 -040042Block::Block() = default;
43
44Block::Block(const Block&) = default;
45
46Block&
47Block::operator=(const Block&) = default;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080048
Alexander Afanasyev15151312014-02-16 00:53:51 -080049Block::Block(const EncodingBuffer& buffer)
Davide Pesavento570b20d2018-07-15 21:53:14 -040050 : Block(buffer.getBuffer(), buffer.begin(), buffer.end(), true)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080051{
52}
53
Alexander Afanasyeva465e972014-03-22 17:21:49 -070054Block::Block(const ConstBufferPtr& buffer)
Junxiao Shidb7464d2017-07-13 03:11:17 +000055 : Block(buffer, buffer->begin(), buffer->end(), true)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080056{
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080057}
58
Junxiao Shidb7464d2017-07-13 03:11:17 +000059Block::Block(ConstBufferPtr buffer, Buffer::const_iterator begin, Buffer::const_iterator end,
60 bool verifyLength)
61 : m_buffer(std::move(buffer))
Alexander Afanasyev187bc482014-02-06 15:04:04 -080062 , m_begin(begin)
63 , m_end(end)
Junxiao Shidb7464d2017-07-13 03:11:17 +000064 , m_valueBegin(m_begin)
65 , m_valueEnd(m_end)
Alexander Afanasyev380420b2014-02-09 20:52:29 -080066 , m_size(m_end - m_begin)
Alexander Afanasyev187bc482014-02-06 15:04:04 -080067{
Junxiao Shidb7464d2017-07-13 03:11:17 +000068 if (m_buffer->size() == 0) {
69 BOOST_THROW_EXCEPTION(std::invalid_argument("buffer is empty"));
70 }
Alexander Afanasyev380420b2014-02-09 20:52:29 -080071
Junxiao Shidb7464d2017-07-13 03:11:17 +000072 const uint8_t* bufferBegin = &m_buffer->front();
73 const uint8_t* bufferEnd = bufferBegin + m_buffer->size();
74 if (&*begin < bufferBegin || &*begin > bufferEnd ||
75 &*end < bufferBegin || &*end > bufferEnd) {
76 BOOST_THROW_EXCEPTION(std::invalid_argument("begin/end iterators points out of the buffer"));
77 }
78
79 m_type = tlv::readType(m_valueBegin, m_valueEnd);
80 uint64_t length = tlv::readVarNumber(m_valueBegin, m_valueEnd);
81 // m_valueBegin now points to TLV-VALUE
82
83 if (verifyLength && length != static_cast<uint64_t>(m_valueEnd - m_valueBegin)) {
84 BOOST_THROW_EXCEPTION(Error("TLV-LENGTH doesn't match buffer size"));
Alexander Afanasyev4448d292015-08-09 20:11:37 -070085 }
86}
87
Junxiao Shidb7464d2017-07-13 03:11:17 +000088Block::Block(const Block& block, Buffer::const_iterator begin, Buffer::const_iterator end,
89 bool verifyLength)
90 : Block(block.m_buffer, begin, end, verifyLength)
91{
92}
93
94Block::Block(ConstBufferPtr buffer, uint32_t type,
95 Buffer::const_iterator begin, Buffer::const_iterator end,
96 Buffer::const_iterator valueBegin, Buffer::const_iterator valueEnd)
97 : m_buffer(std::move(buffer))
Alexander Afanasyev4448d292015-08-09 20:11:37 -070098 , m_begin(begin)
99 , m_end(end)
Junxiao Shidb7464d2017-07-13 03:11:17 +0000100 , m_valueBegin(valueBegin)
101 , m_valueEnd(valueEnd)
102 , m_type(type)
Alexander Afanasyev4448d292015-08-09 20:11:37 -0700103 , m_size(m_end - m_begin)
104{
Alexander Afanasyev187bc482014-02-06 15:04:04 -0800105}
106
Junxiao Shidb7464d2017-07-13 03:11:17 +0000107Block::Block(const uint8_t* buf, size_t bufSize)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800108{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000109 const uint8_t* pos = buf;
110 const uint8_t* const end = buf + bufSize;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700111
Junxiao Shidb7464d2017-07-13 03:11:17 +0000112 m_type = tlv::readType(pos, end);
113 uint64_t length = tlv::readVarNumber(pos, end);
114 // pos now points to TLV-VALUE
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700115
Davide Pesavento3a3e1882018-07-17 14:49:15 -0400116 BOOST_ASSERT(pos <= end);
Junxiao Shidb7464d2017-07-13 03:11:17 +0000117 if (length > static_cast<uint64_t>(end - pos)) {
Junxiao Shi760cc7b2017-07-22 19:17:49 +0000118 BOOST_THROW_EXCEPTION(Error("Not enough bytes in the buffer to fully parse TLV"));
Junxiao Shidb7464d2017-07-13 03:11:17 +0000119 }
Davide Pesavento3a3e1882018-07-17 14:49:15 -0400120
121 BOOST_ASSERT(pos > buf);
122 uint64_t typeLengthSize = static_cast<uint64_t>(pos - buf);
Junxiao Shidb7464d2017-07-13 03:11:17 +0000123 m_size = typeLengthSize + length;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800124
Junxiao Shidb7464d2017-07-13 03:11:17 +0000125 m_buffer = make_shared<Buffer>(buf, m_size);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800126 m_begin = m_buffer->begin();
Junxiao Shidb7464d2017-07-13 03:11:17 +0000127 m_end = m_valueEnd = m_buffer->end();
128 m_valueBegin = m_begin + typeLengthSize;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800129}
130
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800131Block::Block(uint32_t type)
132 : m_type(type)
Junxiao Shidb7464d2017-07-13 03:11:17 +0000133 , m_size(tlv::sizeOfVarNumber(m_type) + tlv::sizeOfVarNumber(0))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800134{
135}
136
Junxiao Shidb7464d2017-07-13 03:11:17 +0000137Block::Block(uint32_t type, ConstBufferPtr value)
138 : m_buffer(std::move(value))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800139 , m_begin(m_buffer->end())
140 , m_end(m_buffer->end())
Junxiao Shidb7464d2017-07-13 03:11:17 +0000141 , m_valueBegin(m_buffer->begin())
142 , m_valueEnd(m_buffer->end())
143 , m_type(type)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800144{
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600145 m_size = tlv::sizeOfVarNumber(m_type) + tlv::sizeOfVarNumber(value_size()) + value_size();
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800146}
147
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700148Block::Block(uint32_t type, const Block& value)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800149 : m_buffer(value.m_buffer)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800150 , m_begin(m_buffer->end())
151 , m_end(m_buffer->end())
Junxiao Shidb7464d2017-07-13 03:11:17 +0000152 , m_valueBegin(value.begin())
153 , m_valueEnd(value.end())
154 , m_type(type)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800155{
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600156 m_size = tlv::sizeOfVarNumber(m_type) + tlv::sizeOfVarNumber(value_size()) + value_size();
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800157}
158
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700159Block
160Block::fromStream(std::istream& is)
161{
Junxiao Shif0da7892015-04-04 22:16:16 -0700162 std::istream_iterator<uint8_t> begin(is >> std::noskipws);
163 std::istream_iterator<uint8_t> end;
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700164
Junxiao Shif0da7892015-04-04 22:16:16 -0700165 uint32_t type = tlv::readType(begin, end);
166 uint64_t length = tlv::readVarNumber(begin, end);
Junxiao Shi760cc7b2017-07-22 19:17:49 +0000167 if (begin != end) {
168 is.putback(*begin);
Junxiao Shif0da7892015-04-04 22:16:16 -0700169 }
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700170
Junxiao Shi760cc7b2017-07-22 19:17:49 +0000171 size_t tlSize = tlv::sizeOfVarNumber(type) + tlv::sizeOfVarNumber(length);
172 if (tlSize + length > MAX_SIZE_OF_BLOCK_FROM_STREAM) {
173 BOOST_THROW_EXCEPTION(Error("TLV-LENGTH from stream exceeds limit"));
Junxiao Shidb7464d2017-07-13 03:11:17 +0000174 }
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700175
Junxiao Shi760cc7b2017-07-22 19:17:49 +0000176 EncodingBuffer eb(tlSize + length, length);
177 uint8_t* valueBuf = eb.buf();
178 is.read(reinterpret_cast<char*>(valueBuf), length);
179 if (length != static_cast<uint64_t>(is.gcount())) {
180 BOOST_THROW_EXCEPTION(Error("Not enough bytes from stream to fully parse TLV"));
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700181 }
182
Junxiao Shi760cc7b2017-07-22 19:17:49 +0000183 eb.prependVarNumber(length);
184 eb.prependVarNumber(type);
185
186 // TLV-VALUE is directly written into eb.buf(), eb.end() is not incremented, but eb.getBuffer()
187 // has the correct layout.
188 return Block(eb.getBuffer());
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700189}
190
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700191std::tuple<bool, Block>
192Block::fromBuffer(ConstBufferPtr buffer, size_t offset)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700193{
Davide Pesavento3b101d02018-07-21 22:44:09 -0400194 auto begin = buffer->begin() + offset;
195 auto pos = begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700196
Junxiao Shidb7464d2017-07-13 03:11:17 +0000197 uint32_t type = 0;
198 bool isOk = tlv::readType(pos, buffer->end(), type);
199 if (!isOk) {
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700200 return std::make_tuple(false, Block());
Junxiao Shidb7464d2017-07-13 03:11:17 +0000201 }
Davide Pesavento3b101d02018-07-21 22:44:09 -0400202
Junxiao Shidb7464d2017-07-13 03:11:17 +0000203 uint64_t length = 0;
204 isOk = tlv::readVarNumber(pos, buffer->end(), length);
205 if (!isOk) {
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700206 return std::make_tuple(false, Block());
Junxiao Shidb7464d2017-07-13 03:11:17 +0000207 }
208 // pos now points to TLV-VALUE
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700209
Junxiao Shidb7464d2017-07-13 03:11:17 +0000210 if (length > static_cast<uint64_t>(buffer->end() - pos)) {
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700211 return std::make_tuple(false, Block());
Junxiao Shidb7464d2017-07-13 03:11:17 +0000212 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700213
Davide Pesavento3b101d02018-07-21 22:44:09 -0400214 return std::make_tuple(true, Block(std::move(buffer), type, begin, pos + length, pos, pos + length));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700215}
216
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700217std::tuple<bool, Block>
Junxiao Shidb7464d2017-07-13 03:11:17 +0000218Block::fromBuffer(const uint8_t* buf, size_t bufSize)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700219{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000220 const uint8_t* pos = buf;
221 const uint8_t* const end = buf + bufSize;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700222
Mickey Sweatt632e0572014-04-20 00:36:32 -0700223 uint32_t type = 0;
Junxiao Shidb7464d2017-07-13 03:11:17 +0000224 bool isOk = tlv::readType(pos, end, type);
225 if (!isOk) {
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700226 return std::make_tuple(false, Block());
Junxiao Shidb7464d2017-07-13 03:11:17 +0000227 }
228 uint64_t length = 0;
229 isOk = tlv::readVarNumber(pos, end, length);
230 if (!isOk) {
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700231 return std::make_tuple(false, Block());
Junxiao Shidb7464d2017-07-13 03:11:17 +0000232 }
233 // pos now points to TLV-VALUE
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700234
Junxiao Shidb7464d2017-07-13 03:11:17 +0000235 if (length > static_cast<uint64_t>(end - pos)) {
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700236 return std::make_tuple(false, Block());
Junxiao Shidb7464d2017-07-13 03:11:17 +0000237 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700238
Junxiao Shidb7464d2017-07-13 03:11:17 +0000239 size_t typeLengthSize = pos - buf;
240 auto b = make_shared<Buffer>(buf, pos + length);
241 return std::make_tuple(true, Block(b, type, b->begin(), b->end(),
242 b->begin() + typeLengthSize, b->end()));
243}
244
245// ---- wire format ----
246
247bool
248Block::hasWire() const
249{
250 return m_buffer != nullptr && m_begin != m_end;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700251}
252
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800253void
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700254Block::reset()
255{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000256 this->resetWire();
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700257
258 m_type = std::numeric_limits<uint32_t>::max();
Junxiao Shidb7464d2017-07-13 03:11:17 +0000259 m_elements.clear();
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700260}
261
262void
263Block::resetWire()
264{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000265 m_buffer.reset(); // discard underlying buffer by resetting shared_ptr
Davide Pesavento3a3e1882018-07-17 14:49:15 -0400266 m_begin = m_end = m_valueBegin = m_valueEnd = {};
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400267}
268
269Buffer::const_iterator
270Block::begin() const
271{
272 if (!hasWire())
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700273 BOOST_THROW_EXCEPTION(Error("Underlying wire buffer is empty"));
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400274
275 return m_begin;
276}
277
278Buffer::const_iterator
279Block::end() const
280{
281 if (!hasWire())
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700282 BOOST_THROW_EXCEPTION(Error("Underlying wire buffer is empty"));
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400283
284 return m_end;
285}
286
287const uint8_t*
288Block::wire() const
289{
290 if (!hasWire())
Junxiao Shidb7464d2017-07-13 03:11:17 +0000291 BOOST_THROW_EXCEPTION(Error("Underlying wire buffer is empty"));
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400292
293 return &*m_begin;
294}
295
296size_t
297Block::size() const
298{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000299 if (empty()) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700300 BOOST_THROW_EXCEPTION(Error("Block size cannot be determined (undefined block size)"));
Junxiao Shidb7464d2017-07-13 03:11:17 +0000301 }
302
303 return m_size;
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400304}
305
Junxiao Shidb7464d2017-07-13 03:11:17 +0000306// ---- value ----
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400307
308const uint8_t*
309Block::value() const
310{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000311 return hasValue() ? &*m_valueBegin : nullptr;
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400312}
313
314size_t
315Block::value_size() const
316{
Davide Pesavento3a3e1882018-07-17 14:49:15 -0400317 return hasValue() ? static_cast<size_t>(m_valueEnd - m_valueBegin) : 0;
Junxiao Shidb7464d2017-07-13 03:11:17 +0000318}
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400319
Junxiao Shidb7464d2017-07-13 03:11:17 +0000320Block
321Block::blockFromValue() const
322{
323 if (!hasValue())
324 BOOST_THROW_EXCEPTION(Error("Block has no TLV-VALUE"));
325
326 return Block(*this, m_valueBegin, m_valueEnd, true);
327}
328
329// ---- sub elements ----
330
331void
332Block::parse() const
333{
334 if (!m_elements.empty() || value_size() == 0)
335 return;
336
337 Buffer::const_iterator begin = value_begin();
338 Buffer::const_iterator end = value_end();
339
340 while (begin != end) {
341 Buffer::const_iterator pos = begin;
342
343 uint32_t type = tlv::readType(pos, end);
344 uint64_t length = tlv::readVarNumber(pos, end);
345 if (length > static_cast<uint64_t>(end - pos)) {
346 m_elements.clear();
347 BOOST_THROW_EXCEPTION(Error("TLV-LENGTH of sub-element of type " + to_string(type) +
348 " exceeds TLV-VALUE boundary of parent block"));
349 }
350 // pos now points to TLV-VALUE of sub element
351
352 Buffer::const_iterator subEnd = pos + length;
353 m_elements.emplace_back(m_buffer, type, begin, subEnd, pos, subEnd);
354
355 begin = subEnd;
356 }
357}
358
359void
360Block::encode()
361{
362 if (hasWire())
363 return;
364
Junxiao Shid2777fa2017-07-27 18:35:34 +0000365 EncodingEstimator estimator;
366 size_t estimatedSize = encode(estimator);
Junxiao Shidb7464d2017-07-13 03:11:17 +0000367
Junxiao Shid2777fa2017-07-27 18:35:34 +0000368 EncodingBuffer buffer(estimatedSize, 0);
369 encode(buffer);
370}
371
372size_t
373Block::encode(EncodingEstimator& estimator) const
374{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000375 if (hasValue()) {
Junxiao Shid2777fa2017-07-27 18:35:34 +0000376 return m_size;
Junxiao Shidb7464d2017-07-13 03:11:17 +0000377 }
Junxiao Shid2777fa2017-07-27 18:35:34 +0000378
Junxiao Shi72c0c642018-04-20 15:41:09 +0000379 size_t len = encodeValue(estimator);
380 len += estimator.prependVarNumber(len);
381 len += estimator.prependVarNumber(m_type);
382 return len;
383}
384
385size_t
386Block::encodeValue(EncodingEstimator& estimator) const
387{
Junxiao Shid2777fa2017-07-27 18:35:34 +0000388 size_t len = 0;
389 for (const Block& element : m_elements | boost::adaptors::reversed) {
390 len += element.encode(estimator);
391 }
Junxiao Shid2777fa2017-07-27 18:35:34 +0000392 return len;
393}
394
395size_t
396Block::encode(EncodingBuffer& encoder)
397{
398 size_t len = 0;
399 m_end = encoder.begin();
400 if (hasValue()) {
401 len += encoder.prependRange(m_valueBegin, m_valueEnd);
Junxiao Shidb7464d2017-07-13 03:11:17 +0000402 }
403 else {
Junxiao Shid2777fa2017-07-27 18:35:34 +0000404 for (Block& element : m_elements | boost::adaptors::reversed) {
405 len += element.encode(encoder);
Junxiao Shidb7464d2017-07-13 03:11:17 +0000406 }
407 }
Junxiao Shid2777fa2017-07-27 18:35:34 +0000408 m_valueEnd = m_end;
409 m_valueBegin = encoder.begin();
Junxiao Shidb7464d2017-07-13 03:11:17 +0000410
Junxiao Shid2777fa2017-07-27 18:35:34 +0000411 len += encoder.prependVarNumber(len);
412 len += encoder.prependVarNumber(m_type);
413 m_begin = encoder.begin();
Junxiao Shidb7464d2017-07-13 03:11:17 +0000414
Junxiao Shid2777fa2017-07-27 18:35:34 +0000415 m_buffer = encoder.getBuffer();
416 m_size = len;
417 return len;
Junxiao Shidb7464d2017-07-13 03:11:17 +0000418}
419
420const Block&
421Block::get(uint32_t type) const
422{
423 auto it = this->find(type);
424 if (it != m_elements.end()) {
425 return *it;
426 }
427
428 BOOST_THROW_EXCEPTION(Error("No sub-element of type " + to_string(type) +
429 " is found in block of type " + to_string(m_type)));
430}
431
432Block::element_const_iterator
433Block::find(uint32_t type) const
434{
435 return std::find_if(m_elements.begin(), m_elements.end(),
436 [type] (const Block& subBlock) { return subBlock.type() == type; });
437}
438
439void
440Block::remove(uint32_t type)
441{
442 resetWire();
443
444 auto it = std::remove_if(m_elements.begin(), m_elements.end(),
445 [type] (const Block& subBlock) { return subBlock.type() == type; });
446 m_elements.resize(it - m_elements.begin());
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400447}
448
449Block::element_iterator
Joao Pereira7476ebf2015-07-07 14:54:39 -0400450Block::erase(Block::element_const_iterator position)
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400451{
452 resetWire();
Junxiao Shidb7464d2017-07-13 03:11:17 +0000453 return m_elements.erase(position);
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400454}
455
456Block::element_iterator
Joao Pereira7476ebf2015-07-07 14:54:39 -0400457Block::erase(Block::element_const_iterator first, Block::element_const_iterator last)
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400458{
459 resetWire();
Junxiao Shidb7464d2017-07-13 03:11:17 +0000460 return m_elements.erase(first, last);
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400461}
462
463void
464Block::push_back(const Block& element)
465{
466 resetWire();
Junxiao Shidb7464d2017-07-13 03:11:17 +0000467 m_elements.push_back(element);
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400468}
469
Joao Pereira7476ebf2015-07-07 14:54:39 -0400470Block::element_iterator
471Block::insert(Block::element_const_iterator pos, const Block& element)
472{
473 resetWire();
Junxiao Shidb7464d2017-07-13 03:11:17 +0000474 return m_elements.insert(pos, element);
Joao Pereira7476ebf2015-07-07 14:54:39 -0400475}
476
Junxiao Shidb7464d2017-07-13 03:11:17 +0000477// ---- misc ----
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400478
Junxiao Shidb7464d2017-07-13 03:11:17 +0000479Block::operator boost::asio::const_buffer() const
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400480{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000481 return boost::asio::const_buffer(wire(), size());
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400482}
483
484bool
Junxiao Shidb7464d2017-07-13 03:11:17 +0000485operator==(const Block& lhs, const Block& rhs)
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400486{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000487 return lhs.type() == rhs.type() &&
488 lhs.value_size() == rhs.value_size() &&
Davide Pesaventoe245b052017-10-31 13:00:44 -0400489 (lhs.value_size() == 0 ||
490 std::memcmp(lhs.value(), rhs.value(), lhs.value_size()) == 0);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700491}
492
Junxiao Shi72c0c642018-04-20 15:41:09 +0000493std::ostream&
494operator<<(std::ostream& os, const Block& block)
495{
496 auto oldFmt = os.flags(std::ios_base::dec);
497
498 if (block.empty()) {
499 os << "[invalid]";
500 }
501 else if (!block.m_elements.empty()) {
502 EncodingEstimator estimator;
503 size_t tlvLength = block.encodeValue(estimator);
504 os << block.type() << '[' << tlvLength << "]={";
505 std::copy(block.elements_begin(), block.elements_end(), make_ostream_joiner(os, ','));
506 os << '}';
507 }
508 else if (block.value_size() > 0) {
509 os << block.type() << '[' << block.value_size() << "]=";
510 printHex(os, block.value(), block.value_size(), true);
511 }
512 else {
513 os << block.type() << "[empty]";
514 }
515
516 os.flags(oldFmt);
517 return os;
518}
519
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800520} // namespace ndn