blob: 3e2d51865ecbe0c7a1028ef4954f2bae479f3002 [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07002/**
Alexander Afanasyevaf99f462015-01-19 21:43:09 -08003 * Copyright (c) 2013-2015 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 "block-helpers.hpp"
26
Alexander Afanasyeve2dcdfd2014-02-07 15:53:28 -080027#include "tlv.hpp"
Alexander Afanasyev15151312014-02-16 00:53:51 -080028#include "encoding-buffer.hpp"
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070029#include "buffer-stream.hpp"
30
31#include <boost/lexical_cast.hpp>
Alexander Afanasyev6a05b4b2014-07-18 17:23:00 -070032#include <boost/asio/buffer.hpp>
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080033
34namespace ndn {
35
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
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080048Block::Block()
49 : m_type(std::numeric_limits<uint32_t>::max())
50{
51}
52
Alexander Afanasyev15151312014-02-16 00:53:51 -080053Block::Block(const EncodingBuffer& buffer)
Alexander Afanasyev74633892015-02-08 18:08:46 -080054 : m_buffer(const_cast<EncodingBuffer&>(buffer).getBuffer())
Alexander Afanasyev15151312014-02-16 00:53:51 -080055 , m_begin(buffer.begin())
56 , m_end(buffer.end())
57 , m_size(m_end - m_begin)
58{
59 m_value_begin = m_begin;
60 m_value_end = m_end;
61
Steve DiBenedetto54ce6682014-07-22 13:22:57 -060062 m_type = tlv::readType(m_value_begin, m_value_end);
63 uint64_t length = tlv::readVarNumber(m_value_begin, m_value_end);
Alexander Afanasyev15151312014-02-16 00:53:51 -080064 if (length != static_cast<uint64_t>(m_value_end - m_value_begin))
65 {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -070066 BOOST_THROW_EXCEPTION(tlv::Error("TLV length doesn't match buffer length"));
Alexander Afanasyev15151312014-02-16 00:53:51 -080067 }
68}
69
Alexander Afanasyeva465e972014-03-22 17:21:49 -070070Block::Block(const ConstBufferPtr& wire,
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080071 uint32_t type,
Alexander Afanasyeva465e972014-03-22 17:21:49 -070072 const Buffer::const_iterator& begin, const Buffer::const_iterator& end,
73 const Buffer::const_iterator& valueBegin, const Buffer::const_iterator& valueEnd)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080074 : m_buffer(wire)
75 , m_type(type)
76 , m_begin(begin)
77 , m_end(end)
78 , m_size(m_end - m_begin)
79 , m_value_begin(valueBegin)
80 , m_value_end(valueEnd)
81{
82}
83
Alexander Afanasyeva465e972014-03-22 17:21:49 -070084Block::Block(const ConstBufferPtr& buffer)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080085 : m_buffer(buffer)
86 , m_begin(m_buffer->begin())
87 , m_end(m_buffer->end())
88 , m_size(m_end - m_begin)
89{
Alexander Afanasyev233750e2014-02-16 00:50:07 -080090 m_value_begin = m_begin;
91 m_value_end = m_end;
Alexander Afanasyev937aa782014-03-21 13:17:57 -070092
Steve DiBenedetto54ce6682014-07-22 13:22:57 -060093 m_type = tlv::readType(m_value_begin, m_value_end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080094
Steve DiBenedetto54ce6682014-07-22 13:22:57 -060095 uint64_t length = tlv::readVarNumber(m_value_begin, m_value_end);
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -080096 if (length != static_cast<uint64_t>(m_value_end - m_value_begin))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080097 {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -070098 BOOST_THROW_EXCEPTION(tlv::Error("TLV length doesn't match buffer length"));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080099 }
100}
101
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700102Block::Block(const ConstBufferPtr& buffer,
103 const Buffer::const_iterator& begin, const Buffer::const_iterator& end,
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800104 bool verifyLength/* = true*/)
Alexander Afanasyev187bc482014-02-06 15:04:04 -0800105 : m_buffer(buffer)
106 , m_begin(begin)
107 , m_end(end)
Alexander Afanasyev380420b2014-02-09 20:52:29 -0800108 , m_size(m_end - m_begin)
Alexander Afanasyev187bc482014-02-06 15:04:04 -0800109{
Alexander Afanasyev233750e2014-02-16 00:50:07 -0800110 m_value_begin = m_begin;
111 m_value_end = m_end;
Alexander Afanasyev380420b2014-02-09 20:52:29 -0800112
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600113 m_type = tlv::readType(m_value_begin, m_value_end);
114 uint64_t length = tlv::readVarNumber(m_value_begin, m_value_end);
Alexander Afanasyev4448d292015-08-09 20:11:37 -0700115 if (verifyLength) {
116 if (length != static_cast<uint64_t>(std::distance(m_value_begin, m_value_end))) {
117 BOOST_THROW_EXCEPTION(tlv::Error("TLV length doesn't match buffer length"));
Alexander Afanasyev187bc482014-02-06 15:04:04 -0800118 }
Alexander Afanasyev4448d292015-08-09 20:11:37 -0700119 }
120}
121
122Block::Block(const Block& block,
123 const Buffer::const_iterator& begin, const Buffer::const_iterator& end,
124 bool verifyLength/* = true*/)
125 : m_buffer(block.m_buffer)
126 , m_begin(begin)
127 , m_end(end)
128 , m_size(m_end - m_begin)
129{
130 if (!(m_buffer->begin() <= begin && begin <= m_buffer->end()) ||
131 !(m_buffer->begin() <= end && end <= m_buffer->end())) {
132 BOOST_THROW_EXCEPTION(Error("begin/end iterators do not point to the underlying buffer of the block"));
133 }
134
135 m_value_begin = m_begin;
136 m_value_end = m_end;
137
138 m_type = tlv::readType(m_value_begin, m_value_end);
139 uint64_t length = tlv::readVarNumber(m_value_begin, m_value_end);
140 if (verifyLength) {
141 if (length != static_cast<uint64_t>(std::distance(m_value_begin, m_value_end))) {
142 BOOST_THROW_EXCEPTION(tlv::Error("TLV length doesn't match buffer length"));
143 }
144 }
Alexander Afanasyev187bc482014-02-06 15:04:04 -0800145}
146
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700147Block::Block(const uint8_t* buffer, size_t maxlength)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800148{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700149 const uint8_t* tmp_begin = buffer;
150 const uint8_t* tmp_end = buffer + maxlength;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700151
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600152 m_type = tlv::readType(tmp_begin, tmp_end);
153 uint64_t length = tlv::readVarNumber(tmp_begin, tmp_end);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700154
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -0800155 if (length > static_cast<uint64_t>(tmp_end - tmp_begin))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800156 {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700157 BOOST_THROW_EXCEPTION(tlv::Error("Not enough data in the buffer to fully parse TLV"));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800158 }
159
Alexander Afanasyevf73f0632014-05-12 18:02:37 -0700160 m_buffer = make_shared<Buffer>(buffer, (tmp_begin - buffer) + length);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800161
162 m_begin = m_buffer->begin();
163 m_end = m_buffer->end();
164 m_size = m_end - m_begin;
165
166 m_value_begin = m_buffer->begin() + (tmp_begin - buffer);
167 m_value_end = m_buffer->end();
168}
169
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700170Block::Block(const void* bufferX, size_t maxlength)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800171{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700172 const uint8_t* buffer = reinterpret_cast<const uint8_t*>(bufferX);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700173
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700174 const uint8_t* tmp_begin = buffer;
175 const uint8_t* tmp_end = buffer + maxlength;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700176
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600177 m_type = tlv::readType(tmp_begin, tmp_end);
178 uint64_t length = tlv::readVarNumber(tmp_begin, tmp_end);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700179
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -0800180 if (length > static_cast<uint64_t>(tmp_end - tmp_begin))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800181 {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700182 BOOST_THROW_EXCEPTION(tlv::Error("Not enough data in the buffer to fully parse TLV"));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800183 }
184
Alexander Afanasyevf73f0632014-05-12 18:02:37 -0700185 m_buffer = make_shared<Buffer>(buffer, (tmp_begin - buffer) + length);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800186
187 m_begin = m_buffer->begin();
188 m_end = m_buffer->end();
189 m_size = m_end - m_begin;
190
191 m_value_begin = m_buffer->begin() + (tmp_begin - buffer);
192 m_value_end = m_buffer->end();
193}
194
195Block::Block(uint32_t type)
196 : m_type(type)
197{
198}
199
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700200Block::Block(uint32_t type, const ConstBufferPtr& value)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800201 : m_buffer(value)
202 , m_type(type)
203 , m_begin(m_buffer->end())
204 , m_end(m_buffer->end())
205 , m_value_begin(m_buffer->begin())
206 , m_value_end(m_buffer->end())
207{
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600208 m_size = tlv::sizeOfVarNumber(m_type) + tlv::sizeOfVarNumber(value_size()) + value_size();
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800209}
210
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700211Block::Block(uint32_t type, const Block& value)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800212 : m_buffer(value.m_buffer)
213 , m_type(type)
214 , m_begin(m_buffer->end())
215 , m_end(m_buffer->end())
Alexander Afanasyevc8823bc2014-02-09 19:33:33 -0800216 , m_value_begin(value.begin())
217 , m_value_end(value.end())
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800218{
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600219 m_size = tlv::sizeOfVarNumber(m_type) + tlv::sizeOfVarNumber(value_size()) + value_size();
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800220}
221
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700222Block
223Block::fromStream(std::istream& is)
224{
Junxiao Shif0da7892015-04-04 22:16:16 -0700225 std::istream_iterator<uint8_t> begin(is >> std::noskipws);
226 std::istream_iterator<uint8_t> end;
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700227
Junxiao Shif0da7892015-04-04 22:16:16 -0700228 uint32_t type = tlv::readType(begin, end);
229 uint64_t length = tlv::readVarNumber(begin, end);
230
231 if (length == 0) {
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700232 return makeEmptyBlock(type);
Junxiao Shif0da7892015-04-04 22:16:16 -0700233 }
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700234
235 if (length > MAX_SIZE_OF_BLOCK_FROM_STREAM)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700236 BOOST_THROW_EXCEPTION(tlv::Error("Length of block from stream is too large"));
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700237
238 // We may still have some problem here, if some exception happens,
239 // we may completely lose all the bytes extracted from the stream.
240
241 char buf[MAX_SIZE_OF_BLOCK_FROM_STREAM];
Junxiao Shif0da7892015-04-04 22:16:16 -0700242 buf[0] = *begin;
243 is.read(buf + 1, length - 1);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700244
245 if (length != static_cast<uint64_t>(is.gcount()) + 1) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700246 BOOST_THROW_EXCEPTION(tlv::Error("Not enough data in the buffer to fully parse TLV"));
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700247 }
248
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700249 return makeBinaryBlock(type, buf, length);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700250}
251
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700252std::tuple<bool, Block>
253Block::fromBuffer(ConstBufferPtr buffer, size_t offset)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700254{
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700255 Buffer::const_iterator tempBegin = buffer->begin() + offset;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700256
257 uint32_t type;
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700258 bool isOk = tlv::readType(tempBegin, buffer->end(), type);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700259 if (!isOk)
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700260 return std::make_tuple(false, Block());
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700261
262 uint64_t length;
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700263 isOk = tlv::readVarNumber(tempBegin, buffer->end(), length);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700264 if (!isOk)
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700265 return std::make_tuple(false, Block());
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700266
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700267 if (length > static_cast<uint64_t>(buffer->end() - tempBegin))
268 return std::make_tuple(false, Block());
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700269
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700270 return std::make_tuple(true, Block(buffer, type,
271 buffer->begin() + offset, tempBegin + length,
272 tempBegin, tempBegin + length));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700273}
274
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700275std::tuple<bool, Block>
276Block::fromBuffer(const uint8_t* buffer, size_t maxSize)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700277{
278 const uint8_t* tempBegin = buffer;
279 const uint8_t* tempEnd = buffer + maxSize;
280
Mickey Sweatt632e0572014-04-20 00:36:32 -0700281 uint32_t type = 0;
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600282 bool isOk = tlv::readType(tempBegin, tempEnd, type);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700283 if (!isOk)
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700284 return std::make_tuple(false, Block());
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700285
286 uint64_t length;
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600287 isOk = tlv::readVarNumber(tempBegin, tempEnd, length);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700288 if (!isOk)
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700289 return std::make_tuple(false, Block());
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700290
291 if (length > static_cast<uint64_t>(tempEnd - tempBegin))
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700292 return std::make_tuple(false, Block());
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700293
294 BufferPtr sharedBuffer = make_shared<Buffer>(buffer, tempBegin + length);
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700295 return std::make_tuple(true,
296 Block(sharedBuffer, type,
297 sharedBuffer->begin(), sharedBuffer->end(),
298 sharedBuffer->begin() + (tempBegin - buffer), sharedBuffer->end()));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700299}
300
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800301void
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700302Block::reset()
303{
304 m_buffer.reset(); // reset of the shared_ptr
305 m_subBlocks.clear(); // remove all parsed subelements
306
307 m_type = std::numeric_limits<uint32_t>::max();
308 m_begin = m_end = m_value_begin = m_value_end = Buffer::const_iterator();
309}
310
311void
312Block::resetWire()
313{
314 m_buffer.reset(); // reset of the shared_ptr
315 // keep subblocks
316
317 // keep type
318 m_begin = m_end = m_value_begin = m_value_end = Buffer::const_iterator();
319}
320
321void
Alexander Afanasyev29e5c3d2014-02-11 00:01:10 -0800322Block::parse() const
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800323{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700324 if (!m_subBlocks.empty() || value_size() == 0)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800325 return;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700326
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700327 Buffer::const_iterator begin = value_begin();
328 Buffer::const_iterator end = value_end();
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800329
330 while (begin != end)
331 {
332 Buffer::const_iterator element_begin = begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700333
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600334 uint32_t type = tlv::readType(begin, end);
335 uint64_t length = tlv::readVarNumber(begin, end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800336
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -0800337 if (length > static_cast<uint64_t>(end - begin))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800338 {
339 m_subBlocks.clear();
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700340 BOOST_THROW_EXCEPTION(tlv::Error("TLV length exceeds buffer length"));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800341 }
342 Buffer::const_iterator element_end = begin + length;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700343
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800344 m_subBlocks.push_back(Block(m_buffer,
345 type,
346 element_begin, element_end,
347 begin, element_end));
348
349 begin = element_end;
350 // don't do recursive parsing, just the top level
351 }
352}
353
354void
355Block::encode()
356{
357 if (hasWire())
358 return;
359
360 OBufferStream os;
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600361 tlv::writeVarNumber(os, type());
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800362
363 if (hasValue())
364 {
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600365 tlv::writeVarNumber(os, value_size());
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800366 os.write(reinterpret_cast<const char*>(value()), value_size());
367 }
Alexander Afanasyev8ea763d2014-02-06 20:32:52 -0800368 else if (m_subBlocks.size() == 0)
369 {
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600370 tlv::writeVarNumber(os, 0);
Alexander Afanasyev8ea763d2014-02-06 20:32:52 -0800371 }
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800372 else
373 {
374 size_t valueSize = 0;
375 for (element_const_iterator i = m_subBlocks.begin(); i != m_subBlocks.end(); ++i) {
376 valueSize += i->size();
377 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700378
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600379 tlv::writeVarNumber(os, valueSize);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800380
381 for (element_const_iterator i = m_subBlocks.begin(); i != m_subBlocks.end(); ++i) {
382 if (i->hasWire())
383 os.write(reinterpret_cast<const char*>(i->wire()), i->size());
384 else if (i->hasValue()) {
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600385 tlv::writeVarNumber(os, i->type());
386 tlv::writeVarNumber(os, i->value_size());
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800387 os.write(reinterpret_cast<const char*>(i->value()), i->value_size());
388 }
389 else
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700390 BOOST_THROW_EXCEPTION(Error("Underlying value buffer is empty"));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800391 }
392 }
393
394 // now assign correct block
395
396 m_buffer = os.buf();
397 m_begin = m_buffer->begin();
398 m_end = m_buffer->end();
399 m_size = m_end - m_begin;
400
401 m_value_begin = m_buffer->begin();
402 m_value_end = m_buffer->end();
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700403
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600404 tlv::readType(m_value_begin, m_value_end);
405 tlv::readVarNumber(m_value_begin, m_value_end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800406}
407
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700408const Block&
409Block::get(uint32_t type) const
410{
411 element_const_iterator it = this->find(type);
412 if (it != m_subBlocks.end())
413 return *it;
414
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700415 BOOST_THROW_EXCEPTION(Error("(Block::get) Requested a non-existed type [" +
416 boost::lexical_cast<std::string>(type) + "] from Block"));
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700417}
418
419Block::element_const_iterator
420Block::find(uint32_t type) const
421{
422 return std::find_if(m_subBlocks.begin(), m_subBlocks.end(),
423 [type] (const Block& subBlock) { return subBlock.type() == type; });
424}
425
426void
427Block::remove(uint32_t type)
428{
429 resetWire();
430
431 auto it = std::remove_if(m_subBlocks.begin(), m_subBlocks.end(),
Eric Newberrya3d9fc02015-07-26 10:55:44 -0700432 [type] (const Block& subBlock) { return subBlock.type() == type; });
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700433 m_subBlocks.resize(it - m_subBlocks.begin());
434}
435
Yingdi Yu4270f202014-01-28 14:19:16 -0800436Block
437Block::blockFromValue() const
438{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700439 if (value_size() == 0)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700440 BOOST_THROW_EXCEPTION(Error("Underlying value buffer is empty"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700441
Yingdi Yu4270f202014-01-28 14:19:16 -0800442 Buffer::const_iterator begin = value_begin(),
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700443 end = value_end();
Yingdi Yu4270f202014-01-28 14:19:16 -0800444
445 Buffer::const_iterator element_begin = begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700446
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600447 uint32_t type = tlv::readType(begin, end);
448 uint64_t length = tlv::readVarNumber(begin, end);
Yingdi Yu4270f202014-01-28 14:19:16 -0800449
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -0800450 if (length != static_cast<uint64_t>(end - begin))
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700451 BOOST_THROW_EXCEPTION(tlv::Error("TLV length mismatches buffer length"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700452
Yingdi Yu4270f202014-01-28 14:19:16 -0800453 return Block(m_buffer,
454 type,
455 element_begin, end,
456 begin, end);
457}
458
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400459Block::operator boost::asio::const_buffer() const
460{
461 return boost::asio::const_buffer(wire(), size());
462}
463
464bool
465Block::empty() const
466{
467 return m_type == std::numeric_limits<uint32_t>::max();
468}
469
470bool
471Block::hasWire() const
472{
473 return m_buffer && (m_begin != m_end);
474}
475
476Buffer::const_iterator
477Block::begin() const
478{
479 if (!hasWire())
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700480 BOOST_THROW_EXCEPTION(Error("Underlying wire buffer is empty"));
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400481
482 return m_begin;
483}
484
485Buffer::const_iterator
486Block::end() const
487{
488 if (!hasWire())
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700489 BOOST_THROW_EXCEPTION(Error("Underlying wire buffer is empty"));
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400490
491 return m_end;
492}
493
494const uint8_t*
495Block::wire() const
496{
497 if (!hasWire())
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700498 BOOST_THROW_EXCEPTION(Error("(Block::wire) Underlying wire buffer is empty"));
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400499
500 return &*m_begin;
501}
502
503size_t
504Block::size() const
505{
506 if (hasWire() || hasValue()) {
507 return m_size;
508 }
509 else
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700510 BOOST_THROW_EXCEPTION(Error("Block size cannot be determined (undefined block size)"));
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400511}
512
513bool
514Block::hasValue() const
515{
516 return static_cast<bool>(m_buffer);
517}
518
519const uint8_t*
520Block::value() const
521{
522 if (!hasValue())
523 return 0;
524
525 return &*m_value_begin;
526}
527
528size_t
529Block::value_size() const
530{
531 if (!hasValue())
532 return 0;
533
534 return m_value_end - m_value_begin;
535}
536
537Block::element_iterator
Joao Pereira7476ebf2015-07-07 14:54:39 -0400538Block::erase(Block::element_const_iterator position)
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400539{
540 resetWire();
Joao Pereira7476ebf2015-07-07 14:54:39 -0400541
542#ifdef NDN_CXX_HAVE_VECTOR_INSERT_ERASE_CONST_ITERATOR
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400543 return m_subBlocks.erase(position);
Joao Pereira7476ebf2015-07-07 14:54:39 -0400544#else
545 element_iterator it = m_subBlocks.begin();
546 std::advance(it, std::distance(m_subBlocks.cbegin(), position));
547 return m_subBlocks.erase(it);
548#endif
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400549}
550
551Block::element_iterator
Joao Pereira7476ebf2015-07-07 14:54:39 -0400552Block::erase(Block::element_const_iterator first, Block::element_const_iterator last)
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400553{
554 resetWire();
Joao Pereira7476ebf2015-07-07 14:54:39 -0400555
556#ifdef NDN_CXX_HAVE_VECTOR_INSERT_ERASE_CONST_ITERATOR
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400557 return m_subBlocks.erase(first, last);
Joao Pereira7476ebf2015-07-07 14:54:39 -0400558#else
559 element_iterator itStart = m_subBlocks.begin();
560 element_iterator itEnd = m_subBlocks.begin();
561 std::advance(itStart, std::distance(m_subBlocks.cbegin(), first));
562 std::advance(itEnd, std::distance(m_subBlocks.cbegin(), last));
563 return m_subBlocks.erase(itStart, itEnd);
564#endif
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400565}
566
567void
568Block::push_back(const Block& element)
569{
570 resetWire();
571 m_subBlocks.push_back(element);
572}
573
Joao Pereira7476ebf2015-07-07 14:54:39 -0400574Block::element_iterator
575Block::insert(Block::element_const_iterator pos, const Block& element)
576{
577 resetWire();
578
579#ifdef NDN_CXX_HAVE_VECTOR_INSERT_ERASE_CONST_ITERATOR
580 return m_subBlocks.insert(pos, element);
581#else
582 element_iterator it = m_subBlocks.begin();
583 std::advance(it, std::distance(m_subBlocks.cbegin(), pos));
584 return m_subBlocks.insert(it, element);
585#endif
586}
587
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400588Block::element_const_iterator
589Block::elements_begin() const
590{
591 return m_subBlocks.begin();
592}
593
594Block::element_const_iterator
595Block::elements_end() const
596{
597 return m_subBlocks.end();
598}
599
600size_t
601Block::elements_size() const
602{
603 return m_subBlocks.size();
604}
605
606bool
607Block::operator!=(const Block& other) const
608{
609 return !this->operator==(other);
610}
611
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700612bool
613Block::operator==(const Block& other) const
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700614{
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700615 return this->size() == other.size() &&
616 std::equal(this->begin(), this->end(), other.begin());
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700617}
618
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800619} // namespace ndn