blob: 77be4f2ba5d50735f637afb8bc3ddf6782d1e9e0 [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
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070046const size_t MAX_SIZE_OF_BLOCK_FROM_STREAM = 8800;
47
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 {
Steve DiBenedetto54ce6682014-07-22 13:22:57 -060066 throw 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 {
Steve DiBenedetto54ce6682014-07-22 13:22:57 -060098 throw 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 Afanasyev5964fb72014-02-18 12:42:45 -0800115 if (verifyLength)
Alexander Afanasyev187bc482014-02-06 15:04:04 -0800116 {
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800117 if (length != static_cast<uint64_t>(m_value_end - m_value_begin))
118 {
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600119 throw tlv::Error("TLV length doesn't match buffer length");
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800120 }
Alexander Afanasyev187bc482014-02-06 15:04:04 -0800121 }
122}
123
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700124Block::Block(const uint8_t* buffer, size_t maxlength)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800125{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700126 const uint8_t* tmp_begin = buffer;
127 const uint8_t* tmp_end = buffer + maxlength;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700128
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600129 m_type = tlv::readType(tmp_begin, tmp_end);
130 uint64_t length = tlv::readVarNumber(tmp_begin, tmp_end);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700131
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -0800132 if (length > static_cast<uint64_t>(tmp_end - tmp_begin))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800133 {
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600134 throw tlv::Error("Not enough data in the buffer to fully parse TLV");
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800135 }
136
Alexander Afanasyevf73f0632014-05-12 18:02:37 -0700137 m_buffer = make_shared<Buffer>(buffer, (tmp_begin - buffer) + length);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800138
139 m_begin = m_buffer->begin();
140 m_end = m_buffer->end();
141 m_size = m_end - m_begin;
142
143 m_value_begin = m_buffer->begin() + (tmp_begin - buffer);
144 m_value_end = m_buffer->end();
145}
146
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700147Block::Block(const void* bufferX, size_t maxlength)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800148{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700149 const uint8_t* buffer = reinterpret_cast<const uint8_t*>(bufferX);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700150
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700151 const uint8_t* tmp_begin = buffer;
152 const uint8_t* tmp_end = buffer + maxlength;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700153
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600154 m_type = tlv::readType(tmp_begin, tmp_end);
155 uint64_t length = tlv::readVarNumber(tmp_begin, tmp_end);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700156
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -0800157 if (length > static_cast<uint64_t>(tmp_end - tmp_begin))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800158 {
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600159 throw tlv::Error("Not enough data in the buffer to fully parse TLV");
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800160 }
161
Alexander Afanasyevf73f0632014-05-12 18:02:37 -0700162 m_buffer = make_shared<Buffer>(buffer, (tmp_begin - buffer) + length);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800163
164 m_begin = m_buffer->begin();
165 m_end = m_buffer->end();
166 m_size = m_end - m_begin;
167
168 m_value_begin = m_buffer->begin() + (tmp_begin - buffer);
169 m_value_end = m_buffer->end();
170}
171
172Block::Block(uint32_t type)
173 : m_type(type)
174{
175}
176
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700177Block::Block(uint32_t type, const ConstBufferPtr& value)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800178 : m_buffer(value)
179 , m_type(type)
180 , m_begin(m_buffer->end())
181 , m_end(m_buffer->end())
182 , m_value_begin(m_buffer->begin())
183 , m_value_end(m_buffer->end())
184{
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600185 m_size = tlv::sizeOfVarNumber(m_type) + tlv::sizeOfVarNumber(value_size()) + value_size();
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800186}
187
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700188Block::Block(uint32_t type, const Block& value)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800189 : m_buffer(value.m_buffer)
190 , m_type(type)
191 , m_begin(m_buffer->end())
192 , m_end(m_buffer->end())
Alexander Afanasyevc8823bc2014-02-09 19:33:33 -0800193 , m_value_begin(value.begin())
194 , m_value_end(value.end())
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800195{
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600196 m_size = tlv::sizeOfVarNumber(m_type) + tlv::sizeOfVarNumber(value_size()) + value_size();
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800197}
198
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700199Block
200Block::fromStream(std::istream& is)
201{
Junxiao Shif0da7892015-04-04 22:16:16 -0700202 std::istream_iterator<uint8_t> begin(is >> std::noskipws);
203 std::istream_iterator<uint8_t> end;
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700204
Junxiao Shif0da7892015-04-04 22:16:16 -0700205 uint32_t type = tlv::readType(begin, end);
206 uint64_t length = tlv::readVarNumber(begin, end);
207
208 if (length == 0) {
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700209 return makeEmptyBlock(type);
Junxiao Shif0da7892015-04-04 22:16:16 -0700210 }
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700211
212 if (length > MAX_SIZE_OF_BLOCK_FROM_STREAM)
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600213 throw tlv::Error("Length of block from stream is too large");
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700214
215 // We may still have some problem here, if some exception happens,
216 // we may completely lose all the bytes extracted from the stream.
217
218 char buf[MAX_SIZE_OF_BLOCK_FROM_STREAM];
Junxiao Shif0da7892015-04-04 22:16:16 -0700219 buf[0] = *begin;
220 is.read(buf + 1, length - 1);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700221
222 if (length != static_cast<uint64_t>(is.gcount()) + 1) {
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600223 throw tlv::Error("Not enough data in the buffer to fully parse TLV");
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700224 }
225
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700226 return makeBinaryBlock(type, buf, length);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700227}
228
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700229std::tuple<bool, Block>
230Block::fromBuffer(ConstBufferPtr buffer, size_t offset)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700231{
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700232 Buffer::const_iterator tempBegin = buffer->begin() + offset;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700233
234 uint32_t type;
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700235 bool isOk = tlv::readType(tempBegin, buffer->end(), type);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700236 if (!isOk)
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700237 return std::make_tuple(false, Block());
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700238
239 uint64_t length;
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700240 isOk = tlv::readVarNumber(tempBegin, buffer->end(), length);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700241 if (!isOk)
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700242 return std::make_tuple(false, Block());
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700243
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700244 if (length > static_cast<uint64_t>(buffer->end() - tempBegin))
245 return std::make_tuple(false, Block());
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700246
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700247 return std::make_tuple(true, Block(buffer, type,
248 buffer->begin() + offset, tempBegin + length,
249 tempBegin, tempBegin + length));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700250}
251
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700252std::tuple<bool, Block>
253Block::fromBuffer(const uint8_t* buffer, size_t maxSize)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700254{
255 const uint8_t* tempBegin = buffer;
256 const uint8_t* tempEnd = buffer + maxSize;
257
Mickey Sweatt632e0572014-04-20 00:36:32 -0700258 uint32_t type = 0;
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600259 bool isOk = tlv::readType(tempBegin, tempEnd, type);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700260 if (!isOk)
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700261 return std::make_tuple(false, Block());
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700262
263 uint64_t length;
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600264 isOk = tlv::readVarNumber(tempBegin, tempEnd, length);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700265 if (!isOk)
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700266 return std::make_tuple(false, Block());
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700267
268 if (length > static_cast<uint64_t>(tempEnd - tempBegin))
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700269 return std::make_tuple(false, Block());
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700270
271 BufferPtr sharedBuffer = make_shared<Buffer>(buffer, tempBegin + length);
Junxiao Shi02a4bf32015-02-21 21:07:46 -0700272 return std::make_tuple(true,
273 Block(sharedBuffer, type,
274 sharedBuffer->begin(), sharedBuffer->end(),
275 sharedBuffer->begin() + (tempBegin - buffer), sharedBuffer->end()));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700276}
277
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800278void
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700279Block::reset()
280{
281 m_buffer.reset(); // reset of the shared_ptr
282 m_subBlocks.clear(); // remove all parsed subelements
283
284 m_type = std::numeric_limits<uint32_t>::max();
285 m_begin = m_end = m_value_begin = m_value_end = Buffer::const_iterator();
286}
287
288void
289Block::resetWire()
290{
291 m_buffer.reset(); // reset of the shared_ptr
292 // keep subblocks
293
294 // keep type
295 m_begin = m_end = m_value_begin = m_value_end = Buffer::const_iterator();
296}
297
298void
Alexander Afanasyev29e5c3d2014-02-11 00:01:10 -0800299Block::parse() const
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800300{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700301 if (!m_subBlocks.empty() || value_size() == 0)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800302 return;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700303
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700304 Buffer::const_iterator begin = value_begin();
305 Buffer::const_iterator end = value_end();
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800306
307 while (begin != end)
308 {
309 Buffer::const_iterator element_begin = begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700310
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600311 uint32_t type = tlv::readType(begin, end);
312 uint64_t length = tlv::readVarNumber(begin, end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800313
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -0800314 if (length > static_cast<uint64_t>(end - begin))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800315 {
316 m_subBlocks.clear();
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600317 throw tlv::Error("TLV length exceeds buffer length");
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800318 }
319 Buffer::const_iterator element_end = begin + length;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700320
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800321 m_subBlocks.push_back(Block(m_buffer,
322 type,
323 element_begin, element_end,
324 begin, element_end));
325
326 begin = element_end;
327 // don't do recursive parsing, just the top level
328 }
329}
330
331void
332Block::encode()
333{
334 if (hasWire())
335 return;
336
337 OBufferStream os;
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600338 tlv::writeVarNumber(os, type());
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800339
340 if (hasValue())
341 {
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600342 tlv::writeVarNumber(os, value_size());
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800343 os.write(reinterpret_cast<const char*>(value()), value_size());
344 }
Alexander Afanasyev8ea763d2014-02-06 20:32:52 -0800345 else if (m_subBlocks.size() == 0)
346 {
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600347 tlv::writeVarNumber(os, 0);
Alexander Afanasyev8ea763d2014-02-06 20:32:52 -0800348 }
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800349 else
350 {
351 size_t valueSize = 0;
352 for (element_const_iterator i = m_subBlocks.begin(); i != m_subBlocks.end(); ++i) {
353 valueSize += i->size();
354 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700355
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600356 tlv::writeVarNumber(os, valueSize);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800357
358 for (element_const_iterator i = m_subBlocks.begin(); i != m_subBlocks.end(); ++i) {
359 if (i->hasWire())
360 os.write(reinterpret_cast<const char*>(i->wire()), i->size());
361 else if (i->hasValue()) {
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600362 tlv::writeVarNumber(os, i->type());
363 tlv::writeVarNumber(os, i->value_size());
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800364 os.write(reinterpret_cast<const char*>(i->value()), i->value_size());
365 }
366 else
367 throw Error("Underlying value buffer is empty");
368 }
369 }
370
371 // now assign correct block
372
373 m_buffer = os.buf();
374 m_begin = m_buffer->begin();
375 m_end = m_buffer->end();
376 m_size = m_end - m_begin;
377
378 m_value_begin = m_buffer->begin();
379 m_value_end = m_buffer->end();
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700380
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600381 tlv::readType(m_value_begin, m_value_end);
382 tlv::readVarNumber(m_value_begin, m_value_end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800383}
384
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700385const Block&
386Block::get(uint32_t type) const
387{
388 element_const_iterator it = this->find(type);
389 if (it != m_subBlocks.end())
390 return *it;
391
392 throw Error("(Block::get) Requested a non-existed type [" +
393 boost::lexical_cast<std::string>(type) + "] from Block");
394}
395
396Block::element_const_iterator
397Block::find(uint32_t type) const
398{
399 return std::find_if(m_subBlocks.begin(), m_subBlocks.end(),
400 [type] (const Block& subBlock) { return subBlock.type() == type; });
401}
402
403void
404Block::remove(uint32_t type)
405{
406 resetWire();
407
408 auto it = std::remove_if(m_subBlocks.begin(), m_subBlocks.end(),
Eric Newberrya3d9fc02015-07-26 10:55:44 -0700409 [type] (const Block& subBlock) { return subBlock.type() == type; });
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700410 m_subBlocks.resize(it - m_subBlocks.begin());
411}
412
Yingdi Yu4270f202014-01-28 14:19:16 -0800413Block
414Block::blockFromValue() const
415{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700416 if (value_size() == 0)
Yingdi Yu4270f202014-01-28 14:19:16 -0800417 throw Error("Underlying value buffer is empty");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700418
Yingdi Yu4270f202014-01-28 14:19:16 -0800419 Buffer::const_iterator begin = value_begin(),
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700420 end = value_end();
Yingdi Yu4270f202014-01-28 14:19:16 -0800421
422 Buffer::const_iterator element_begin = begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700423
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600424 uint32_t type = tlv::readType(begin, end);
425 uint64_t length = tlv::readVarNumber(begin, end);
Yingdi Yu4270f202014-01-28 14:19:16 -0800426
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -0800427 if (length != static_cast<uint64_t>(end - begin))
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600428 throw tlv::Error("TLV length mismatches buffer length");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700429
Yingdi Yu4270f202014-01-28 14:19:16 -0800430 return Block(m_buffer,
431 type,
432 element_begin, end,
433 begin, end);
434}
435
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400436Block::operator boost::asio::const_buffer() const
437{
438 return boost::asio::const_buffer(wire(), size());
439}
440
441bool
442Block::empty() const
443{
444 return m_type == std::numeric_limits<uint32_t>::max();
445}
446
447bool
448Block::hasWire() const
449{
450 return m_buffer && (m_begin != m_end);
451}
452
453Buffer::const_iterator
454Block::begin() const
455{
456 if (!hasWire())
457 throw Error("Underlying wire buffer is empty");
458
459 return m_begin;
460}
461
462Buffer::const_iterator
463Block::end() const
464{
465 if (!hasWire())
466 throw Error("Underlying wire buffer is empty");
467
468 return m_end;
469}
470
471const uint8_t*
472Block::wire() const
473{
474 if (!hasWire())
475 throw Error("(Block::wire) Underlying wire buffer is empty");
476
477 return &*m_begin;
478}
479
480size_t
481Block::size() const
482{
483 if (hasWire() || hasValue()) {
484 return m_size;
485 }
486 else
487 throw Error("Block size cannot be determined (undefined block size)");
488}
489
490bool
491Block::hasValue() const
492{
493 return static_cast<bool>(m_buffer);
494}
495
496const uint8_t*
497Block::value() const
498{
499 if (!hasValue())
500 return 0;
501
502 return &*m_value_begin;
503}
504
505size_t
506Block::value_size() const
507{
508 if (!hasValue())
509 return 0;
510
511 return m_value_end - m_value_begin;
512}
513
514Block::element_iterator
Joao Pereira7476ebf2015-07-07 14:54:39 -0400515Block::erase(Block::element_const_iterator position)
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400516{
517 resetWire();
Joao Pereira7476ebf2015-07-07 14:54:39 -0400518
519#ifdef NDN_CXX_HAVE_VECTOR_INSERT_ERASE_CONST_ITERATOR
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400520 return m_subBlocks.erase(position);
Joao Pereira7476ebf2015-07-07 14:54:39 -0400521#else
522 element_iterator it = m_subBlocks.begin();
523 std::advance(it, std::distance(m_subBlocks.cbegin(), position));
524 return m_subBlocks.erase(it);
525#endif
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400526}
527
528Block::element_iterator
Joao Pereira7476ebf2015-07-07 14:54:39 -0400529Block::erase(Block::element_const_iterator first, Block::element_const_iterator last)
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400530{
531 resetWire();
Joao Pereira7476ebf2015-07-07 14:54:39 -0400532
533#ifdef NDN_CXX_HAVE_VECTOR_INSERT_ERASE_CONST_ITERATOR
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400534 return m_subBlocks.erase(first, last);
Joao Pereira7476ebf2015-07-07 14:54:39 -0400535#else
536 element_iterator itStart = m_subBlocks.begin();
537 element_iterator itEnd = m_subBlocks.begin();
538 std::advance(itStart, std::distance(m_subBlocks.cbegin(), first));
539 std::advance(itEnd, std::distance(m_subBlocks.cbegin(), last));
540 return m_subBlocks.erase(itStart, itEnd);
541#endif
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400542}
543
544void
545Block::push_back(const Block& element)
546{
547 resetWire();
548 m_subBlocks.push_back(element);
549}
550
Joao Pereira7476ebf2015-07-07 14:54:39 -0400551Block::element_iterator
552Block::insert(Block::element_const_iterator pos, const Block& element)
553{
554 resetWire();
555
556#ifdef NDN_CXX_HAVE_VECTOR_INSERT_ERASE_CONST_ITERATOR
557 return m_subBlocks.insert(pos, element);
558#else
559 element_iterator it = m_subBlocks.begin();
560 std::advance(it, std::distance(m_subBlocks.cbegin(), pos));
561 return m_subBlocks.insert(it, element);
562#endif
563}
564
Joao Pereira9c2a9a82015-07-10 14:45:48 -0400565Block::element_const_iterator
566Block::elements_begin() const
567{
568 return m_subBlocks.begin();
569}
570
571Block::element_const_iterator
572Block::elements_end() const
573{
574 return m_subBlocks.end();
575}
576
577size_t
578Block::elements_size() const
579{
580 return m_subBlocks.size();
581}
582
583bool
584Block::operator!=(const Block& other) const
585{
586 return !this->operator==(other);
587}
588
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700589bool
590Block::operator==(const Block& other) const
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700591{
Junxiao Shi81a6c5d2014-11-30 00:14:42 -0700592 return this->size() == other.size() &&
593 std::equal(this->begin(), this->end(), other.begin());
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700594}
595
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800596} // namespace ndn