blob: eeb0c3f444afa72956d2034a02f1027c9224dc39 [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 Afanasyevc169a812014-05-20 20:37:29 -04003 * Copyright (c) 2013-2014 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 "common.hpp"
25
26#include "block.hpp"
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070027#include "block-helpers.hpp"
28
Alexander Afanasyeve2dcdfd2014-02-07 15:53:28 -080029#include "tlv.hpp"
Alexander Afanasyev15151312014-02-16 00:53:51 -080030#include "encoding-buffer.hpp"
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070031#include "buffer-stream.hpp"
32
33#include <boost/lexical_cast.hpp>
Alexander Afanasyev6a05b4b2014-07-18 17:23:00 -070034#include <boost/asio/buffer.hpp>
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080035
36namespace ndn {
37
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070038const size_t MAX_SIZE_OF_BLOCK_FROM_STREAM = 8800;
39
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080040Block::Block()
41 : m_type(std::numeric_limits<uint32_t>::max())
42{
43}
44
Alexander Afanasyev15151312014-02-16 00:53:51 -080045Block::Block(const EncodingBuffer& buffer)
46 : m_buffer(buffer.m_buffer)
47 , m_begin(buffer.begin())
48 , m_end(buffer.end())
49 , m_size(m_end - m_begin)
50{
51 m_value_begin = m_begin;
52 m_value_end = m_end;
53
54 m_type = Tlv::readType(m_value_begin, m_value_end);
55 uint64_t length = Tlv::readVarNumber(m_value_begin, m_value_end);
56 if (length != static_cast<uint64_t>(m_value_end - m_value_begin))
57 {
58 throw Tlv::Error("TLV length doesn't match buffer length");
59 }
60}
61
Alexander Afanasyeva465e972014-03-22 17:21:49 -070062Block::Block(const ConstBufferPtr& wire,
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080063 uint32_t type,
Alexander Afanasyeva465e972014-03-22 17:21:49 -070064 const Buffer::const_iterator& begin, const Buffer::const_iterator& end,
65 const Buffer::const_iterator& valueBegin, const Buffer::const_iterator& valueEnd)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080066 : m_buffer(wire)
67 , m_type(type)
68 , m_begin(begin)
69 , m_end(end)
70 , m_size(m_end - m_begin)
71 , m_value_begin(valueBegin)
72 , m_value_end(valueEnd)
73{
74}
75
Alexander Afanasyeva465e972014-03-22 17:21:49 -070076Block::Block(const ConstBufferPtr& buffer)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080077 : m_buffer(buffer)
78 , m_begin(m_buffer->begin())
79 , m_end(m_buffer->end())
80 , m_size(m_end - m_begin)
81{
Alexander Afanasyev233750e2014-02-16 00:50:07 -080082 m_value_begin = m_begin;
83 m_value_end = m_end;
Alexander Afanasyev937aa782014-03-21 13:17:57 -070084
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080085 m_type = Tlv::readType(m_value_begin, m_value_end);
86
87 uint64_t length = Tlv::readVarNumber(m_value_begin, m_value_end);
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -080088 if (length != static_cast<uint64_t>(m_value_end - m_value_begin))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080089 {
90 throw Tlv::Error("TLV length doesn't match buffer length");
91 }
92}
93
Alexander Afanasyeva465e972014-03-22 17:21:49 -070094Block::Block(const ConstBufferPtr& buffer,
95 const Buffer::const_iterator& begin, const Buffer::const_iterator& end,
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080096 bool verifyLength/* = true*/)
Alexander Afanasyev187bc482014-02-06 15:04:04 -080097 : m_buffer(buffer)
98 , m_begin(begin)
99 , m_end(end)
Alexander Afanasyev380420b2014-02-09 20:52:29 -0800100 , m_size(m_end - m_begin)
Alexander Afanasyev187bc482014-02-06 15:04:04 -0800101{
Alexander Afanasyev233750e2014-02-16 00:50:07 -0800102 m_value_begin = m_begin;
103 m_value_end = m_end;
Alexander Afanasyev380420b2014-02-09 20:52:29 -0800104
Alexander Afanasyev187bc482014-02-06 15:04:04 -0800105 m_type = Tlv::readType(m_value_begin, m_value_end);
Alexander Afanasyev63ab0842014-03-19 18:39:31 -0700106 uint64_t length = Tlv::readVarNumber(m_value_begin, m_value_end);
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800107 if (verifyLength)
Alexander Afanasyev187bc482014-02-06 15:04:04 -0800108 {
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800109 if (length != static_cast<uint64_t>(m_value_end - m_value_begin))
110 {
111 throw Tlv::Error("TLV length doesn't match buffer length");
112 }
Alexander Afanasyev187bc482014-02-06 15:04:04 -0800113 }
114}
115
Yingdi Yu27158392014-01-20 13:04:20 -0800116
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700117Block::Block(const uint8_t* buffer, size_t maxlength)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800118{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700119 const uint8_t* tmp_begin = buffer;
120 const uint8_t* tmp_end = buffer + maxlength;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700121
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800122 m_type = Tlv::readType(tmp_begin, tmp_end);
123 uint64_t length = Tlv::readVarNumber(tmp_begin, tmp_end);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700124
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -0800125 if (length > static_cast<uint64_t>(tmp_end - tmp_begin))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800126 {
127 throw Tlv::Error("Not enough data in the buffer to fully parse TLV");
128 }
129
Alexander Afanasyevf73f0632014-05-12 18:02:37 -0700130 m_buffer = make_shared<Buffer>(buffer, (tmp_begin - buffer) + length);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800131
132 m_begin = m_buffer->begin();
133 m_end = m_buffer->end();
134 m_size = m_end - m_begin;
135
136 m_value_begin = m_buffer->begin() + (tmp_begin - buffer);
137 m_value_end = m_buffer->end();
138}
139
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700140Block::Block(const void* bufferX, size_t maxlength)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800141{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700142 const uint8_t* buffer = reinterpret_cast<const uint8_t*>(bufferX);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700143
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700144 const uint8_t* tmp_begin = buffer;
145 const uint8_t* tmp_end = buffer + maxlength;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700146
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800147 m_type = Tlv::readType(tmp_begin, tmp_end);
148 uint64_t length = Tlv::readVarNumber(tmp_begin, tmp_end);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700149
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -0800150 if (length > static_cast<uint64_t>(tmp_end - tmp_begin))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800151 {
152 throw Tlv::Error("Not enough data in the buffer to fully parse TLV");
153 }
154
Alexander Afanasyevf73f0632014-05-12 18:02:37 -0700155 m_buffer = make_shared<Buffer>(buffer, (tmp_begin - buffer) + length);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800156
157 m_begin = m_buffer->begin();
158 m_end = m_buffer->end();
159 m_size = m_end - m_begin;
160
161 m_value_begin = m_buffer->begin() + (tmp_begin - buffer);
162 m_value_end = m_buffer->end();
163}
164
165Block::Block(uint32_t type)
166 : m_type(type)
167{
168}
169
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700170Block::Block(uint32_t type, const ConstBufferPtr& value)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800171 : m_buffer(value)
172 , m_type(type)
173 , m_begin(m_buffer->end())
174 , m_end(m_buffer->end())
175 , m_value_begin(m_buffer->begin())
176 , m_value_end(m_buffer->end())
177{
178 m_size = Tlv::sizeOfVarNumber(m_type) + Tlv::sizeOfVarNumber(value_size()) + value_size();
179}
180
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700181Block::Block(uint32_t type, const Block& value)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800182 : m_buffer(value.m_buffer)
183 , m_type(type)
184 , m_begin(m_buffer->end())
185 , m_end(m_buffer->end())
Alexander Afanasyevc8823bc2014-02-09 19:33:33 -0800186 , m_value_begin(value.begin())
187 , m_value_end(value.end())
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800188{
189 m_size = Tlv::sizeOfVarNumber(m_type) + Tlv::sizeOfVarNumber(value_size()) + value_size();
190}
191
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700192Block
193Block::fromStream(std::istream& is)
194{
195 std::istream_iterator<uint8_t> tmp_begin(is);
196 std::istream_iterator<uint8_t> tmp_end;
197
198 uint32_t type = Tlv::readType(tmp_begin, tmp_end);
199 uint64_t length = Tlv::readVarNumber(tmp_begin, tmp_end);
200
201 if (length > MAX_SIZE_OF_BLOCK_FROM_STREAM)
202 throw Tlv::Error("Length of block from stream is too large");
203
204 // We may still have some problem here, if some exception happens,
205 // we may completely lose all the bytes extracted from the stream.
206
207 char buf[MAX_SIZE_OF_BLOCK_FROM_STREAM];
208 buf[0] = *tmp_begin;
209 is.read(buf+1, length-1);
210
211 if (length != static_cast<uint64_t>(is.gcount()) + 1) {
212 throw Tlv::Error("Not enough data in the buffer to fully parse TLV");
213 }
214
215 return dataBlock(type, buf, length);
216}
217
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700218bool
219Block::fromBuffer(const ConstBufferPtr& wire, size_t offset, Block& block)
220{
221 Buffer::const_iterator tempBegin = wire->begin() + offset;
222
223 uint32_t type;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700224 bool isOk = Tlv::readType(tempBegin, wire->end(), type);
225 if (!isOk)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700226 return false;
227
228 uint64_t length;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700229 isOk = Tlv::readVarNumber(tempBegin, wire->end(), length);
230 if (!isOk)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700231 return false;
232
233 if (length > static_cast<uint64_t>(wire->end() - tempBegin))
234 {
235 return false;
236 }
237
238 block = Block(wire, type,
239 wire->begin() + offset, tempBegin + length,
240 tempBegin, tempBegin + length);
241
242 return true;
243}
244
245bool
246Block::fromBuffer(const uint8_t* buffer, size_t maxSize, Block& block)
247{
248 const uint8_t* tempBegin = buffer;
249 const uint8_t* tempEnd = buffer + maxSize;
250
Mickey Sweatt632e0572014-04-20 00:36:32 -0700251 uint32_t type = 0;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700252 bool isOk = Tlv::readType(tempBegin, tempEnd, type);
253 if (!isOk)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700254 return false;
255
256 uint64_t length;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700257 isOk = Tlv::readVarNumber(tempBegin, tempEnd, length);
258 if (!isOk)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700259 return false;
260
261 if (length > static_cast<uint64_t>(tempEnd - tempBegin))
262 {
263 return false;
264 }
265
266 BufferPtr sharedBuffer = make_shared<Buffer>(buffer, tempBegin + length);
267 block = Block(sharedBuffer, type,
268 sharedBuffer->begin(), sharedBuffer->end(),
269 sharedBuffer->begin() + (tempBegin - buffer), sharedBuffer->end());
270
271 return true;
272}
273
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800274void
Alexander Afanasyev29e5c3d2014-02-11 00:01:10 -0800275Block::parse() const
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800276{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700277 if (!m_subBlocks.empty() || value_size() == 0)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800278 return;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700279
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700280 Buffer::const_iterator begin = value_begin();
281 Buffer::const_iterator end = value_end();
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800282
283 while (begin != end)
284 {
285 Buffer::const_iterator element_begin = begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700286
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800287 uint32_t type = Tlv::readType(begin, end);
288 uint64_t length = Tlv::readVarNumber(begin, end);
289
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -0800290 if (length > static_cast<uint64_t>(end - begin))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800291 {
292 m_subBlocks.clear();
293 throw Tlv::Error("TLV length exceeds buffer length");
294 }
295 Buffer::const_iterator element_end = begin + length;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700296
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800297 m_subBlocks.push_back(Block(m_buffer,
298 type,
299 element_begin, element_end,
300 begin, element_end));
301
302 begin = element_end;
303 // don't do recursive parsing, just the top level
304 }
305}
306
307void
308Block::encode()
309{
310 if (hasWire())
311 return;
312
313 OBufferStream os;
314 Tlv::writeVarNumber(os, type());
315
316 if (hasValue())
317 {
318 Tlv::writeVarNumber(os, value_size());
319 os.write(reinterpret_cast<const char*>(value()), value_size());
320 }
Alexander Afanasyev8ea763d2014-02-06 20:32:52 -0800321 else if (m_subBlocks.size() == 0)
322 {
323 Tlv::writeVarNumber(os, 0);
324 }
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800325 else
326 {
327 size_t valueSize = 0;
328 for (element_const_iterator i = m_subBlocks.begin(); i != m_subBlocks.end(); ++i) {
329 valueSize += i->size();
330 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700331
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800332 Tlv::writeVarNumber(os, valueSize);
333
334 for (element_const_iterator i = m_subBlocks.begin(); i != m_subBlocks.end(); ++i) {
335 if (i->hasWire())
336 os.write(reinterpret_cast<const char*>(i->wire()), i->size());
337 else if (i->hasValue()) {
338 Tlv::writeVarNumber(os, i->type());
339 Tlv::writeVarNumber(os, i->value_size());
340 os.write(reinterpret_cast<const char*>(i->value()), i->value_size());
341 }
342 else
343 throw Error("Underlying value buffer is empty");
344 }
345 }
346
347 // now assign correct block
348
349 m_buffer = os.buf();
350 m_begin = m_buffer->begin();
351 m_end = m_buffer->end();
352 m_size = m_end - m_begin;
353
354 m_value_begin = m_buffer->begin();
355 m_value_end = m_buffer->end();
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700356
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800357 Tlv::readType(m_value_begin, m_value_end);
358 Tlv::readVarNumber(m_value_begin, m_value_end);
359}
360
Yingdi Yu4270f202014-01-28 14:19:16 -0800361Block
362Block::blockFromValue() const
363{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700364 if (value_size() == 0)
Yingdi Yu4270f202014-01-28 14:19:16 -0800365 throw Error("Underlying value buffer is empty");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700366
Yingdi Yu4270f202014-01-28 14:19:16 -0800367 Buffer::const_iterator begin = value_begin(),
368 end = value_end();
369
370 Buffer::const_iterator element_begin = begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700371
Yingdi Yu4270f202014-01-28 14:19:16 -0800372 uint32_t type = Tlv::readType(begin, end);
373 uint64_t length = Tlv::readVarNumber(begin, end);
374
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -0800375 if (length != static_cast<uint64_t>(end - begin))
Yingdi Yu4270f202014-01-28 14:19:16 -0800376 throw Tlv::Error("TLV length mismatches buffer length");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700377
Yingdi Yu4270f202014-01-28 14:19:16 -0800378 return Block(m_buffer,
379 type,
380 element_begin, end,
381 begin, end);
382}
383
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700384const Block&
385Block::get(uint32_t type) const
386{
387 for (element_const_iterator i = m_subBlocks.begin();
388 i != m_subBlocks.end();
389 i++)
390 {
391 if (i->type() == type)
392 {
393 return *i;
394 }
395 }
396
397 throw Error("(Block::get) Requested a non-existed type [" +
398 boost::lexical_cast<std::string>(type) + "] from Block");
399}
400
Alexander Afanasyev6a05b4b2014-07-18 17:23:00 -0700401Block::operator boost::asio::const_buffer() const
402{
403 return boost::asio::const_buffer(wire(), size());
404}
405
406
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800407} // namespace ndn