blob: cd90b1fdbf9dc158142c43c1015dd3e7b5b9665a [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/*
Davide Pesavento5c803b92019-02-02 19:23:48 -05003 * Copyright (c) 2013-2019 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
Davide Pesavento7e780642018-11-24 15:51:34 -050024#include "ndn-cxx/encoding/block.hpp"
25#include "ndn-cxx/encoding/buffer-stream.hpp"
26#include "ndn-cxx/encoding/encoding-buffer.hpp"
27#include "ndn-cxx/encoding/tlv.hpp"
28#include "ndn-cxx/security/transform.hpp"
29#include "ndn-cxx/util/string-helper.hpp"
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070030
Alexander Afanasyev6a05b4b2014-07-18 17:23:00 -070031#include <boost/asio/buffer.hpp>
Junxiao Shid2777fa2017-07-27 18:35:34 +000032#include <boost/range/adaptor/reversed.hpp>
Davide Pesaventoe245b052017-10-31 13:00:44 -040033#include <cstring>
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080034
35namespace ndn {
36
Junxiao Shidc4277a2017-07-17 11:34:02 +000037BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Block>));
Junxiao Shi81a6c5d2014-11-30 00:14:42 -070038
susmit8b156552016-01-12 13:10:55 -070039const size_t MAX_SIZE_OF_BLOCK_FROM_STREAM = MAX_NDN_PACKET_SIZE;
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070040
Junxiao Shidb7464d2017-07-13 03:11:17 +000041// ---- constructor, creation, assignment ----
42
Davide Pesavento3a3e1882018-07-17 14:49:15 -040043Block::Block() = default;
44
45Block::Block(const Block&) = default;
46
47Block&
48Block::operator=(const Block&) = default;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080049
Alexander Afanasyev15151312014-02-16 00:53:51 -080050Block::Block(const EncodingBuffer& buffer)
Davide Pesavento570b20d2018-07-15 21:53:14 -040051 : Block(buffer.getBuffer(), buffer.begin(), buffer.end(), true)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080052{
53}
54
Alexander Afanasyeva465e972014-03-22 17:21:49 -070055Block::Block(const ConstBufferPtr& buffer)
Junxiao Shidb7464d2017-07-13 03:11:17 +000056 : Block(buffer, buffer->begin(), buffer->end(), true)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080057{
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080058}
59
Junxiao Shidb7464d2017-07-13 03:11:17 +000060Block::Block(ConstBufferPtr buffer, Buffer::const_iterator begin, Buffer::const_iterator end,
61 bool verifyLength)
62 : m_buffer(std::move(buffer))
Alexander Afanasyev187bc482014-02-06 15:04:04 -080063 , m_begin(begin)
64 , m_end(end)
Junxiao Shidb7464d2017-07-13 03:11:17 +000065 , m_valueBegin(m_begin)
66 , m_valueEnd(m_end)
Alexander Afanasyev380420b2014-02-09 20:52:29 -080067 , m_size(m_end - m_begin)
Alexander Afanasyev187bc482014-02-06 15:04:04 -080068{
Junxiao Shidb7464d2017-07-13 03:11:17 +000069 if (m_buffer->size() == 0) {
Davide Pesavento923ba442019-02-12 22:00:38 -050070 NDN_THROW(std::invalid_argument("Buffer is empty"));
Junxiao Shidb7464d2017-07-13 03:11:17 +000071 }
Alexander Afanasyev380420b2014-02-09 20:52:29 -080072
Junxiao Shidb7464d2017-07-13 03:11:17 +000073 const uint8_t* bufferBegin = &m_buffer->front();
74 const uint8_t* bufferEnd = bufferBegin + m_buffer->size();
75 if (&*begin < bufferBegin || &*begin > bufferEnd ||
76 &*end < bufferBegin || &*end > bufferEnd) {
Davide Pesavento923ba442019-02-12 22:00:38 -050077 NDN_THROW(std::invalid_argument("Begin/end iterators point outside the buffer"));
Junxiao Shidb7464d2017-07-13 03:11:17 +000078 }
79
80 m_type = tlv::readType(m_valueBegin, m_valueEnd);
81 uint64_t length = tlv::readVarNumber(m_valueBegin, m_valueEnd);
82 // m_valueBegin now points to TLV-VALUE
83
84 if (verifyLength && length != static_cast<uint64_t>(m_valueEnd - m_valueBegin)) {
Davide Pesavento923ba442019-02-12 22:00:38 -050085 NDN_THROW(Error("TLV-LENGTH does not match buffer size"));
Alexander Afanasyev4448d292015-08-09 20:11:37 -070086 }
87}
88
Junxiao Shidb7464d2017-07-13 03:11:17 +000089Block::Block(const Block& block, Buffer::const_iterator begin, Buffer::const_iterator end,
90 bool verifyLength)
91 : Block(block.m_buffer, begin, end, verifyLength)
92{
93}
94
95Block::Block(ConstBufferPtr buffer, uint32_t type,
96 Buffer::const_iterator begin, Buffer::const_iterator end,
97 Buffer::const_iterator valueBegin, Buffer::const_iterator valueEnd)
98 : m_buffer(std::move(buffer))
Alexander Afanasyev4448d292015-08-09 20:11:37 -070099 , m_begin(begin)
100 , m_end(end)
Junxiao Shidb7464d2017-07-13 03:11:17 +0000101 , m_valueBegin(valueBegin)
102 , m_valueEnd(valueEnd)
103 , m_type(type)
Alexander Afanasyev4448d292015-08-09 20:11:37 -0700104 , m_size(m_end - m_begin)
105{
Alexander Afanasyev187bc482014-02-06 15:04:04 -0800106}
107
Junxiao Shidb7464d2017-07-13 03:11:17 +0000108Block::Block(const uint8_t* buf, size_t bufSize)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800109{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000110 const uint8_t* pos = buf;
111 const uint8_t* const end = buf + bufSize;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700112
Junxiao Shidb7464d2017-07-13 03:11:17 +0000113 m_type = tlv::readType(pos, end);
114 uint64_t length = tlv::readVarNumber(pos, end);
115 // pos now points to TLV-VALUE
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700116
Davide Pesavento3a3e1882018-07-17 14:49:15 -0400117 BOOST_ASSERT(pos <= end);
Junxiao Shidb7464d2017-07-13 03:11:17 +0000118 if (length > static_cast<uint64_t>(end - pos)) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500119 NDN_THROW(Error("Not enough bytes in the buffer to fully parse TLV"));
Junxiao Shidb7464d2017-07-13 03:11:17 +0000120 }
Davide Pesavento3a3e1882018-07-17 14:49:15 -0400121
122 BOOST_ASSERT(pos > buf);
123 uint64_t typeLengthSize = static_cast<uint64_t>(pos - buf);
Junxiao Shidb7464d2017-07-13 03:11:17 +0000124 m_size = typeLengthSize + length;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800125
Junxiao Shidb7464d2017-07-13 03:11:17 +0000126 m_buffer = make_shared<Buffer>(buf, m_size);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800127 m_begin = m_buffer->begin();
Junxiao Shidb7464d2017-07-13 03:11:17 +0000128 m_end = m_valueEnd = m_buffer->end();
129 m_valueBegin = m_begin + typeLengthSize;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800130}
131
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800132Block::Block(uint32_t type)
133 : m_type(type)
Junxiao Shidb7464d2017-07-13 03:11:17 +0000134 , m_size(tlv::sizeOfVarNumber(m_type) + tlv::sizeOfVarNumber(0))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800135{
136}
137
Junxiao Shidb7464d2017-07-13 03:11:17 +0000138Block::Block(uint32_t type, ConstBufferPtr value)
139 : m_buffer(std::move(value))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800140 , m_begin(m_buffer->end())
141 , m_end(m_buffer->end())
Junxiao Shidb7464d2017-07-13 03:11:17 +0000142 , m_valueBegin(m_buffer->begin())
143 , m_valueEnd(m_buffer->end())
144 , m_type(type)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800145{
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600146 m_size = tlv::sizeOfVarNumber(m_type) + tlv::sizeOfVarNumber(value_size()) + value_size();
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800147}
148
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700149Block::Block(uint32_t type, const Block& value)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800150 : m_buffer(value.m_buffer)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800151 , m_begin(m_buffer->end())
152 , m_end(m_buffer->end())
Junxiao Shidb7464d2017-07-13 03:11:17 +0000153 , m_valueBegin(value.begin())
154 , m_valueEnd(value.end())
155 , m_type(type)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800156{
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600157 m_size = tlv::sizeOfVarNumber(m_type) + tlv::sizeOfVarNumber(value_size()) + value_size();
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800158}
159
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700160Block
161Block::fromStream(std::istream& is)
162{
Junxiao Shif0da7892015-04-04 22:16:16 -0700163 std::istream_iterator<uint8_t> begin(is >> std::noskipws);
164 std::istream_iterator<uint8_t> end;
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700165
Junxiao Shif0da7892015-04-04 22:16:16 -0700166 uint32_t type = tlv::readType(begin, end);
167 uint64_t length = tlv::readVarNumber(begin, end);
Junxiao Shi760cc7b2017-07-22 19:17:49 +0000168 if (begin != end) {
169 is.putback(*begin);
Junxiao Shif0da7892015-04-04 22:16:16 -0700170 }
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700171
Junxiao Shi760cc7b2017-07-22 19:17:49 +0000172 size_t tlSize = tlv::sizeOfVarNumber(type) + tlv::sizeOfVarNumber(length);
173 if (tlSize + length > MAX_SIZE_OF_BLOCK_FROM_STREAM) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500174 NDN_THROW(Error("TLV-LENGTH from stream exceeds limit"));
Junxiao Shidb7464d2017-07-13 03:11:17 +0000175 }
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700176
Junxiao Shi760cc7b2017-07-22 19:17:49 +0000177 EncodingBuffer eb(tlSize + length, length);
178 uint8_t* valueBuf = eb.buf();
179 is.read(reinterpret_cast<char*>(valueBuf), length);
180 if (length != static_cast<uint64_t>(is.gcount())) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500181 NDN_THROW(Error("Not enough bytes from stream to fully parse TLV"));
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700182 }
183
Junxiao Shi760cc7b2017-07-22 19:17:49 +0000184 eb.prependVarNumber(length);
185 eb.prependVarNumber(type);
186
187 // TLV-VALUE is directly written into eb.buf(), eb.end() is not incremented, but eb.getBuffer()
188 // has the correct layout.
189 return Block(eb.getBuffer());
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700190}
191
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700192std::tuple<bool, Block>
193Block::fromBuffer(ConstBufferPtr buffer, size_t offset)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700194{
Davide Pesavento3b101d02018-07-21 22:44:09 -0400195 auto begin = buffer->begin() + offset;
196 auto pos = begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700197
Junxiao Shidb7464d2017-07-13 03:11:17 +0000198 uint32_t type = 0;
199 bool isOk = tlv::readType(pos, buffer->end(), type);
200 if (!isOk) {
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700201 return std::make_tuple(false, Block());
Junxiao Shidb7464d2017-07-13 03:11:17 +0000202 }
Davide Pesavento3b101d02018-07-21 22:44:09 -0400203
Junxiao Shidb7464d2017-07-13 03:11:17 +0000204 uint64_t length = 0;
205 isOk = tlv::readVarNumber(pos, buffer->end(), length);
206 if (!isOk) {
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700207 return std::make_tuple(false, Block());
Junxiao Shidb7464d2017-07-13 03:11:17 +0000208 }
209 // pos now points to TLV-VALUE
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700210
Junxiao Shidb7464d2017-07-13 03:11:17 +0000211 if (length > static_cast<uint64_t>(buffer->end() - pos)) {
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700212 return std::make_tuple(false, Block());
Junxiao Shidb7464d2017-07-13 03:11:17 +0000213 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700214
Davide Pesavento3b101d02018-07-21 22:44:09 -0400215 return std::make_tuple(true, Block(std::move(buffer), type, begin, pos + length, pos, pos + length));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700216}
217
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700218std::tuple<bool, Block>
Junxiao Shidb7464d2017-07-13 03:11:17 +0000219Block::fromBuffer(const uint8_t* buf, size_t bufSize)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700220{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000221 const uint8_t* pos = buf;
222 const uint8_t* const end = buf + bufSize;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700223
Mickey Sweatt632e0572014-04-20 00:36:32 -0700224 uint32_t type = 0;
Junxiao Shidb7464d2017-07-13 03:11:17 +0000225 bool isOk = tlv::readType(pos, end, type);
226 if (!isOk) {
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700227 return std::make_tuple(false, Block());
Junxiao Shidb7464d2017-07-13 03:11:17 +0000228 }
229 uint64_t length = 0;
230 isOk = tlv::readVarNumber(pos, end, length);
231 if (!isOk) {
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700232 return std::make_tuple(false, Block());
Junxiao Shidb7464d2017-07-13 03:11:17 +0000233 }
234 // pos now points to TLV-VALUE
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700235
Junxiao Shidb7464d2017-07-13 03:11:17 +0000236 if (length > static_cast<uint64_t>(end - pos)) {
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700237 return std::make_tuple(false, Block());
Junxiao Shidb7464d2017-07-13 03:11:17 +0000238 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700239
Junxiao Shidb7464d2017-07-13 03:11:17 +0000240 size_t typeLengthSize = pos - buf;
241 auto b = make_shared<Buffer>(buf, pos + length);
242 return std::make_tuple(true, Block(b, type, b->begin(), b->end(),
243 b->begin() + typeLengthSize, b->end()));
244}
245
246// ---- wire format ----
247
Davide Pesavento5c803b92019-02-02 19:23:48 -0500248void
249Block::reset() noexcept
Junxiao Shidb7464d2017-07-13 03:11:17 +0000250{
Davide Pesavento5c803b92019-02-02 19:23:48 -0500251 *this = {};
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700252}
253
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800254void
Davide Pesavento5c803b92019-02-02 19:23:48 -0500255Block::resetWire() noexcept
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700256{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000257 m_buffer.reset(); // discard underlying buffer by resetting shared_ptr
Davide Pesavento3a3e1882018-07-17 14:49:15 -0400258 m_begin = m_end = m_valueBegin = m_valueEnd = {};
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400259}
260
261Buffer::const_iterator
262Block::begin() const
263{
264 if (!hasWire())
Davide Pesavento923ba442019-02-12 22:00:38 -0500265 NDN_THROW(Error("Underlying wire buffer is empty"));
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400266
267 return m_begin;
268}
269
270Buffer::const_iterator
271Block::end() const
272{
273 if (!hasWire())
Davide Pesavento923ba442019-02-12 22:00:38 -0500274 NDN_THROW(Error("Underlying wire buffer is empty"));
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400275
276 return m_end;
277}
278
279const uint8_t*
280Block::wire() const
281{
282 if (!hasWire())
Davide Pesavento923ba442019-02-12 22:00:38 -0500283 NDN_THROW(Error("Underlying wire buffer is empty"));
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400284
285 return &*m_begin;
286}
287
288size_t
289Block::size() const
290{
Davide Pesavento6b330402019-04-24 00:14:01 -0400291 if (!isValid()) {
292 NDN_THROW(Error("Cannot determine size of invalid block"));
Junxiao Shidb7464d2017-07-13 03:11:17 +0000293 }
294
295 return m_size;
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400296}
297
Junxiao Shidb7464d2017-07-13 03:11:17 +0000298// ---- value ----
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400299
300const uint8_t*
Davide Pesavento5c803b92019-02-02 19:23:48 -0500301Block::value() const noexcept
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400302{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000303 return hasValue() ? &*m_valueBegin : nullptr;
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400304}
305
306size_t
Davide Pesavento5c803b92019-02-02 19:23:48 -0500307Block::value_size() const noexcept
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400308{
Davide Pesavento3a3e1882018-07-17 14:49:15 -0400309 return hasValue() ? static_cast<size_t>(m_valueEnd - m_valueBegin) : 0;
Junxiao Shidb7464d2017-07-13 03:11:17 +0000310}
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400311
Junxiao Shidb7464d2017-07-13 03:11:17 +0000312Block
313Block::blockFromValue() const
314{
315 if (!hasValue())
Davide Pesavento923ba442019-02-12 22:00:38 -0500316 NDN_THROW(Error("Block has no TLV-VALUE"));
Junxiao Shidb7464d2017-07-13 03:11:17 +0000317
318 return Block(*this, m_valueBegin, m_valueEnd, true);
319}
320
321// ---- sub elements ----
322
323void
324Block::parse() const
325{
326 if (!m_elements.empty() || value_size() == 0)
327 return;
328
329 Buffer::const_iterator begin = value_begin();
330 Buffer::const_iterator end = value_end();
331
332 while (begin != end) {
333 Buffer::const_iterator pos = begin;
334
335 uint32_t type = tlv::readType(pos, end);
336 uint64_t length = tlv::readVarNumber(pos, end);
337 if (length > static_cast<uint64_t>(end - pos)) {
338 m_elements.clear();
Davide Pesavento923ba442019-02-12 22:00:38 -0500339 NDN_THROW(Error("TLV-LENGTH of sub-element of type " + to_string(type) +
340 " exceeds TLV-VALUE boundary of parent block"));
Junxiao Shidb7464d2017-07-13 03:11:17 +0000341 }
342 // pos now points to TLV-VALUE of sub element
343
344 Buffer::const_iterator subEnd = pos + length;
345 m_elements.emplace_back(m_buffer, type, begin, subEnd, pos, subEnd);
346
347 begin = subEnd;
348 }
349}
350
351void
352Block::encode()
353{
354 if (hasWire())
355 return;
356
Junxiao Shid2777fa2017-07-27 18:35:34 +0000357 EncodingEstimator estimator;
358 size_t estimatedSize = encode(estimator);
Junxiao Shidb7464d2017-07-13 03:11:17 +0000359
Junxiao Shid2777fa2017-07-27 18:35:34 +0000360 EncodingBuffer buffer(estimatedSize, 0);
361 encode(buffer);
362}
363
364size_t
365Block::encode(EncodingEstimator& estimator) const
366{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000367 if (hasValue()) {
Junxiao Shid2777fa2017-07-27 18:35:34 +0000368 return m_size;
Junxiao Shidb7464d2017-07-13 03:11:17 +0000369 }
Junxiao Shid2777fa2017-07-27 18:35:34 +0000370
Junxiao Shi72c0c642018-04-20 15:41:09 +0000371 size_t len = encodeValue(estimator);
372 len += estimator.prependVarNumber(len);
373 len += estimator.prependVarNumber(m_type);
374 return len;
375}
376
377size_t
378Block::encodeValue(EncodingEstimator& estimator) const
379{
Junxiao Shid2777fa2017-07-27 18:35:34 +0000380 size_t len = 0;
381 for (const Block& element : m_elements | boost::adaptors::reversed) {
382 len += element.encode(estimator);
383 }
Junxiao Shid2777fa2017-07-27 18:35:34 +0000384 return len;
385}
386
387size_t
388Block::encode(EncodingBuffer& encoder)
389{
390 size_t len = 0;
391 m_end = encoder.begin();
392 if (hasValue()) {
393 len += encoder.prependRange(m_valueBegin, m_valueEnd);
Junxiao Shidb7464d2017-07-13 03:11:17 +0000394 }
395 else {
Junxiao Shid2777fa2017-07-27 18:35:34 +0000396 for (Block& element : m_elements | boost::adaptors::reversed) {
397 len += element.encode(encoder);
Junxiao Shidb7464d2017-07-13 03:11:17 +0000398 }
399 }
Junxiao Shid2777fa2017-07-27 18:35:34 +0000400 m_valueEnd = m_end;
401 m_valueBegin = encoder.begin();
Junxiao Shidb7464d2017-07-13 03:11:17 +0000402
Junxiao Shid2777fa2017-07-27 18:35:34 +0000403 len += encoder.prependVarNumber(len);
404 len += encoder.prependVarNumber(m_type);
405 m_begin = encoder.begin();
Junxiao Shidb7464d2017-07-13 03:11:17 +0000406
Junxiao Shid2777fa2017-07-27 18:35:34 +0000407 m_buffer = encoder.getBuffer();
408 m_size = len;
409 return len;
Junxiao Shidb7464d2017-07-13 03:11:17 +0000410}
411
412const Block&
413Block::get(uint32_t type) const
414{
415 auto it = this->find(type);
416 if (it != m_elements.end()) {
417 return *it;
418 }
419
Davide Pesavento923ba442019-02-12 22:00:38 -0500420 NDN_THROW(Error("No sub-element of type " + to_string(type) +
421 " found in block of type " + to_string(m_type)));
Junxiao Shidb7464d2017-07-13 03:11:17 +0000422}
423
424Block::element_const_iterator
425Block::find(uint32_t type) const
426{
427 return std::find_if(m_elements.begin(), m_elements.end(),
428 [type] (const Block& subBlock) { return subBlock.type() == type; });
429}
430
431void
432Block::remove(uint32_t type)
433{
434 resetWire();
435
436 auto it = std::remove_if(m_elements.begin(), m_elements.end(),
437 [type] (const Block& subBlock) { return subBlock.type() == type; });
Davide Pesavento5c803b92019-02-02 19:23:48 -0500438 m_elements.erase(it, m_elements.end());
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400439}
440
441Block::element_iterator
Joao Pereira7476ebf2015-07-07 14:54:39 -0400442Block::erase(Block::element_const_iterator position)
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400443{
444 resetWire();
Junxiao Shidb7464d2017-07-13 03:11:17 +0000445 return m_elements.erase(position);
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400446}
447
448Block::element_iterator
Joao Pereira7476ebf2015-07-07 14:54:39 -0400449Block::erase(Block::element_const_iterator first, Block::element_const_iterator last)
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400450{
451 resetWire();
Junxiao Shidb7464d2017-07-13 03:11:17 +0000452 return m_elements.erase(first, last);
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400453}
454
455void
456Block::push_back(const Block& element)
457{
458 resetWire();
Junxiao Shidb7464d2017-07-13 03:11:17 +0000459 m_elements.push_back(element);
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400460}
461
Joao Pereira7476ebf2015-07-07 14:54:39 -0400462Block::element_iterator
463Block::insert(Block::element_const_iterator pos, const Block& element)
464{
465 resetWire();
Junxiao Shidb7464d2017-07-13 03:11:17 +0000466 return m_elements.insert(pos, element);
Joao Pereira7476ebf2015-07-07 14:54:39 -0400467}
468
Junxiao Shidb7464d2017-07-13 03:11:17 +0000469// ---- misc ----
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400470
Junxiao Shidb7464d2017-07-13 03:11:17 +0000471Block::operator boost::asio::const_buffer() const
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400472{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000473 return boost::asio::const_buffer(wire(), size());
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400474}
475
476bool
Junxiao Shidb7464d2017-07-13 03:11:17 +0000477operator==(const Block& lhs, const Block& rhs)
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400478{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000479 return lhs.type() == rhs.type() &&
480 lhs.value_size() == rhs.value_size() &&
Davide Pesaventoe245b052017-10-31 13:00:44 -0400481 (lhs.value_size() == 0 ||
482 std::memcmp(lhs.value(), rhs.value(), lhs.value_size()) == 0);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700483}
484
Junxiao Shi72c0c642018-04-20 15:41:09 +0000485std::ostream&
486operator<<(std::ostream& os, const Block& block)
487{
488 auto oldFmt = os.flags(std::ios_base::dec);
489
Davide Pesavento6b330402019-04-24 00:14:01 -0400490 if (!block.isValid()) {
Junxiao Shi72c0c642018-04-20 15:41:09 +0000491 os << "[invalid]";
492 }
493 else if (!block.m_elements.empty()) {
494 EncodingEstimator estimator;
495 size_t tlvLength = block.encodeValue(estimator);
496 os << block.type() << '[' << tlvLength << "]={";
497 std::copy(block.elements_begin(), block.elements_end(), make_ostream_joiner(os, ','));
498 os << '}';
499 }
500 else if (block.value_size() > 0) {
501 os << block.type() << '[' << block.value_size() << "]=";
502 printHex(os, block.value(), block.value_size(), true);
503 }
504 else {
505 os << block.type() << "[empty]";
506 }
507
508 os.flags(oldFmt);
509 return os;
510}
511
Junxiao Shi2b322eb2018-08-24 10:43:27 -0600512Block
513operator "" _block(const char* input, std::size_t len)
514{
515 namespace t = security::transform;
516 t::StepSource ss;
517 OBufferStream os;
518 ss >> t::hexDecode() >> t::streamSink(os);
519
520 for (const char* end = input + len; input != end; ++input) {
521 if (std::strchr("0123456789ABCDEF", *input) != nullptr) {
522 ss.write(reinterpret_cast<const uint8_t*>(input), 1);
523 }
524 }
525
526 try {
527 ss.end();
528 }
529 catch (const t::Error&) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500530 NDN_THROW(std::invalid_argument("Input has odd number of hexadecimal digits"));
Junxiao Shi2b322eb2018-08-24 10:43:27 -0600531 }
532
533 return Block(os.buf());
534}
535
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800536} // namespace ndn