blob: 09acafdb77563c1f87a94aef5d4a344b2487eea1 [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/*
3 * Copyright (c) 2013-2017 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"
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070028
Alexander Afanasyev6a05b4b2014-07-18 17:23:00 -070029#include <boost/asio/buffer.hpp>
Junxiao Shid2777fa2017-07-27 18:35:34 +000030#include <boost/range/adaptor/reversed.hpp>
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080031
32namespace ndn {
33
Junxiao Shidc4277a2017-07-17 11:34:02 +000034BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Block>));
Junxiao Shi88681402015-06-30 09:58:53 -070035#if NDN_CXX_HAVE_IS_NOTHROW_MOVE_CONSTRUCTIBLE
36static_assert(std::is_nothrow_move_constructible<Block>::value,
37 "Block must be MoveConstructible with noexcept");
38#endif // NDN_CXX_HAVE_IS_NOTHROW_MOVE_CONSTRUCTIBLE
Junxiao Shi81a6c5d2014-11-30 00:14:42 -070039
Junxiao Shi88681402015-06-30 09:58:53 -070040#if NDN_CXX_HAVE_IS_NOTHROW_MOVE_ASSIGNABLE
41static_assert(std::is_nothrow_move_assignable<Block>::value,
42 "Block must be MoveAssignable with noexcept");
43#endif // NDN_CXX_HAVE_IS_NOTHROW_MOVE_ASSIGNABLE
Junxiao Shi81a6c5d2014-11-30 00:14:42 -070044
susmit8b156552016-01-12 13:10:55 -070045const size_t MAX_SIZE_OF_BLOCK_FROM_STREAM = MAX_NDN_PACKET_SIZE;
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070046
Junxiao Shidb7464d2017-07-13 03:11:17 +000047// ---- constructor, creation, assignment ----
48
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080049Block::Block()
50 : m_type(std::numeric_limits<uint32_t>::max())
Junxiao Shidb7464d2017-07-13 03:11:17 +000051 , m_size(0)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080052{
53}
54
Alexander Afanasyev15151312014-02-16 00:53:51 -080055Block::Block(const EncodingBuffer& buffer)
Junxiao Shidb7464d2017-07-13 03:11:17 +000056 : Block(const_cast<EncodingBuffer&>(buffer).getBuffer(), buffer.begin(), buffer.end(), true)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080057{
58}
59
Alexander Afanasyeva465e972014-03-22 17:21:49 -070060Block::Block(const ConstBufferPtr& buffer)
Junxiao Shidb7464d2017-07-13 03:11:17 +000061 : Block(buffer, buffer->begin(), buffer->end(), true)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080062{
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080063}
64
Junxiao Shidb7464d2017-07-13 03:11:17 +000065Block::Block(ConstBufferPtr buffer, Buffer::const_iterator begin, Buffer::const_iterator end,
66 bool verifyLength)
67 : m_buffer(std::move(buffer))
Alexander Afanasyev187bc482014-02-06 15:04:04 -080068 , m_begin(begin)
69 , m_end(end)
Junxiao Shidb7464d2017-07-13 03:11:17 +000070 , m_valueBegin(m_begin)
71 , m_valueEnd(m_end)
Alexander Afanasyev380420b2014-02-09 20:52:29 -080072 , m_size(m_end - m_begin)
Alexander Afanasyev187bc482014-02-06 15:04:04 -080073{
Junxiao Shidb7464d2017-07-13 03:11:17 +000074 if (m_buffer->size() == 0) {
75 BOOST_THROW_EXCEPTION(std::invalid_argument("buffer is empty"));
76 }
Alexander Afanasyev380420b2014-02-09 20:52:29 -080077
Junxiao Shidb7464d2017-07-13 03:11:17 +000078 const uint8_t* bufferBegin = &m_buffer->front();
79 const uint8_t* bufferEnd = bufferBegin + m_buffer->size();
80 if (&*begin < bufferBegin || &*begin > bufferEnd ||
81 &*end < bufferBegin || &*end > bufferEnd) {
82 BOOST_THROW_EXCEPTION(std::invalid_argument("begin/end iterators points out of the buffer"));
83 }
84
85 m_type = tlv::readType(m_valueBegin, m_valueEnd);
86 uint64_t length = tlv::readVarNumber(m_valueBegin, m_valueEnd);
87 // m_valueBegin now points to TLV-VALUE
88
89 if (verifyLength && length != static_cast<uint64_t>(m_valueEnd - m_valueBegin)) {
90 BOOST_THROW_EXCEPTION(Error("TLV-LENGTH doesn't match buffer size"));
Alexander Afanasyev4448d292015-08-09 20:11:37 -070091 }
92}
93
Junxiao Shidb7464d2017-07-13 03:11:17 +000094Block::Block(const Block& block, Buffer::const_iterator begin, Buffer::const_iterator end,
95 bool verifyLength)
96 : Block(block.m_buffer, begin, end, verifyLength)
97{
98}
99
100Block::Block(ConstBufferPtr buffer, uint32_t type,
101 Buffer::const_iterator begin, Buffer::const_iterator end,
102 Buffer::const_iterator valueBegin, Buffer::const_iterator valueEnd)
103 : m_buffer(std::move(buffer))
Alexander Afanasyev4448d292015-08-09 20:11:37 -0700104 , m_begin(begin)
105 , m_end(end)
Junxiao Shidb7464d2017-07-13 03:11:17 +0000106 , m_valueBegin(valueBegin)
107 , m_valueEnd(valueEnd)
108 , m_type(type)
Alexander Afanasyev4448d292015-08-09 20:11:37 -0700109 , m_size(m_end - m_begin)
110{
Alexander Afanasyev187bc482014-02-06 15:04:04 -0800111}
112
Junxiao Shidb7464d2017-07-13 03:11:17 +0000113Block::Block(const uint8_t* buf, size_t bufSize)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800114{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000115 const uint8_t* pos = buf;
116 const uint8_t* const end = buf + bufSize;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700117
Junxiao Shidb7464d2017-07-13 03:11:17 +0000118 m_type = tlv::readType(pos, end);
119 uint64_t length = tlv::readVarNumber(pos, end);
120 // pos now points to TLV-VALUE
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700121
Junxiao Shidb7464d2017-07-13 03:11:17 +0000122 if (length > static_cast<uint64_t>(end - pos)) {
Junxiao Shi760cc7b2017-07-22 19:17:49 +0000123 BOOST_THROW_EXCEPTION(Error("Not enough bytes in the buffer to fully parse TLV"));
Junxiao Shidb7464d2017-07-13 03:11:17 +0000124 }
125 size_t typeLengthSize = pos - buf;
126 m_size = typeLengthSize + length;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800127
Junxiao Shidb7464d2017-07-13 03:11:17 +0000128 m_buffer = make_shared<Buffer>(buf, m_size);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800129 m_begin = m_buffer->begin();
Junxiao Shidb7464d2017-07-13 03:11:17 +0000130 m_end = m_valueEnd = m_buffer->end();
131 m_valueBegin = m_begin + typeLengthSize;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800132}
133
Junxiao Shidb7464d2017-07-13 03:11:17 +0000134Block::Block(const void* buf, size_t bufSize)
135 : Block(reinterpret_cast<const uint8_t*>(buf), bufSize)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800136{
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800137}
138
139Block::Block(uint32_t type)
140 : m_type(type)
Junxiao Shidb7464d2017-07-13 03:11:17 +0000141 , m_size(tlv::sizeOfVarNumber(m_type) + tlv::sizeOfVarNumber(0))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800142{
143}
144
Junxiao Shidb7464d2017-07-13 03:11:17 +0000145Block::Block(uint32_t type, ConstBufferPtr value)
146 : m_buffer(std::move(value))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800147 , m_begin(m_buffer->end())
148 , m_end(m_buffer->end())
Junxiao Shidb7464d2017-07-13 03:11:17 +0000149 , m_valueBegin(m_buffer->begin())
150 , m_valueEnd(m_buffer->end())
151 , m_type(type)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800152{
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600153 m_size = tlv::sizeOfVarNumber(m_type) + tlv::sizeOfVarNumber(value_size()) + value_size();
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800154}
155
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700156Block::Block(uint32_t type, const Block& value)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800157 : m_buffer(value.m_buffer)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800158 , m_begin(m_buffer->end())
159 , m_end(m_buffer->end())
Junxiao Shidb7464d2017-07-13 03:11:17 +0000160 , m_valueBegin(value.begin())
161 , m_valueEnd(value.end())
162 , m_type(type)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800163{
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600164 m_size = tlv::sizeOfVarNumber(m_type) + tlv::sizeOfVarNumber(value_size()) + value_size();
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800165}
166
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700167Block
168Block::fromStream(std::istream& is)
169{
Junxiao Shif0da7892015-04-04 22:16:16 -0700170 std::istream_iterator<uint8_t> begin(is >> std::noskipws);
171 std::istream_iterator<uint8_t> end;
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700172
Junxiao Shif0da7892015-04-04 22:16:16 -0700173 uint32_t type = tlv::readType(begin, end);
174 uint64_t length = tlv::readVarNumber(begin, end);
Junxiao Shi760cc7b2017-07-22 19:17:49 +0000175 if (begin != end) {
176 is.putback(*begin);
Junxiao Shif0da7892015-04-04 22:16:16 -0700177 }
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700178
Junxiao Shi760cc7b2017-07-22 19:17:49 +0000179 size_t tlSize = tlv::sizeOfVarNumber(type) + tlv::sizeOfVarNumber(length);
180 if (tlSize + length > MAX_SIZE_OF_BLOCK_FROM_STREAM) {
181 BOOST_THROW_EXCEPTION(Error("TLV-LENGTH from stream exceeds limit"));
Junxiao Shidb7464d2017-07-13 03:11:17 +0000182 }
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700183
Junxiao Shi760cc7b2017-07-22 19:17:49 +0000184 EncodingBuffer eb(tlSize + length, length);
185 uint8_t* valueBuf = eb.buf();
186 is.read(reinterpret_cast<char*>(valueBuf), length);
187 if (length != static_cast<uint64_t>(is.gcount())) {
188 BOOST_THROW_EXCEPTION(Error("Not enough bytes from stream to fully parse TLV"));
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700189 }
190
Junxiao Shi760cc7b2017-07-22 19:17:49 +0000191 eb.prependVarNumber(length);
192 eb.prependVarNumber(type);
193
194 // TLV-VALUE is directly written into eb.buf(), eb.end() is not incremented, but eb.getBuffer()
195 // has the correct layout.
196 return Block(eb.getBuffer());
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700197}
198
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700199std::tuple<bool, Block>
200Block::fromBuffer(ConstBufferPtr buffer, size_t offset)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700201{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000202 const Buffer::const_iterator begin = buffer->begin() + offset;
203 Buffer::const_iterator pos = begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700204
Junxiao Shidb7464d2017-07-13 03:11:17 +0000205 uint32_t type = 0;
206 bool isOk = tlv::readType(pos, buffer->end(), type);
207 if (!isOk) {
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700208 return std::make_tuple(false, Block());
Junxiao Shidb7464d2017-07-13 03:11:17 +0000209 }
210 uint64_t length = 0;
211 isOk = tlv::readVarNumber(pos, buffer->end(), length);
212 if (!isOk) {
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700213 return std::make_tuple(false, Block());
Junxiao Shidb7464d2017-07-13 03:11:17 +0000214 }
215 // pos now points to TLV-VALUE
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700216
Junxiao Shidb7464d2017-07-13 03:11:17 +0000217 if (length > static_cast<uint64_t>(buffer->end() - pos)) {
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700218 return std::make_tuple(false, Block());
Junxiao Shidb7464d2017-07-13 03:11:17 +0000219 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700220
Junxiao Shidb7464d2017-07-13 03:11:17 +0000221 return std::make_tuple(true, Block(buffer, type, begin, pos + length, pos, pos + length));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700222}
223
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700224std::tuple<bool, Block>
Junxiao Shidb7464d2017-07-13 03:11:17 +0000225Block::fromBuffer(const uint8_t* buf, size_t bufSize)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700226{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000227 const uint8_t* pos = buf;
228 const uint8_t* const end = buf + bufSize;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700229
Mickey Sweatt632e0572014-04-20 00:36:32 -0700230 uint32_t type = 0;
Junxiao Shidb7464d2017-07-13 03:11:17 +0000231 bool isOk = tlv::readType(pos, end, type);
232 if (!isOk) {
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700233 return std::make_tuple(false, Block());
Junxiao Shidb7464d2017-07-13 03:11:17 +0000234 }
235 uint64_t length = 0;
236 isOk = tlv::readVarNumber(pos, end, length);
237 if (!isOk) {
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700238 return std::make_tuple(false, Block());
Junxiao Shidb7464d2017-07-13 03:11:17 +0000239 }
240 // pos now points to TLV-VALUE
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700241
Junxiao Shidb7464d2017-07-13 03:11:17 +0000242 if (length > static_cast<uint64_t>(end - pos)) {
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700243 return std::make_tuple(false, Block());
Junxiao Shidb7464d2017-07-13 03:11:17 +0000244 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700245
Junxiao Shidb7464d2017-07-13 03:11:17 +0000246 size_t typeLengthSize = pos - buf;
247 auto b = make_shared<Buffer>(buf, pos + length);
248 return std::make_tuple(true, Block(b, type, b->begin(), b->end(),
249 b->begin() + typeLengthSize, b->end()));
250}
251
252// ---- wire format ----
253
254bool
255Block::hasWire() const
256{
257 return m_buffer != nullptr && m_begin != m_end;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700258}
259
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800260void
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700261Block::reset()
262{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000263 this->resetWire();
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700264
265 m_type = std::numeric_limits<uint32_t>::max();
Junxiao Shidb7464d2017-07-13 03:11:17 +0000266 m_elements.clear();
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700267}
268
269void
270Block::resetWire()
271{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000272 m_buffer.reset(); // discard underlying buffer by resetting shared_ptr
273 m_begin = m_end = m_valueBegin = m_valueEnd = Buffer::const_iterator();
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400274}
275
276Buffer::const_iterator
277Block::begin() const
278{
279 if (!hasWire())
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700280 BOOST_THROW_EXCEPTION(Error("Underlying wire buffer is empty"));
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400281
282 return m_begin;
283}
284
285Buffer::const_iterator
286Block::end() const
287{
288 if (!hasWire())
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700289 BOOST_THROW_EXCEPTION(Error("Underlying wire buffer is empty"));
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400290
291 return m_end;
292}
293
294const uint8_t*
295Block::wire() const
296{
297 if (!hasWire())
Junxiao Shidb7464d2017-07-13 03:11:17 +0000298 BOOST_THROW_EXCEPTION(Error("Underlying wire buffer is empty"));
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400299
300 return &*m_begin;
301}
302
303size_t
304Block::size() const
305{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000306 if (empty()) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700307 BOOST_THROW_EXCEPTION(Error("Block size cannot be determined (undefined block size)"));
Junxiao Shidb7464d2017-07-13 03:11:17 +0000308 }
309
310 return m_size;
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400311}
312
Junxiao Shidb7464d2017-07-13 03:11:17 +0000313// ---- value ----
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400314
315const uint8_t*
316Block::value() const
317{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000318 return hasValue() ? &*m_valueBegin : nullptr;
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400319}
320
321size_t
322Block::value_size() const
323{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000324 return hasValue() ? m_valueEnd - m_valueBegin : 0;
325}
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400326
Junxiao Shidb7464d2017-07-13 03:11:17 +0000327Block
328Block::blockFromValue() const
329{
330 if (!hasValue())
331 BOOST_THROW_EXCEPTION(Error("Block has no TLV-VALUE"));
332
333 return Block(*this, m_valueBegin, m_valueEnd, true);
334}
335
336// ---- sub elements ----
337
338void
339Block::parse() const
340{
341 if (!m_elements.empty() || value_size() == 0)
342 return;
343
344 Buffer::const_iterator begin = value_begin();
345 Buffer::const_iterator end = value_end();
346
347 while (begin != end) {
348 Buffer::const_iterator pos = begin;
349
350 uint32_t type = tlv::readType(pos, end);
351 uint64_t length = tlv::readVarNumber(pos, end);
352 if (length > static_cast<uint64_t>(end - pos)) {
353 m_elements.clear();
354 BOOST_THROW_EXCEPTION(Error("TLV-LENGTH of sub-element of type " + to_string(type) +
355 " exceeds TLV-VALUE boundary of parent block"));
356 }
357 // pos now points to TLV-VALUE of sub element
358
359 Buffer::const_iterator subEnd = pos + length;
360 m_elements.emplace_back(m_buffer, type, begin, subEnd, pos, subEnd);
361
362 begin = subEnd;
363 }
364}
365
366void
367Block::encode()
368{
369 if (hasWire())
370 return;
371
Junxiao Shid2777fa2017-07-27 18:35:34 +0000372 EncodingEstimator estimator;
373 size_t estimatedSize = encode(estimator);
Junxiao Shidb7464d2017-07-13 03:11:17 +0000374
Junxiao Shid2777fa2017-07-27 18:35:34 +0000375 EncodingBuffer buffer(estimatedSize, 0);
376 encode(buffer);
377}
378
379size_t
380Block::encode(EncodingEstimator& estimator) const
381{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000382 if (hasValue()) {
Junxiao Shid2777fa2017-07-27 18:35:34 +0000383 return m_size;
Junxiao Shidb7464d2017-07-13 03:11:17 +0000384 }
Junxiao Shid2777fa2017-07-27 18:35:34 +0000385
386 size_t len = 0;
387 for (const Block& element : m_elements | boost::adaptors::reversed) {
388 len += element.encode(estimator);
389 }
390 len += estimator.prependVarNumber(len);
391 len += estimator.prependVarNumber(m_type);
392 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();
Joao Pereira7476ebf2015-07-07 14:54:39 -0400453
454#ifdef NDN_CXX_HAVE_VECTOR_INSERT_ERASE_CONST_ITERATOR
Junxiao Shidb7464d2017-07-13 03:11:17 +0000455 return m_elements.erase(position);
Joao Pereira7476ebf2015-07-07 14:54:39 -0400456#else
Junxiao Shidb7464d2017-07-13 03:11:17 +0000457 element_iterator it = m_elements.begin();
458 std::advance(it, std::distance(m_elements.cbegin(), position));
459 return m_elements.erase(it);
Joao Pereira7476ebf2015-07-07 14:54:39 -0400460#endif
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400461}
462
463Block::element_iterator
Joao Pereira7476ebf2015-07-07 14:54:39 -0400464Block::erase(Block::element_const_iterator first, Block::element_const_iterator last)
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400465{
466 resetWire();
Joao Pereira7476ebf2015-07-07 14:54:39 -0400467
468#ifdef NDN_CXX_HAVE_VECTOR_INSERT_ERASE_CONST_ITERATOR
Junxiao Shidb7464d2017-07-13 03:11:17 +0000469 return m_elements.erase(first, last);
Joao Pereira7476ebf2015-07-07 14:54:39 -0400470#else
Junxiao Shidb7464d2017-07-13 03:11:17 +0000471 element_iterator itStart = m_elements.begin();
472 element_iterator itEnd = m_elements.begin();
473 std::advance(itStart, std::distance(m_elements.cbegin(), first));
474 std::advance(itEnd, std::distance(m_elements.cbegin(), last));
475 return m_elements.erase(itStart, itEnd);
Joao Pereira7476ebf2015-07-07 14:54:39 -0400476#endif
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400477}
478
479void
480Block::push_back(const Block& element)
481{
482 resetWire();
Junxiao Shidb7464d2017-07-13 03:11:17 +0000483 m_elements.push_back(element);
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400484}
485
Joao Pereira7476ebf2015-07-07 14:54:39 -0400486Block::element_iterator
487Block::insert(Block::element_const_iterator pos, const Block& element)
488{
489 resetWire();
490
491#ifdef NDN_CXX_HAVE_VECTOR_INSERT_ERASE_CONST_ITERATOR
Junxiao Shidb7464d2017-07-13 03:11:17 +0000492 return m_elements.insert(pos, element);
Joao Pereira7476ebf2015-07-07 14:54:39 -0400493#else
Junxiao Shidb7464d2017-07-13 03:11:17 +0000494 element_iterator it = m_elements.begin();
495 std::advance(it, std::distance(m_elements.cbegin(), pos));
496 return m_elements.insert(it, element);
Joao Pereira7476ebf2015-07-07 14:54:39 -0400497#endif
498}
499
Junxiao Shidb7464d2017-07-13 03:11:17 +0000500// ---- misc ----
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400501
Junxiao Shidb7464d2017-07-13 03:11:17 +0000502Block::operator boost::asio::const_buffer() const
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400503{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000504 return boost::asio::const_buffer(wire(), size());
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400505}
506
507bool
Junxiao Shidb7464d2017-07-13 03:11:17 +0000508operator==(const Block& lhs, const Block& rhs)
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400509{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000510 return lhs.type() == rhs.type() &&
511 lhs.value_size() == rhs.value_size() &&
512 ::memcmp(lhs.value(), rhs.value(), lhs.value_size()) == 0;
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700513}
514
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800515} // namespace ndn