blob: ed265b02dc8075f54b82999abf2ed127b153d7ad [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 Afanasyev13bb51a2014-01-02 19:13:26 -080034
35namespace ndn {
36
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070037const size_t MAX_SIZE_OF_BLOCK_FROM_STREAM = 8800;
38
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080039Block::Block()
40 : m_type(std::numeric_limits<uint32_t>::max())
41{
42}
43
Alexander Afanasyev15151312014-02-16 00:53:51 -080044Block::Block(const EncodingBuffer& buffer)
45 : m_buffer(buffer.m_buffer)
46 , m_begin(buffer.begin())
47 , m_end(buffer.end())
48 , m_size(m_end - m_begin)
49{
50 m_value_begin = m_begin;
51 m_value_end = m_end;
52
53 m_type = Tlv::readType(m_value_begin, m_value_end);
54 uint64_t length = Tlv::readVarNumber(m_value_begin, m_value_end);
55 if (length != static_cast<uint64_t>(m_value_end - m_value_begin))
56 {
57 throw Tlv::Error("TLV length doesn't match buffer length");
58 }
59}
60
Alexander Afanasyeva465e972014-03-22 17:21:49 -070061Block::Block(const ConstBufferPtr& wire,
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080062 uint32_t type,
Alexander Afanasyeva465e972014-03-22 17:21:49 -070063 const Buffer::const_iterator& begin, const Buffer::const_iterator& end,
64 const Buffer::const_iterator& valueBegin, const Buffer::const_iterator& valueEnd)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080065 : m_buffer(wire)
66 , m_type(type)
67 , m_begin(begin)
68 , m_end(end)
69 , m_size(m_end - m_begin)
70 , m_value_begin(valueBegin)
71 , m_value_end(valueEnd)
72{
73}
74
Alexander Afanasyeva465e972014-03-22 17:21:49 -070075Block::Block(const ConstBufferPtr& buffer)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080076 : m_buffer(buffer)
77 , m_begin(m_buffer->begin())
78 , m_end(m_buffer->end())
79 , m_size(m_end - m_begin)
80{
Alexander Afanasyev233750e2014-02-16 00:50:07 -080081 m_value_begin = m_begin;
82 m_value_end = m_end;
Alexander Afanasyev937aa782014-03-21 13:17:57 -070083
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080084 m_type = Tlv::readType(m_value_begin, m_value_end);
85
86 uint64_t length = Tlv::readVarNumber(m_value_begin, m_value_end);
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -080087 if (length != static_cast<uint64_t>(m_value_end - m_value_begin))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080088 {
89 throw Tlv::Error("TLV length doesn't match buffer length");
90 }
91}
92
Alexander Afanasyeva465e972014-03-22 17:21:49 -070093Block::Block(const ConstBufferPtr& buffer,
94 const Buffer::const_iterator& begin, const Buffer::const_iterator& end,
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080095 bool verifyLength/* = true*/)
Alexander Afanasyev187bc482014-02-06 15:04:04 -080096 : m_buffer(buffer)
97 , m_begin(begin)
98 , m_end(end)
Alexander Afanasyev380420b2014-02-09 20:52:29 -080099 , m_size(m_end - m_begin)
Alexander Afanasyev187bc482014-02-06 15:04:04 -0800100{
Alexander Afanasyev233750e2014-02-16 00:50:07 -0800101 m_value_begin = m_begin;
102 m_value_end = m_end;
Alexander Afanasyev380420b2014-02-09 20:52:29 -0800103
Alexander Afanasyev187bc482014-02-06 15:04:04 -0800104 m_type = Tlv::readType(m_value_begin, m_value_end);
Alexander Afanasyev63ab0842014-03-19 18:39:31 -0700105 uint64_t length = Tlv::readVarNumber(m_value_begin, m_value_end);
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800106 if (verifyLength)
Alexander Afanasyev187bc482014-02-06 15:04:04 -0800107 {
Alexander Afanasyev5964fb72014-02-18 12:42:45 -0800108 if (length != static_cast<uint64_t>(m_value_end - m_value_begin))
109 {
110 throw Tlv::Error("TLV length doesn't match buffer length");
111 }
Alexander Afanasyev187bc482014-02-06 15:04:04 -0800112 }
113}
114
Yingdi Yu27158392014-01-20 13:04:20 -0800115
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700116Block::Block(const uint8_t* buffer, size_t maxlength)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800117{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700118 const uint8_t* tmp_begin = buffer;
119 const uint8_t* tmp_end = buffer + maxlength;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700120
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800121 m_type = Tlv::readType(tmp_begin, tmp_end);
122 uint64_t length = Tlv::readVarNumber(tmp_begin, tmp_end);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700123
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -0800124 if (length > static_cast<uint64_t>(tmp_end - tmp_begin))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800125 {
126 throw Tlv::Error("Not enough data in the buffer to fully parse TLV");
127 }
128
Alexander Afanasyevf73f0632014-05-12 18:02:37 -0700129 m_buffer = make_shared<Buffer>(buffer, (tmp_begin - buffer) + length);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800130
131 m_begin = m_buffer->begin();
132 m_end = m_buffer->end();
133 m_size = m_end - m_begin;
134
135 m_value_begin = m_buffer->begin() + (tmp_begin - buffer);
136 m_value_end = m_buffer->end();
137}
138
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700139Block::Block(const void* bufferX, size_t maxlength)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800140{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700141 const uint8_t* buffer = reinterpret_cast<const uint8_t*>(bufferX);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700142
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700143 const uint8_t* tmp_begin = buffer;
144 const uint8_t* tmp_end = buffer + maxlength;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700145
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800146 m_type = Tlv::readType(tmp_begin, tmp_end);
147 uint64_t length = Tlv::readVarNumber(tmp_begin, tmp_end);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700148
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -0800149 if (length > static_cast<uint64_t>(tmp_end - tmp_begin))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800150 {
151 throw Tlv::Error("Not enough data in the buffer to fully parse TLV");
152 }
153
Alexander Afanasyevf73f0632014-05-12 18:02:37 -0700154 m_buffer = make_shared<Buffer>(buffer, (tmp_begin - buffer) + length);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800155
156 m_begin = m_buffer->begin();
157 m_end = m_buffer->end();
158 m_size = m_end - m_begin;
159
160 m_value_begin = m_buffer->begin() + (tmp_begin - buffer);
161 m_value_end = m_buffer->end();
162}
163
164Block::Block(uint32_t type)
165 : m_type(type)
166{
167}
168
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700169Block::Block(uint32_t type, const ConstBufferPtr& value)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800170 : m_buffer(value)
171 , m_type(type)
172 , m_begin(m_buffer->end())
173 , m_end(m_buffer->end())
174 , m_value_begin(m_buffer->begin())
175 , m_value_end(m_buffer->end())
176{
177 m_size = Tlv::sizeOfVarNumber(m_type) + Tlv::sizeOfVarNumber(value_size()) + value_size();
178}
179
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700180Block::Block(uint32_t type, const Block& value)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800181 : m_buffer(value.m_buffer)
182 , m_type(type)
183 , m_begin(m_buffer->end())
184 , m_end(m_buffer->end())
Alexander Afanasyevc8823bc2014-02-09 19:33:33 -0800185 , m_value_begin(value.begin())
186 , m_value_end(value.end())
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800187{
188 m_size = Tlv::sizeOfVarNumber(m_type) + Tlv::sizeOfVarNumber(value_size()) + value_size();
189}
190
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700191Block
192Block::fromStream(std::istream& is)
193{
194 std::istream_iterator<uint8_t> tmp_begin(is);
195 std::istream_iterator<uint8_t> tmp_end;
196
197 uint32_t type = Tlv::readType(tmp_begin, tmp_end);
198 uint64_t length = Tlv::readVarNumber(tmp_begin, tmp_end);
199
200 if (length > MAX_SIZE_OF_BLOCK_FROM_STREAM)
201 throw Tlv::Error("Length of block from stream is too large");
202
203 // We may still have some problem here, if some exception happens,
204 // we may completely lose all the bytes extracted from the stream.
205
206 char buf[MAX_SIZE_OF_BLOCK_FROM_STREAM];
207 buf[0] = *tmp_begin;
208 is.read(buf+1, length-1);
209
210 if (length != static_cast<uint64_t>(is.gcount()) + 1) {
211 throw Tlv::Error("Not enough data in the buffer to fully parse TLV");
212 }
213
214 return dataBlock(type, buf, length);
215}
216
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700217bool
218Block::fromBuffer(const ConstBufferPtr& wire, size_t offset, Block& block)
219{
220 Buffer::const_iterator tempBegin = wire->begin() + offset;
221
222 uint32_t type;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700223 bool isOk = Tlv::readType(tempBegin, wire->end(), type);
224 if (!isOk)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700225 return false;
226
227 uint64_t length;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700228 isOk = Tlv::readVarNumber(tempBegin, wire->end(), length);
229 if (!isOk)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700230 return false;
231
232 if (length > static_cast<uint64_t>(wire->end() - tempBegin))
233 {
234 return false;
235 }
236
237 block = Block(wire, type,
238 wire->begin() + offset, tempBegin + length,
239 tempBegin, tempBegin + length);
240
241 return true;
242}
243
244bool
245Block::fromBuffer(const uint8_t* buffer, size_t maxSize, Block& block)
246{
247 const uint8_t* tempBegin = buffer;
248 const uint8_t* tempEnd = buffer + maxSize;
249
Mickey Sweatt632e0572014-04-20 00:36:32 -0700250 uint32_t type = 0;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700251 bool isOk = Tlv::readType(tempBegin, tempEnd, type);
252 if (!isOk)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700253 return false;
254
255 uint64_t length;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700256 isOk = Tlv::readVarNumber(tempBegin, tempEnd, length);
257 if (!isOk)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700258 return false;
259
260 if (length > static_cast<uint64_t>(tempEnd - tempBegin))
261 {
262 return false;
263 }
264
265 BufferPtr sharedBuffer = make_shared<Buffer>(buffer, tempBegin + length);
266 block = Block(sharedBuffer, type,
267 sharedBuffer->begin(), sharedBuffer->end(),
268 sharedBuffer->begin() + (tempBegin - buffer), sharedBuffer->end());
269
270 return true;
271}
272
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800273void
Alexander Afanasyev29e5c3d2014-02-11 00:01:10 -0800274Block::parse() const
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800275{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700276 if (!m_subBlocks.empty() || value_size() == 0)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800277 return;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700278
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700279 Buffer::const_iterator begin = value_begin();
280 Buffer::const_iterator end = value_end();
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800281
282 while (begin != end)
283 {
284 Buffer::const_iterator element_begin = begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700285
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800286 uint32_t type = Tlv::readType(begin, end);
287 uint64_t length = Tlv::readVarNumber(begin, end);
288
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -0800289 if (length > static_cast<uint64_t>(end - begin))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800290 {
291 m_subBlocks.clear();
292 throw Tlv::Error("TLV length exceeds buffer length");
293 }
294 Buffer::const_iterator element_end = begin + length;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700295
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800296 m_subBlocks.push_back(Block(m_buffer,
297 type,
298 element_begin, element_end,
299 begin, element_end));
300
301 begin = element_end;
302 // don't do recursive parsing, just the top level
303 }
304}
305
306void
307Block::encode()
308{
309 if (hasWire())
310 return;
311
312 OBufferStream os;
313 Tlv::writeVarNumber(os, type());
314
315 if (hasValue())
316 {
317 Tlv::writeVarNumber(os, value_size());
318 os.write(reinterpret_cast<const char*>(value()), value_size());
319 }
Alexander Afanasyev8ea763d2014-02-06 20:32:52 -0800320 else if (m_subBlocks.size() == 0)
321 {
322 Tlv::writeVarNumber(os, 0);
323 }
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800324 else
325 {
326 size_t valueSize = 0;
327 for (element_const_iterator i = m_subBlocks.begin(); i != m_subBlocks.end(); ++i) {
328 valueSize += i->size();
329 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700330
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800331 Tlv::writeVarNumber(os, valueSize);
332
333 for (element_const_iterator i = m_subBlocks.begin(); i != m_subBlocks.end(); ++i) {
334 if (i->hasWire())
335 os.write(reinterpret_cast<const char*>(i->wire()), i->size());
336 else if (i->hasValue()) {
337 Tlv::writeVarNumber(os, i->type());
338 Tlv::writeVarNumber(os, i->value_size());
339 os.write(reinterpret_cast<const char*>(i->value()), i->value_size());
340 }
341 else
342 throw Error("Underlying value buffer is empty");
343 }
344 }
345
346 // now assign correct block
347
348 m_buffer = os.buf();
349 m_begin = m_buffer->begin();
350 m_end = m_buffer->end();
351 m_size = m_end - m_begin;
352
353 m_value_begin = m_buffer->begin();
354 m_value_end = m_buffer->end();
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700355
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800356 Tlv::readType(m_value_begin, m_value_end);
357 Tlv::readVarNumber(m_value_begin, m_value_end);
358}
359
Yingdi Yu4270f202014-01-28 14:19:16 -0800360Block
361Block::blockFromValue() const
362{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700363 if (value_size() == 0)
Yingdi Yu4270f202014-01-28 14:19:16 -0800364 throw Error("Underlying value buffer is empty");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700365
Yingdi Yu4270f202014-01-28 14:19:16 -0800366 Buffer::const_iterator begin = value_begin(),
367 end = value_end();
368
369 Buffer::const_iterator element_begin = begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700370
Yingdi Yu4270f202014-01-28 14:19:16 -0800371 uint32_t type = Tlv::readType(begin, end);
372 uint64_t length = Tlv::readVarNumber(begin, end);
373
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -0800374 if (length != static_cast<uint64_t>(end - begin))
Yingdi Yu4270f202014-01-28 14:19:16 -0800375 throw Tlv::Error("TLV length mismatches buffer length");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700376
Yingdi Yu4270f202014-01-28 14:19:16 -0800377 return Block(m_buffer,
378 type,
379 element_begin, end,
380 begin, end);
381}
382
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700383const Block&
384Block::get(uint32_t type) const
385{
386 for (element_const_iterator i = m_subBlocks.begin();
387 i != m_subBlocks.end();
388 i++)
389 {
390 if (i->type() == type)
391 {
392 return *i;
393 }
394 }
395
396 throw Error("(Block::get) Requested a non-existed type [" +
397 boost::lexical_cast<std::string>(type) + "] from Block");
398}
399
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800400} // namespace ndn