blob: 38fb85bb4b57db9ddea5a71a1f1506f779e9b8eb [file] [log] [blame]
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07002/**
3 * Copyright (c) 2013-2014, Regents of the University of California.
4 * All rights reserved.
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -08005 *
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07006 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
7 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -08008 *
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07009 * This file licensed under New BSD License. See COPYING for detailed information about
10 * ndn-cxx library copyright, permissions, and redistribution restrictions.
11 *
12 * @author Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080013 */
14
Alexander Afanasyeve2dcdfd2014-02-07 15:53:28 -080015#include "common.hpp"
16
17#include "block.hpp"
18#include "tlv.hpp"
Alexander Afanasyev15151312014-02-16 00:53:51 -080019#include "encoding-buffer.hpp"
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080020
21namespace ndn {
22
23Block::Block()
24 : m_type(std::numeric_limits<uint32_t>::max())
25{
26}
27
Alexander Afanasyev15151312014-02-16 00:53:51 -080028Block::Block(const EncodingBuffer& buffer)
29 : m_buffer(buffer.m_buffer)
30 , m_begin(buffer.begin())
31 , m_end(buffer.end())
32 , m_size(m_end - m_begin)
33{
34 m_value_begin = m_begin;
35 m_value_end = m_end;
36
37 m_type = Tlv::readType(m_value_begin, m_value_end);
38 uint64_t length = Tlv::readVarNumber(m_value_begin, m_value_end);
39 if (length != static_cast<uint64_t>(m_value_end - m_value_begin))
40 {
41 throw Tlv::Error("TLV length doesn't match buffer length");
42 }
43}
44
Alexander Afanasyeva465e972014-03-22 17:21:49 -070045Block::Block(const ConstBufferPtr& wire,
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080046 uint32_t type,
Alexander Afanasyeva465e972014-03-22 17:21:49 -070047 const Buffer::const_iterator& begin, const Buffer::const_iterator& end,
48 const Buffer::const_iterator& valueBegin, const Buffer::const_iterator& valueEnd)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080049 : m_buffer(wire)
50 , m_type(type)
51 , m_begin(begin)
52 , m_end(end)
53 , m_size(m_end - m_begin)
54 , m_value_begin(valueBegin)
55 , m_value_end(valueEnd)
56{
57}
58
Alexander Afanasyeva465e972014-03-22 17:21:49 -070059Block::Block(const ConstBufferPtr& buffer)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080060 : m_buffer(buffer)
61 , m_begin(m_buffer->begin())
62 , m_end(m_buffer->end())
63 , m_size(m_end - m_begin)
64{
Alexander Afanasyev233750e2014-02-16 00:50:07 -080065 m_value_begin = m_begin;
66 m_value_end = m_end;
Alexander Afanasyev937aa782014-03-21 13:17:57 -070067
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080068 m_type = Tlv::readType(m_value_begin, m_value_end);
69
70 uint64_t length = Tlv::readVarNumber(m_value_begin, m_value_end);
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -080071 if (length != static_cast<uint64_t>(m_value_end - m_value_begin))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080072 {
73 throw Tlv::Error("TLV length doesn't match buffer length");
74 }
75}
76
Alexander Afanasyeva465e972014-03-22 17:21:49 -070077Block::Block(const ConstBufferPtr& buffer,
78 const Buffer::const_iterator& begin, const Buffer::const_iterator& end,
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080079 bool verifyLength/* = true*/)
Alexander Afanasyev187bc482014-02-06 15:04:04 -080080 : m_buffer(buffer)
81 , m_begin(begin)
82 , m_end(end)
Alexander Afanasyev380420b2014-02-09 20:52:29 -080083 , m_size(m_end - m_begin)
Alexander Afanasyev187bc482014-02-06 15:04:04 -080084{
Alexander Afanasyev233750e2014-02-16 00:50:07 -080085 m_value_begin = m_begin;
86 m_value_end = m_end;
Alexander Afanasyev380420b2014-02-09 20:52:29 -080087
Alexander Afanasyev187bc482014-02-06 15:04:04 -080088 m_type = Tlv::readType(m_value_begin, m_value_end);
Alexander Afanasyev63ab0842014-03-19 18:39:31 -070089 uint64_t length = Tlv::readVarNumber(m_value_begin, m_value_end);
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080090 if (verifyLength)
Alexander Afanasyev187bc482014-02-06 15:04:04 -080091 {
Alexander Afanasyev5964fb72014-02-18 12:42:45 -080092 if (length != static_cast<uint64_t>(m_value_end - m_value_begin))
93 {
94 throw Tlv::Error("TLV length doesn't match buffer length");
95 }
Alexander Afanasyev187bc482014-02-06 15:04:04 -080096 }
97}
98
Yingdi Yu27158392014-01-20 13:04:20 -080099Block::Block(std::istream& is)
100{
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700101 std::istream_iterator<uint8_t> tmp_begin(is);
Yingdi Yu27158392014-01-20 13:04:20 -0800102 std::istream_iterator<uint8_t> tmp_end;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700103
Yingdi Yu27158392014-01-20 13:04:20 -0800104 m_type = Tlv::readType(tmp_begin, tmp_end);
105 uint64_t length = Tlv::readVarNumber(tmp_begin, tmp_end);
106
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700107 // We may still have some problem here, if some exception happens in this constructor,
108 // we may completely lose all the bytes extracted from the stream.
Yingdi Yu27158392014-01-20 13:04:20 -0800109
110 OBufferStream os;
111 size_t headerLength = Tlv::writeVarNumber(os, m_type);
112 headerLength += Tlv::writeVarNumber(os, length);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700113
Yingdi Yu27158392014-01-20 13:04:20 -0800114 char* buf = new char[length];
115 buf[0] = *tmp_begin;
116 is.read(buf+1, length-1);
117
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700118 if (length != static_cast<uint64_t>(is.gcount()) + 1)
Yingdi Yu27158392014-01-20 13:04:20 -0800119 {
120 delete [] buf;
121 throw Tlv::Error("Not enough data in the buffer to fully parse TLV");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700122 }
Yingdi Yu27158392014-01-20 13:04:20 -0800123
124 os.write(buf, length);
125 delete [] buf;
126
127 m_buffer = os.buf();
128
129 m_begin = m_buffer->begin();
130 m_end = m_buffer->end();
131 m_size = m_end - m_begin;
132
133 m_value_begin = m_buffer->begin() + headerLength;
134 m_value_end = m_buffer->end();
135}
136
137
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700138Block::Block(const uint8_t* buffer, size_t maxlength)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800139{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700140 const uint8_t* tmp_begin = buffer;
141 const uint8_t* tmp_end = buffer + maxlength;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700142
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800143 m_type = Tlv::readType(tmp_begin, tmp_end);
144 uint64_t length = Tlv::readVarNumber(tmp_begin, tmp_end);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700145
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -0800146 if (length > static_cast<uint64_t>(tmp_end - tmp_begin))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800147 {
148 throw Tlv::Error("Not enough data in the buffer to fully parse TLV");
149 }
150
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700151 m_buffer = ptr_lib::make_shared<Buffer>(buffer, (tmp_begin - buffer) + length);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800152
153 m_begin = m_buffer->begin();
154 m_end = m_buffer->end();
155 m_size = m_end - m_begin;
156
157 m_value_begin = m_buffer->begin() + (tmp_begin - buffer);
158 m_value_end = m_buffer->end();
159}
160
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700161Block::Block(const void* bufferX, size_t maxlength)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800162{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700163 const uint8_t* buffer = reinterpret_cast<const uint8_t*>(bufferX);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700164
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700165 const uint8_t* tmp_begin = buffer;
166 const uint8_t* tmp_end = buffer + maxlength;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700167
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800168 m_type = Tlv::readType(tmp_begin, tmp_end);
169 uint64_t length = Tlv::readVarNumber(tmp_begin, tmp_end);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700170
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -0800171 if (length > static_cast<uint64_t>(tmp_end - tmp_begin))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800172 {
173 throw Tlv::Error("Not enough data in the buffer to fully parse TLV");
174 }
175
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700176 m_buffer = ptr_lib::make_shared<Buffer>(buffer, (tmp_begin - buffer) + length);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800177
178 m_begin = m_buffer->begin();
179 m_end = m_buffer->end();
180 m_size = m_end - m_begin;
181
182 m_value_begin = m_buffer->begin() + (tmp_begin - buffer);
183 m_value_end = m_buffer->end();
184}
185
186Block::Block(uint32_t type)
187 : m_type(type)
188{
189}
190
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700191Block::Block(uint32_t type, const ConstBufferPtr& value)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800192 : m_buffer(value)
193 , m_type(type)
194 , m_begin(m_buffer->end())
195 , m_end(m_buffer->end())
196 , m_value_begin(m_buffer->begin())
197 , m_value_end(m_buffer->end())
198{
199 m_size = Tlv::sizeOfVarNumber(m_type) + Tlv::sizeOfVarNumber(value_size()) + value_size();
200}
201
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700202Block::Block(uint32_t type, const Block& value)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800203 : m_buffer(value.m_buffer)
204 , m_type(type)
205 , m_begin(m_buffer->end())
206 , m_end(m_buffer->end())
Alexander Afanasyevc8823bc2014-02-09 19:33:33 -0800207 , m_value_begin(value.begin())
208 , m_value_end(value.end())
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800209{
210 m_size = Tlv::sizeOfVarNumber(m_type) + Tlv::sizeOfVarNumber(value_size()) + value_size();
211}
212
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700213bool
214Block::fromBuffer(const ConstBufferPtr& wire, size_t offset, Block& block)
215{
216 Buffer::const_iterator tempBegin = wire->begin() + offset;
217
218 uint32_t type;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700219 bool isOk = Tlv::readType(tempBegin, wire->end(), type);
220 if (!isOk)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700221 return false;
222
223 uint64_t length;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700224 isOk = Tlv::readVarNumber(tempBegin, wire->end(), length);
225 if (!isOk)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700226 return false;
227
228 if (length > static_cast<uint64_t>(wire->end() - tempBegin))
229 {
230 return false;
231 }
232
233 block = Block(wire, type,
234 wire->begin() + offset, tempBegin + length,
235 tempBegin, tempBegin + length);
236
237 return true;
238}
239
240bool
241Block::fromBuffer(const uint8_t* buffer, size_t maxSize, Block& block)
242{
243 const uint8_t* tempBegin = buffer;
244 const uint8_t* tempEnd = buffer + maxSize;
245
Mickey Sweatt632e0572014-04-20 00:36:32 -0700246 uint32_t type = 0;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700247 bool isOk = Tlv::readType(tempBegin, tempEnd, type);
248 if (!isOk)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700249 return false;
250
251 uint64_t length;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700252 isOk = Tlv::readVarNumber(tempBegin, tempEnd, length);
253 if (!isOk)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700254 return false;
255
256 if (length > static_cast<uint64_t>(tempEnd - tempBegin))
257 {
258 return false;
259 }
260
261 BufferPtr sharedBuffer = make_shared<Buffer>(buffer, tempBegin + length);
262 block = Block(sharedBuffer, type,
263 sharedBuffer->begin(), sharedBuffer->end(),
264 sharedBuffer->begin() + (tempBegin - buffer), sharedBuffer->end());
265
266 return true;
267}
268
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800269void
Alexander Afanasyev29e5c3d2014-02-11 00:01:10 -0800270Block::parse() const
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800271{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700272 if (!m_subBlocks.empty() || value_size() == 0)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800273 return;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700274
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700275 Buffer::const_iterator begin = value_begin();
276 Buffer::const_iterator end = value_end();
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800277
278 while (begin != end)
279 {
280 Buffer::const_iterator element_begin = begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700281
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800282 uint32_t type = Tlv::readType(begin, end);
283 uint64_t length = Tlv::readVarNumber(begin, end);
284
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -0800285 if (length > static_cast<uint64_t>(end - begin))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800286 {
287 m_subBlocks.clear();
288 throw Tlv::Error("TLV length exceeds buffer length");
289 }
290 Buffer::const_iterator element_end = begin + length;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700291
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800292 m_subBlocks.push_back(Block(m_buffer,
293 type,
294 element_begin, element_end,
295 begin, element_end));
296
297 begin = element_end;
298 // don't do recursive parsing, just the top level
299 }
300}
301
302void
303Block::encode()
304{
305 if (hasWire())
306 return;
307
308 OBufferStream os;
309 Tlv::writeVarNumber(os, type());
310
311 if (hasValue())
312 {
313 Tlv::writeVarNumber(os, value_size());
314 os.write(reinterpret_cast<const char*>(value()), value_size());
315 }
Alexander Afanasyev8ea763d2014-02-06 20:32:52 -0800316 else if (m_subBlocks.size() == 0)
317 {
318 Tlv::writeVarNumber(os, 0);
319 }
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800320 else
321 {
322 size_t valueSize = 0;
323 for (element_const_iterator i = m_subBlocks.begin(); i != m_subBlocks.end(); ++i) {
324 valueSize += i->size();
325 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700326
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800327 Tlv::writeVarNumber(os, valueSize);
328
329 for (element_const_iterator i = m_subBlocks.begin(); i != m_subBlocks.end(); ++i) {
330 if (i->hasWire())
331 os.write(reinterpret_cast<const char*>(i->wire()), i->size());
332 else if (i->hasValue()) {
333 Tlv::writeVarNumber(os, i->type());
334 Tlv::writeVarNumber(os, i->value_size());
335 os.write(reinterpret_cast<const char*>(i->value()), i->value_size());
336 }
337 else
338 throw Error("Underlying value buffer is empty");
339 }
340 }
341
342 // now assign correct block
343
344 m_buffer = os.buf();
345 m_begin = m_buffer->begin();
346 m_end = m_buffer->end();
347 m_size = m_end - m_begin;
348
349 m_value_begin = m_buffer->begin();
350 m_value_end = m_buffer->end();
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700351
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800352 Tlv::readType(m_value_begin, m_value_end);
353 Tlv::readVarNumber(m_value_begin, m_value_end);
354}
355
Yingdi Yu4270f202014-01-28 14:19:16 -0800356Block
357Block::blockFromValue() const
358{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700359 if (value_size() == 0)
Yingdi Yu4270f202014-01-28 14:19:16 -0800360 throw Error("Underlying value buffer is empty");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700361
Yingdi Yu4270f202014-01-28 14:19:16 -0800362 Buffer::const_iterator begin = value_begin(),
363 end = value_end();
364
365 Buffer::const_iterator element_begin = begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700366
Yingdi Yu4270f202014-01-28 14:19:16 -0800367 uint32_t type = Tlv::readType(begin, end);
368 uint64_t length = Tlv::readVarNumber(begin, end);
369
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -0800370 if (length != static_cast<uint64_t>(end - begin))
Yingdi Yu4270f202014-01-28 14:19:16 -0800371 throw Tlv::Error("TLV length mismatches buffer length");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700372
Yingdi Yu4270f202014-01-28 14:19:16 -0800373 return Block(m_buffer,
374 type,
375 element_begin, end,
376 begin, end);
377}
378
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800379} // namespace ndn