blob: 37b2e6fd733d48a948bfe6c6c8c4346178cdee8d [file] [log] [blame]
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/*
3 * Copyright (c) 2013, Regents of the University of California
4 *
5 * BSD license, See the LICENSE file for more information
6 *
7 * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
8 */
9
Alexander Afanasyeve2dcdfd2014-02-07 15:53:28 -080010#include "common.hpp"
11
12#include "block.hpp"
13#include "tlv.hpp"
Alexander Afanasyev15151312014-02-16 00:53:51 -080014#include "encoding-buffer.hpp"
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080015
16namespace ndn {
17
18Block::Block()
19 : m_type(std::numeric_limits<uint32_t>::max())
20{
21}
22
Alexander Afanasyev15151312014-02-16 00:53:51 -080023Block::Block(const EncodingBuffer& buffer)
24 : m_buffer(buffer.m_buffer)
25 , m_begin(buffer.begin())
26 , m_end(buffer.end())
27 , m_size(m_end - m_begin)
28{
29 m_value_begin = m_begin;
30 m_value_end = m_end;
31
32 m_type = Tlv::readType(m_value_begin, m_value_end);
33 uint64_t length = Tlv::readVarNumber(m_value_begin, m_value_end);
34 if (length != static_cast<uint64_t>(m_value_end - m_value_begin))
35 {
36 throw Tlv::Error("TLV length doesn't match buffer length");
37 }
38}
39
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080040Block::Block(const ConstBufferPtr &wire,
41 uint32_t type,
Alexander Afanasyev187bc482014-02-06 15:04:04 -080042 const Buffer::const_iterator &begin, const Buffer::const_iterator &end,
43 const Buffer::const_iterator &valueBegin, const Buffer::const_iterator &valueEnd)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080044 : m_buffer(wire)
45 , m_type(type)
46 , m_begin(begin)
47 , m_end(end)
48 , m_size(m_end - m_begin)
49 , m_value_begin(valueBegin)
50 , m_value_end(valueEnd)
51{
52}
53
54Block::Block(const ConstBufferPtr &buffer)
55 : m_buffer(buffer)
56 , m_begin(m_buffer->begin())
57 , m_end(m_buffer->end())
58 , m_size(m_end - m_begin)
59{
Alexander Afanasyev233750e2014-02-16 00:50:07 -080060 m_value_begin = m_begin;
61 m_value_end = m_end;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080062
63 m_type = Tlv::readType(m_value_begin, m_value_end);
64
65 uint64_t length = Tlv::readVarNumber(m_value_begin, m_value_end);
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -080066 if (length != static_cast<uint64_t>(m_value_end - m_value_begin))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080067 {
68 throw Tlv::Error("TLV length doesn't match buffer length");
69 }
70}
71
Alexander Afanasyev187bc482014-02-06 15:04:04 -080072Block::Block(const ConstBufferPtr &buffer,
73 const Buffer::const_iterator &begin, const Buffer::const_iterator &end)
74 : m_buffer(buffer)
75 , m_begin(begin)
76 , m_end(end)
Alexander Afanasyev380420b2014-02-09 20:52:29 -080077 , m_size(m_end - m_begin)
Alexander Afanasyev187bc482014-02-06 15:04:04 -080078{
Alexander Afanasyev233750e2014-02-16 00:50:07 -080079 m_value_begin = m_begin;
80 m_value_end = m_end;
Alexander Afanasyev380420b2014-02-09 20:52:29 -080081
Alexander Afanasyev187bc482014-02-06 15:04:04 -080082 m_type = Tlv::readType(m_value_begin, m_value_end);
83 uint64_t length = Tlv::readVarNumber(m_value_begin, m_value_end);
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -080084 if (length != static_cast<uint64_t>(m_value_end - m_value_begin))
Alexander Afanasyev187bc482014-02-06 15:04:04 -080085 {
86 throw Tlv::Error("TLV length doesn't match buffer length");
87 }
88}
89
Yingdi Yu27158392014-01-20 13:04:20 -080090Block::Block(std::istream& is)
91{
92 std::istream_iterator<uint8_t> tmp_begin(is);
93 std::istream_iterator<uint8_t> tmp_end;
94
95 m_type = Tlv::readType(tmp_begin, tmp_end);
96 uint64_t length = Tlv::readVarNumber(tmp_begin, tmp_end);
97
98 // We may still have some problem here, if some exception happens in this constructor, we may completely lose all the bytes extracted from the stream.
99
100 OBufferStream os;
101 size_t headerLength = Tlv::writeVarNumber(os, m_type);
102 headerLength += Tlv::writeVarNumber(os, length);
103
104 char* buf = new char[length];
105 buf[0] = *tmp_begin;
106 is.read(buf+1, length-1);
107
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -0800108 if(length != static_cast<uint64_t>(is.gcount())+1)
Yingdi Yu27158392014-01-20 13:04:20 -0800109 {
110 delete [] buf;
111 throw Tlv::Error("Not enough data in the buffer to fully parse TLV");
112 }
113
114 os.write(buf, length);
115 delete [] buf;
116
117 m_buffer = os.buf();
118
119 m_begin = m_buffer->begin();
120 m_end = m_buffer->end();
121 m_size = m_end - m_begin;
122
123 m_value_begin = m_buffer->begin() + headerLength;
124 m_value_end = m_buffer->end();
125}
126
127
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800128Block::Block(const uint8_t *buffer, size_t maxlength)
129{
130 const uint8_t * tmp_begin = buffer;
131 const uint8_t * tmp_end = buffer + maxlength;
132
133 m_type = Tlv::readType(tmp_begin, tmp_end);
134 uint64_t length = Tlv::readVarNumber(tmp_begin, tmp_end);
135
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -0800136 if (length > static_cast<uint64_t>(tmp_end - tmp_begin))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800137 {
138 throw Tlv::Error("Not enough data in the buffer to fully parse TLV");
139 }
140
141 m_buffer = ptr_lib::make_shared<Buffer> (buffer, (tmp_begin - buffer) + length);
142
143 m_begin = m_buffer->begin();
144 m_end = m_buffer->end();
145 m_size = m_end - m_begin;
146
147 m_value_begin = m_buffer->begin() + (tmp_begin - buffer);
148 m_value_end = m_buffer->end();
149}
150
151Block::Block(const void *bufferX, size_t maxlength)
152{
153 const uint8_t * buffer = reinterpret_cast<const uint8_t*>(bufferX);
154
155 const uint8_t * tmp_begin = buffer;
156 const uint8_t * tmp_end = buffer + maxlength;
157
158 m_type = Tlv::readType(tmp_begin, tmp_end);
159 uint64_t length = Tlv::readVarNumber(tmp_begin, tmp_end);
160
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -0800161 if (length > static_cast<uint64_t>(tmp_end - tmp_begin))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800162 {
163 throw Tlv::Error("Not enough data in the buffer to fully parse TLV");
164 }
165
166 m_buffer = ptr_lib::make_shared<Buffer> (buffer, (tmp_begin - buffer) + length);
167
168 m_begin = m_buffer->begin();
169 m_end = m_buffer->end();
170 m_size = m_end - m_begin;
171
172 m_value_begin = m_buffer->begin() + (tmp_begin - buffer);
173 m_value_end = m_buffer->end();
174}
175
176Block::Block(uint32_t type)
177 : m_type(type)
178{
179}
180
181Block::Block(uint32_t type, const ConstBufferPtr &value)
182 : m_buffer(value)
183 , m_type(type)
184 , m_begin(m_buffer->end())
185 , m_end(m_buffer->end())
186 , m_value_begin(m_buffer->begin())
187 , m_value_end(m_buffer->end())
188{
189 m_size = Tlv::sizeOfVarNumber(m_type) + Tlv::sizeOfVarNumber(value_size()) + value_size();
190}
191
192Block::Block(uint32_t type, const Block &value)
193 : m_buffer(value.m_buffer)
194 , m_type(type)
195 , m_begin(m_buffer->end())
196 , m_end(m_buffer->end())
Alexander Afanasyevc8823bc2014-02-09 19:33:33 -0800197 , m_value_begin(value.begin())
198 , m_value_end(value.end())
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800199{
200 m_size = Tlv::sizeOfVarNumber(m_type) + Tlv::sizeOfVarNumber(value_size()) + value_size();
201}
202
203void
Alexander Afanasyev29e5c3d2014-02-11 00:01:10 -0800204Block::parse() const
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800205{
206 if (!m_subBlocks.empty() || value_size()==0)
207 return;
208
209 Buffer::const_iterator begin = value_begin(),
210 end = value_end();
211
212 while (begin != end)
213 {
214 Buffer::const_iterator element_begin = begin;
215
216 uint32_t type = Tlv::readType(begin, end);
217 uint64_t length = Tlv::readVarNumber(begin, end);
218
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -0800219 if (length > static_cast<uint64_t>(end - begin))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800220 {
221 m_subBlocks.clear();
222 throw Tlv::Error("TLV length exceeds buffer length");
223 }
224 Buffer::const_iterator element_end = begin + length;
225
226 m_subBlocks.push_back(Block(m_buffer,
227 type,
228 element_begin, element_end,
229 begin, element_end));
230
231 begin = element_end;
232 // don't do recursive parsing, just the top level
233 }
234}
235
236void
237Block::encode()
238{
239 if (hasWire())
240 return;
241
242 OBufferStream os;
243 Tlv::writeVarNumber(os, type());
244
245 if (hasValue())
246 {
247 Tlv::writeVarNumber(os, value_size());
248 os.write(reinterpret_cast<const char*>(value()), value_size());
249 }
Alexander Afanasyev8ea763d2014-02-06 20:32:52 -0800250 else if (m_subBlocks.size() == 0)
251 {
252 Tlv::writeVarNumber(os, 0);
253 }
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800254 else
255 {
256 size_t valueSize = 0;
257 for (element_const_iterator i = m_subBlocks.begin(); i != m_subBlocks.end(); ++i) {
258 valueSize += i->size();
259 }
260
261 Tlv::writeVarNumber(os, valueSize);
262
263 for (element_const_iterator i = m_subBlocks.begin(); i != m_subBlocks.end(); ++i) {
264 if (i->hasWire())
265 os.write(reinterpret_cast<const char*>(i->wire()), i->size());
266 else if (i->hasValue()) {
267 Tlv::writeVarNumber(os, i->type());
268 Tlv::writeVarNumber(os, i->value_size());
269 os.write(reinterpret_cast<const char*>(i->value()), i->value_size());
270 }
271 else
272 throw Error("Underlying value buffer is empty");
273 }
274 }
275
276 // now assign correct block
277
278 m_buffer = os.buf();
279 m_begin = m_buffer->begin();
280 m_end = m_buffer->end();
281 m_size = m_end - m_begin;
282
283 m_value_begin = m_buffer->begin();
284 m_value_end = m_buffer->end();
285
286 Tlv::readType(m_value_begin, m_value_end);
287 Tlv::readVarNumber(m_value_begin, m_value_end);
288}
289
Yingdi Yu4270f202014-01-28 14:19:16 -0800290Block
291Block::blockFromValue() const
292{
293 if (value_size()==0)
294 throw Error("Underlying value buffer is empty");
295
296 Buffer::const_iterator begin = value_begin(),
297 end = value_end();
298
299 Buffer::const_iterator element_begin = begin;
300
301 uint32_t type = Tlv::readType(begin, end);
302 uint64_t length = Tlv::readVarNumber(begin, end);
303
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -0800304 if (length != static_cast<uint64_t>(end - begin))
Yingdi Yu4270f202014-01-28 14:19:16 -0800305 throw Tlv::Error("TLV length mismatches buffer length");
306
307 return Block(m_buffer,
308 type,
309 element_begin, end,
310 begin, end);
311}
312
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800313} // namespace ndn