blob: 691bbdfe81c81e1dfb9a46ce0e6c18d566c64cd1 [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>
Davide Pesaventoe245b052017-10-31 13:00:44 -040031#include <cstring>
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080032
33namespace ndn {
34
Junxiao Shidc4277a2017-07-17 11:34:02 +000035BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Block>));
Junxiao Shi88681402015-06-30 09:58:53 -070036#if NDN_CXX_HAVE_IS_NOTHROW_MOVE_CONSTRUCTIBLE
37static_assert(std::is_nothrow_move_constructible<Block>::value,
38 "Block must be MoveConstructible with noexcept");
39#endif // NDN_CXX_HAVE_IS_NOTHROW_MOVE_CONSTRUCTIBLE
Junxiao Shi81a6c5d2014-11-30 00:14:42 -070040
Junxiao Shi88681402015-06-30 09:58:53 -070041#if NDN_CXX_HAVE_IS_NOTHROW_MOVE_ASSIGNABLE
42static_assert(std::is_nothrow_move_assignable<Block>::value,
43 "Block must be MoveAssignable with noexcept");
44#endif // NDN_CXX_HAVE_IS_NOTHROW_MOVE_ASSIGNABLE
Junxiao Shi81a6c5d2014-11-30 00:14:42 -070045
susmit8b156552016-01-12 13:10:55 -070046const size_t MAX_SIZE_OF_BLOCK_FROM_STREAM = MAX_NDN_PACKET_SIZE;
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070047
Junxiao Shidb7464d2017-07-13 03:11:17 +000048// ---- constructor, creation, assignment ----
49
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080050Block::Block()
51 : m_type(std::numeric_limits<uint32_t>::max())
Junxiao Shidb7464d2017-07-13 03:11:17 +000052 , m_size(0)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080053{
54}
55
Alexander Afanasyev15151312014-02-16 00:53:51 -080056Block::Block(const EncodingBuffer& buffer)
Junxiao Shidb7464d2017-07-13 03:11:17 +000057 : Block(const_cast<EncodingBuffer&>(buffer).getBuffer(), buffer.begin(), buffer.end(), true)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080058{
59}
60
Alexander Afanasyeva465e972014-03-22 17:21:49 -070061Block::Block(const ConstBufferPtr& buffer)
Junxiao Shidb7464d2017-07-13 03:11:17 +000062 : Block(buffer, buffer->begin(), buffer->end(), true)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080063{
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080064}
65
Junxiao Shidb7464d2017-07-13 03:11:17 +000066Block::Block(ConstBufferPtr buffer, Buffer::const_iterator begin, Buffer::const_iterator end,
67 bool verifyLength)
68 : m_buffer(std::move(buffer))
Alexander Afanasyev187bc482014-02-06 15:04:04 -080069 , m_begin(begin)
70 , m_end(end)
Junxiao Shidb7464d2017-07-13 03:11:17 +000071 , m_valueBegin(m_begin)
72 , m_valueEnd(m_end)
Alexander Afanasyev380420b2014-02-09 20:52:29 -080073 , m_size(m_end - m_begin)
Alexander Afanasyev187bc482014-02-06 15:04:04 -080074{
Junxiao Shidb7464d2017-07-13 03:11:17 +000075 if (m_buffer->size() == 0) {
76 BOOST_THROW_EXCEPTION(std::invalid_argument("buffer is empty"));
77 }
Alexander Afanasyev380420b2014-02-09 20:52:29 -080078
Junxiao Shidb7464d2017-07-13 03:11:17 +000079 const uint8_t* bufferBegin = &m_buffer->front();
80 const uint8_t* bufferEnd = bufferBegin + m_buffer->size();
81 if (&*begin < bufferBegin || &*begin > bufferEnd ||
82 &*end < bufferBegin || &*end > bufferEnd) {
83 BOOST_THROW_EXCEPTION(std::invalid_argument("begin/end iterators points out of the buffer"));
84 }
85
86 m_type = tlv::readType(m_valueBegin, m_valueEnd);
87 uint64_t length = tlv::readVarNumber(m_valueBegin, m_valueEnd);
88 // m_valueBegin now points to TLV-VALUE
89
90 if (verifyLength && length != static_cast<uint64_t>(m_valueEnd - m_valueBegin)) {
91 BOOST_THROW_EXCEPTION(Error("TLV-LENGTH doesn't match buffer size"));
Alexander Afanasyev4448d292015-08-09 20:11:37 -070092 }
93}
94
Junxiao Shidb7464d2017-07-13 03:11:17 +000095Block::Block(const Block& block, Buffer::const_iterator begin, Buffer::const_iterator end,
96 bool verifyLength)
97 : Block(block.m_buffer, begin, end, verifyLength)
98{
99}
100
101Block::Block(ConstBufferPtr buffer, uint32_t type,
102 Buffer::const_iterator begin, Buffer::const_iterator end,
103 Buffer::const_iterator valueBegin, Buffer::const_iterator valueEnd)
104 : m_buffer(std::move(buffer))
Alexander Afanasyev4448d292015-08-09 20:11:37 -0700105 , m_begin(begin)
106 , m_end(end)
Junxiao Shidb7464d2017-07-13 03:11:17 +0000107 , m_valueBegin(valueBegin)
108 , m_valueEnd(valueEnd)
109 , m_type(type)
Alexander Afanasyev4448d292015-08-09 20:11:37 -0700110 , m_size(m_end - m_begin)
111{
Alexander Afanasyev187bc482014-02-06 15:04:04 -0800112}
113
Junxiao Shidb7464d2017-07-13 03:11:17 +0000114Block::Block(const uint8_t* buf, size_t bufSize)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800115{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000116 const uint8_t* pos = buf;
117 const uint8_t* const end = buf + bufSize;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700118
Junxiao Shidb7464d2017-07-13 03:11:17 +0000119 m_type = tlv::readType(pos, end);
120 uint64_t length = tlv::readVarNumber(pos, end);
121 // pos now points to TLV-VALUE
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700122
Junxiao Shidb7464d2017-07-13 03:11:17 +0000123 if (length > static_cast<uint64_t>(end - pos)) {
Junxiao Shi760cc7b2017-07-22 19:17:49 +0000124 BOOST_THROW_EXCEPTION(Error("Not enough bytes in the buffer to fully parse TLV"));
Junxiao Shidb7464d2017-07-13 03:11:17 +0000125 }
126 size_t typeLengthSize = pos - buf;
127 m_size = typeLengthSize + length;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800128
Junxiao Shidb7464d2017-07-13 03:11:17 +0000129 m_buffer = make_shared<Buffer>(buf, m_size);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800130 m_begin = m_buffer->begin();
Junxiao Shidb7464d2017-07-13 03:11:17 +0000131 m_end = m_valueEnd = m_buffer->end();
132 m_valueBegin = m_begin + typeLengthSize;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800133}
134
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800135Block::Block(uint32_t type)
136 : m_type(type)
Junxiao Shidb7464d2017-07-13 03:11:17 +0000137 , m_size(tlv::sizeOfVarNumber(m_type) + tlv::sizeOfVarNumber(0))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800138{
139}
140
Junxiao Shidb7464d2017-07-13 03:11:17 +0000141Block::Block(uint32_t type, ConstBufferPtr value)
142 : m_buffer(std::move(value))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800143 , m_begin(m_buffer->end())
144 , m_end(m_buffer->end())
Junxiao Shidb7464d2017-07-13 03:11:17 +0000145 , m_valueBegin(m_buffer->begin())
146 , m_valueEnd(m_buffer->end())
147 , m_type(type)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800148{
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600149 m_size = tlv::sizeOfVarNumber(m_type) + tlv::sizeOfVarNumber(value_size()) + value_size();
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800150}
151
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700152Block::Block(uint32_t type, const Block& value)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800153 : m_buffer(value.m_buffer)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800154 , m_begin(m_buffer->end())
155 , m_end(m_buffer->end())
Junxiao Shidb7464d2017-07-13 03:11:17 +0000156 , m_valueBegin(value.begin())
157 , m_valueEnd(value.end())
158 , m_type(type)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800159{
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600160 m_size = tlv::sizeOfVarNumber(m_type) + tlv::sizeOfVarNumber(value_size()) + value_size();
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800161}
162
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700163Block
164Block::fromStream(std::istream& is)
165{
Junxiao Shif0da7892015-04-04 22:16:16 -0700166 std::istream_iterator<uint8_t> begin(is >> std::noskipws);
167 std::istream_iterator<uint8_t> end;
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700168
Junxiao Shif0da7892015-04-04 22:16:16 -0700169 uint32_t type = tlv::readType(begin, end);
170 uint64_t length = tlv::readVarNumber(begin, end);
Junxiao Shi760cc7b2017-07-22 19:17:49 +0000171 if (begin != end) {
172 is.putback(*begin);
Junxiao Shif0da7892015-04-04 22:16:16 -0700173 }
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700174
Junxiao Shi760cc7b2017-07-22 19:17:49 +0000175 size_t tlSize = tlv::sizeOfVarNumber(type) + tlv::sizeOfVarNumber(length);
176 if (tlSize + length > MAX_SIZE_OF_BLOCK_FROM_STREAM) {
177 BOOST_THROW_EXCEPTION(Error("TLV-LENGTH from stream exceeds limit"));
Junxiao Shidb7464d2017-07-13 03:11:17 +0000178 }
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700179
Junxiao Shi760cc7b2017-07-22 19:17:49 +0000180 EncodingBuffer eb(tlSize + length, length);
181 uint8_t* valueBuf = eb.buf();
182 is.read(reinterpret_cast<char*>(valueBuf), length);
183 if (length != static_cast<uint64_t>(is.gcount())) {
184 BOOST_THROW_EXCEPTION(Error("Not enough bytes from stream to fully parse TLV"));
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700185 }
186
Junxiao Shi760cc7b2017-07-22 19:17:49 +0000187 eb.prependVarNumber(length);
188 eb.prependVarNumber(type);
189
190 // TLV-VALUE is directly written into eb.buf(), eb.end() is not incremented, but eb.getBuffer()
191 // has the correct layout.
192 return Block(eb.getBuffer());
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700193}
194
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700195std::tuple<bool, Block>
196Block::fromBuffer(ConstBufferPtr buffer, size_t offset)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700197{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000198 const Buffer::const_iterator begin = buffer->begin() + offset;
199 Buffer::const_iterator pos = begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700200
Junxiao Shidb7464d2017-07-13 03:11:17 +0000201 uint32_t type = 0;
202 bool isOk = tlv::readType(pos, buffer->end(), type);
203 if (!isOk) {
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700204 return std::make_tuple(false, Block());
Junxiao Shidb7464d2017-07-13 03:11:17 +0000205 }
206 uint64_t length = 0;
207 isOk = tlv::readVarNumber(pos, buffer->end(), length);
208 if (!isOk) {
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700209 return std::make_tuple(false, Block());
Junxiao Shidb7464d2017-07-13 03:11:17 +0000210 }
211 // pos now points to TLV-VALUE
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700212
Junxiao Shidb7464d2017-07-13 03:11:17 +0000213 if (length > static_cast<uint64_t>(buffer->end() - pos)) {
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700214 return std::make_tuple(false, Block());
Junxiao Shidb7464d2017-07-13 03:11:17 +0000215 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700216
Junxiao Shidb7464d2017-07-13 03:11:17 +0000217 return std::make_tuple(true, Block(buffer, type, begin, pos + length, pos, pos + length));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700218}
219
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700220std::tuple<bool, Block>
Junxiao Shidb7464d2017-07-13 03:11:17 +0000221Block::fromBuffer(const uint8_t* buf, size_t bufSize)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700222{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000223 const uint8_t* pos = buf;
224 const uint8_t* const end = buf + bufSize;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700225
Mickey Sweatt632e0572014-04-20 00:36:32 -0700226 uint32_t type = 0;
Junxiao Shidb7464d2017-07-13 03:11:17 +0000227 bool isOk = tlv::readType(pos, end, type);
228 if (!isOk) {
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700229 return std::make_tuple(false, Block());
Junxiao Shidb7464d2017-07-13 03:11:17 +0000230 }
231 uint64_t length = 0;
232 isOk = tlv::readVarNumber(pos, end, length);
233 if (!isOk) {
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700234 return std::make_tuple(false, Block());
Junxiao Shidb7464d2017-07-13 03:11:17 +0000235 }
236 // pos now points to TLV-VALUE
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700237
Junxiao Shidb7464d2017-07-13 03:11:17 +0000238 if (length > static_cast<uint64_t>(end - pos)) {
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700239 return std::make_tuple(false, Block());
Junxiao Shidb7464d2017-07-13 03:11:17 +0000240 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700241
Junxiao Shidb7464d2017-07-13 03:11:17 +0000242 size_t typeLengthSize = pos - buf;
243 auto b = make_shared<Buffer>(buf, pos + length);
244 return std::make_tuple(true, Block(b, type, b->begin(), b->end(),
245 b->begin() + typeLengthSize, b->end()));
246}
247
248// ---- wire format ----
249
250bool
251Block::hasWire() const
252{
253 return m_buffer != nullptr && m_begin != m_end;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700254}
255
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800256void
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700257Block::reset()
258{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000259 this->resetWire();
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700260
261 m_type = std::numeric_limits<uint32_t>::max();
Junxiao Shidb7464d2017-07-13 03:11:17 +0000262 m_elements.clear();
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700263}
264
265void
266Block::resetWire()
267{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000268 m_buffer.reset(); // discard underlying buffer by resetting shared_ptr
269 m_begin = m_end = m_valueBegin = m_valueEnd = Buffer::const_iterator();
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400270}
271
272Buffer::const_iterator
273Block::begin() const
274{
275 if (!hasWire())
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700276 BOOST_THROW_EXCEPTION(Error("Underlying wire buffer is empty"));
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400277
278 return m_begin;
279}
280
281Buffer::const_iterator
282Block::end() const
283{
284 if (!hasWire())
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700285 BOOST_THROW_EXCEPTION(Error("Underlying wire buffer is empty"));
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400286
287 return m_end;
288}
289
290const uint8_t*
291Block::wire() const
292{
293 if (!hasWire())
Junxiao Shidb7464d2017-07-13 03:11:17 +0000294 BOOST_THROW_EXCEPTION(Error("Underlying wire buffer is empty"));
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400295
296 return &*m_begin;
297}
298
299size_t
300Block::size() const
301{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000302 if (empty()) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700303 BOOST_THROW_EXCEPTION(Error("Block size cannot be determined (undefined block size)"));
Junxiao Shidb7464d2017-07-13 03:11:17 +0000304 }
305
306 return m_size;
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400307}
308
Junxiao Shidb7464d2017-07-13 03:11:17 +0000309// ---- value ----
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400310
311const uint8_t*
312Block::value() const
313{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000314 return hasValue() ? &*m_valueBegin : nullptr;
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400315}
316
317size_t
318Block::value_size() const
319{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000320 return hasValue() ? m_valueEnd - m_valueBegin : 0;
321}
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400322
Junxiao Shidb7464d2017-07-13 03:11:17 +0000323Block
324Block::blockFromValue() const
325{
326 if (!hasValue())
327 BOOST_THROW_EXCEPTION(Error("Block has no TLV-VALUE"));
328
329 return Block(*this, m_valueBegin, m_valueEnd, true);
330}
331
332// ---- sub elements ----
333
334void
335Block::parse() const
336{
337 if (!m_elements.empty() || value_size() == 0)
338 return;
339
340 Buffer::const_iterator begin = value_begin();
341 Buffer::const_iterator end = value_end();
342
343 while (begin != end) {
344 Buffer::const_iterator pos = begin;
345
346 uint32_t type = tlv::readType(pos, end);
347 uint64_t length = tlv::readVarNumber(pos, end);
348 if (length > static_cast<uint64_t>(end - pos)) {
349 m_elements.clear();
350 BOOST_THROW_EXCEPTION(Error("TLV-LENGTH of sub-element of type " + to_string(type) +
351 " exceeds TLV-VALUE boundary of parent block"));
352 }
353 // pos now points to TLV-VALUE of sub element
354
355 Buffer::const_iterator subEnd = pos + length;
356 m_elements.emplace_back(m_buffer, type, begin, subEnd, pos, subEnd);
357
358 begin = subEnd;
359 }
360}
361
362void
363Block::encode()
364{
365 if (hasWire())
366 return;
367
Junxiao Shid2777fa2017-07-27 18:35:34 +0000368 EncodingEstimator estimator;
369 size_t estimatedSize = encode(estimator);
Junxiao Shidb7464d2017-07-13 03:11:17 +0000370
Junxiao Shid2777fa2017-07-27 18:35:34 +0000371 EncodingBuffer buffer(estimatedSize, 0);
372 encode(buffer);
373}
374
375size_t
376Block::encode(EncodingEstimator& estimator) const
377{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000378 if (hasValue()) {
Junxiao Shid2777fa2017-07-27 18:35:34 +0000379 return m_size;
Junxiao Shidb7464d2017-07-13 03:11:17 +0000380 }
Junxiao Shid2777fa2017-07-27 18:35:34 +0000381
382 size_t len = 0;
383 for (const Block& element : m_elements | boost::adaptors::reversed) {
384 len += element.encode(estimator);
385 }
386 len += estimator.prependVarNumber(len);
387 len += estimator.prependVarNumber(m_type);
388 return len;
389}
390
391size_t
392Block::encode(EncodingBuffer& encoder)
393{
394 size_t len = 0;
395 m_end = encoder.begin();
396 if (hasValue()) {
397 len += encoder.prependRange(m_valueBegin, m_valueEnd);
Junxiao Shidb7464d2017-07-13 03:11:17 +0000398 }
399 else {
Junxiao Shid2777fa2017-07-27 18:35:34 +0000400 for (Block& element : m_elements | boost::adaptors::reversed) {
401 len += element.encode(encoder);
Junxiao Shidb7464d2017-07-13 03:11:17 +0000402 }
403 }
Junxiao Shid2777fa2017-07-27 18:35:34 +0000404 m_valueEnd = m_end;
405 m_valueBegin = encoder.begin();
Junxiao Shidb7464d2017-07-13 03:11:17 +0000406
Junxiao Shid2777fa2017-07-27 18:35:34 +0000407 len += encoder.prependVarNumber(len);
408 len += encoder.prependVarNumber(m_type);
409 m_begin = encoder.begin();
Junxiao Shidb7464d2017-07-13 03:11:17 +0000410
Junxiao Shid2777fa2017-07-27 18:35:34 +0000411 m_buffer = encoder.getBuffer();
412 m_size = len;
413 return len;
Junxiao Shidb7464d2017-07-13 03:11:17 +0000414}
415
416const Block&
417Block::get(uint32_t type) const
418{
419 auto it = this->find(type);
420 if (it != m_elements.end()) {
421 return *it;
422 }
423
424 BOOST_THROW_EXCEPTION(Error("No sub-element of type " + to_string(type) +
425 " is found in block of type " + to_string(m_type)));
426}
427
428Block::element_const_iterator
429Block::find(uint32_t type) const
430{
431 return std::find_if(m_elements.begin(), m_elements.end(),
432 [type] (const Block& subBlock) { return subBlock.type() == type; });
433}
434
435void
436Block::remove(uint32_t type)
437{
438 resetWire();
439
440 auto it = std::remove_if(m_elements.begin(), m_elements.end(),
441 [type] (const Block& subBlock) { return subBlock.type() == type; });
442 m_elements.resize(it - m_elements.begin());
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400443}
444
445Block::element_iterator
Joao Pereira7476ebf2015-07-07 14:54:39 -0400446Block::erase(Block::element_const_iterator position)
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400447{
448 resetWire();
Joao Pereira7476ebf2015-07-07 14:54:39 -0400449
450#ifdef NDN_CXX_HAVE_VECTOR_INSERT_ERASE_CONST_ITERATOR
Junxiao Shidb7464d2017-07-13 03:11:17 +0000451 return m_elements.erase(position);
Joao Pereira7476ebf2015-07-07 14:54:39 -0400452#else
Junxiao Shidb7464d2017-07-13 03:11:17 +0000453 element_iterator it = m_elements.begin();
454 std::advance(it, std::distance(m_elements.cbegin(), position));
455 return m_elements.erase(it);
Joao Pereira7476ebf2015-07-07 14:54:39 -0400456#endif
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400457}
458
459Block::element_iterator
Joao Pereira7476ebf2015-07-07 14:54:39 -0400460Block::erase(Block::element_const_iterator first, Block::element_const_iterator last)
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400461{
462 resetWire();
Joao Pereira7476ebf2015-07-07 14:54:39 -0400463
464#ifdef NDN_CXX_HAVE_VECTOR_INSERT_ERASE_CONST_ITERATOR
Junxiao Shidb7464d2017-07-13 03:11:17 +0000465 return m_elements.erase(first, last);
Joao Pereira7476ebf2015-07-07 14:54:39 -0400466#else
Junxiao Shidb7464d2017-07-13 03:11:17 +0000467 element_iterator itStart = m_elements.begin();
468 element_iterator itEnd = m_elements.begin();
469 std::advance(itStart, std::distance(m_elements.cbegin(), first));
470 std::advance(itEnd, std::distance(m_elements.cbegin(), last));
471 return m_elements.erase(itStart, itEnd);
Joao Pereira7476ebf2015-07-07 14:54:39 -0400472#endif
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400473}
474
475void
476Block::push_back(const Block& element)
477{
478 resetWire();
Junxiao Shidb7464d2017-07-13 03:11:17 +0000479 m_elements.push_back(element);
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400480}
481
Joao Pereira7476ebf2015-07-07 14:54:39 -0400482Block::element_iterator
483Block::insert(Block::element_const_iterator pos, const Block& element)
484{
485 resetWire();
486
487#ifdef NDN_CXX_HAVE_VECTOR_INSERT_ERASE_CONST_ITERATOR
Junxiao Shidb7464d2017-07-13 03:11:17 +0000488 return m_elements.insert(pos, element);
Joao Pereira7476ebf2015-07-07 14:54:39 -0400489#else
Junxiao Shidb7464d2017-07-13 03:11:17 +0000490 element_iterator it = m_elements.begin();
491 std::advance(it, std::distance(m_elements.cbegin(), pos));
492 return m_elements.insert(it, element);
Joao Pereira7476ebf2015-07-07 14:54:39 -0400493#endif
494}
495
Junxiao Shidb7464d2017-07-13 03:11:17 +0000496// ---- misc ----
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400497
Junxiao Shidb7464d2017-07-13 03:11:17 +0000498Block::operator boost::asio::const_buffer() const
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400499{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000500 return boost::asio::const_buffer(wire(), size());
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400501}
502
503bool
Junxiao Shidb7464d2017-07-13 03:11:17 +0000504operator==(const Block& lhs, const Block& rhs)
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400505{
Junxiao Shidb7464d2017-07-13 03:11:17 +0000506 return lhs.type() == rhs.type() &&
507 lhs.value_size() == rhs.value_size() &&
Davide Pesaventoe245b052017-10-31 13:00:44 -0400508 (lhs.value_size() == 0 ||
509 std::memcmp(lhs.value(), rhs.value(), lhs.value_size()) == 0);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700510}
511
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800512} // namespace ndn