blob: 9c8ba1ef224e9d9a521f3ff1587810ab8d377532 [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 Afanasyev13bb51a2014-01-02 19:13:26 -080014
15namespace ndn {
16
17Block::Block()
18 : m_type(std::numeric_limits<uint32_t>::max())
19{
20}
21
22Block::Block(const ConstBufferPtr &wire,
23 uint32_t type,
Alexander Afanasyev187bc482014-02-06 15:04:04 -080024 const Buffer::const_iterator &begin, const Buffer::const_iterator &end,
25 const Buffer::const_iterator &valueBegin, const Buffer::const_iterator &valueEnd)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080026 : m_buffer(wire)
27 , m_type(type)
28 , m_begin(begin)
29 , m_end(end)
30 , m_size(m_end - m_begin)
31 , m_value_begin(valueBegin)
32 , m_value_end(valueEnd)
33{
34}
35
36Block::Block(const ConstBufferPtr &buffer)
37 : m_buffer(buffer)
38 , m_begin(m_buffer->begin())
39 , m_end(m_buffer->end())
40 , m_size(m_end - m_begin)
41{
42 m_value_begin = m_buffer->begin();
43 m_value_end = m_buffer->end();
44
45 m_type = Tlv::readType(m_value_begin, m_value_end);
46
47 uint64_t length = Tlv::readVarNumber(m_value_begin, m_value_end);
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -080048 if (length != static_cast<uint64_t>(m_value_end - m_value_begin))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080049 {
50 throw Tlv::Error("TLV length doesn't match buffer length");
51 }
52}
53
Alexander Afanasyev187bc482014-02-06 15:04:04 -080054Block::Block(const ConstBufferPtr &buffer,
55 const Buffer::const_iterator &begin, const Buffer::const_iterator &end)
56 : m_buffer(buffer)
57 , m_begin(begin)
58 , m_end(end)
Alexander Afanasyev380420b2014-02-09 20:52:29 -080059 , m_size(m_end - m_begin)
Alexander Afanasyev187bc482014-02-06 15:04:04 -080060{
61 m_value_begin = m_buffer->begin();
62 m_value_end = m_buffer->end();
Alexander Afanasyev380420b2014-02-09 20:52:29 -080063
Alexander Afanasyev187bc482014-02-06 15:04:04 -080064 m_type = Tlv::readType(m_value_begin, m_value_end);
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 Afanasyev187bc482014-02-06 15:04:04 -080067 {
68 throw Tlv::Error("TLV length doesn't match buffer length");
69 }
70}
71
Yingdi Yu27158392014-01-20 13:04:20 -080072Block::Block(std::istream& is)
73{
74 std::istream_iterator<uint8_t> tmp_begin(is);
75 std::istream_iterator<uint8_t> tmp_end;
76
77 m_type = Tlv::readType(tmp_begin, tmp_end);
78 uint64_t length = Tlv::readVarNumber(tmp_begin, tmp_end);
79
80 // 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.
81
82 OBufferStream os;
83 size_t headerLength = Tlv::writeVarNumber(os, m_type);
84 headerLength += Tlv::writeVarNumber(os, length);
85
86 char* buf = new char[length];
87 buf[0] = *tmp_begin;
88 is.read(buf+1, length-1);
89
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -080090 if(length != static_cast<uint64_t>(is.gcount())+1)
Yingdi Yu27158392014-01-20 13:04:20 -080091 {
92 delete [] buf;
93 throw Tlv::Error("Not enough data in the buffer to fully parse TLV");
94 }
95
96 os.write(buf, length);
97 delete [] buf;
98
99 m_buffer = os.buf();
100
101 m_begin = m_buffer->begin();
102 m_end = m_buffer->end();
103 m_size = m_end - m_begin;
104
105 m_value_begin = m_buffer->begin() + headerLength;
106 m_value_end = m_buffer->end();
107}
108
109
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800110Block::Block(const uint8_t *buffer, size_t maxlength)
111{
112 const uint8_t * tmp_begin = buffer;
113 const uint8_t * tmp_end = buffer + maxlength;
114
115 m_type = Tlv::readType(tmp_begin, tmp_end);
116 uint64_t length = Tlv::readVarNumber(tmp_begin, tmp_end);
117
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -0800118 if (length > static_cast<uint64_t>(tmp_end - tmp_begin))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800119 {
120 throw Tlv::Error("Not enough data in the buffer to fully parse TLV");
121 }
122
123 m_buffer = ptr_lib::make_shared<Buffer> (buffer, (tmp_begin - buffer) + length);
124
125 m_begin = m_buffer->begin();
126 m_end = m_buffer->end();
127 m_size = m_end - m_begin;
128
129 m_value_begin = m_buffer->begin() + (tmp_begin - buffer);
130 m_value_end = m_buffer->end();
131}
132
133Block::Block(const void *bufferX, size_t maxlength)
134{
135 const uint8_t * buffer = reinterpret_cast<const uint8_t*>(bufferX);
136
137 const uint8_t * tmp_begin = buffer;
138 const uint8_t * tmp_end = buffer + maxlength;
139
140 m_type = Tlv::readType(tmp_begin, tmp_end);
141 uint64_t length = Tlv::readVarNumber(tmp_begin, tmp_end);
142
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -0800143 if (length > static_cast<uint64_t>(tmp_end - tmp_begin))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800144 {
145 throw Tlv::Error("Not enough data in the buffer to fully parse TLV");
146 }
147
148 m_buffer = ptr_lib::make_shared<Buffer> (buffer, (tmp_begin - buffer) + length);
149
150 m_begin = m_buffer->begin();
151 m_end = m_buffer->end();
152 m_size = m_end - m_begin;
153
154 m_value_begin = m_buffer->begin() + (tmp_begin - buffer);
155 m_value_end = m_buffer->end();
156}
157
158Block::Block(uint32_t type)
159 : m_type(type)
160{
161}
162
163Block::Block(uint32_t type, const ConstBufferPtr &value)
164 : m_buffer(value)
165 , m_type(type)
166 , m_begin(m_buffer->end())
167 , m_end(m_buffer->end())
168 , m_value_begin(m_buffer->begin())
169 , m_value_end(m_buffer->end())
170{
171 m_size = Tlv::sizeOfVarNumber(m_type) + Tlv::sizeOfVarNumber(value_size()) + value_size();
172}
173
174Block::Block(uint32_t type, const Block &value)
175 : m_buffer(value.m_buffer)
176 , m_type(type)
177 , m_begin(m_buffer->end())
178 , m_end(m_buffer->end())
Alexander Afanasyevc8823bc2014-02-09 19:33:33 -0800179 , m_value_begin(value.begin())
180 , m_value_end(value.end())
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800181{
182 m_size = Tlv::sizeOfVarNumber(m_type) + Tlv::sizeOfVarNumber(value_size()) + value_size();
183}
184
185void
Alexander Afanasyev29e5c3d2014-02-11 00:01:10 -0800186Block::parse() const
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800187{
188 if (!m_subBlocks.empty() || value_size()==0)
189 return;
190
191 Buffer::const_iterator begin = value_begin(),
192 end = value_end();
193
194 while (begin != end)
195 {
196 Buffer::const_iterator element_begin = begin;
197
198 uint32_t type = Tlv::readType(begin, end);
199 uint64_t length = Tlv::readVarNumber(begin, end);
200
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -0800201 if (length > static_cast<uint64_t>(end - begin))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800202 {
203 m_subBlocks.clear();
204 throw Tlv::Error("TLV length exceeds buffer length");
205 }
206 Buffer::const_iterator element_end = begin + length;
207
208 m_subBlocks.push_back(Block(m_buffer,
209 type,
210 element_begin, element_end,
211 begin, element_end));
212
213 begin = element_end;
214 // don't do recursive parsing, just the top level
215 }
216}
217
218void
219Block::encode()
220{
221 if (hasWire())
222 return;
223
224 OBufferStream os;
225 Tlv::writeVarNumber(os, type());
226
227 if (hasValue())
228 {
229 Tlv::writeVarNumber(os, value_size());
230 os.write(reinterpret_cast<const char*>(value()), value_size());
231 }
Alexander Afanasyev8ea763d2014-02-06 20:32:52 -0800232 else if (m_subBlocks.size() == 0)
233 {
234 Tlv::writeVarNumber(os, 0);
235 }
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800236 else
237 {
238 size_t valueSize = 0;
239 for (element_const_iterator i = m_subBlocks.begin(); i != m_subBlocks.end(); ++i) {
240 valueSize += i->size();
241 }
242
243 Tlv::writeVarNumber(os, valueSize);
244
245 for (element_const_iterator i = m_subBlocks.begin(); i != m_subBlocks.end(); ++i) {
246 if (i->hasWire())
247 os.write(reinterpret_cast<const char*>(i->wire()), i->size());
248 else if (i->hasValue()) {
249 Tlv::writeVarNumber(os, i->type());
250 Tlv::writeVarNumber(os, i->value_size());
251 os.write(reinterpret_cast<const char*>(i->value()), i->value_size());
252 }
253 else
254 throw Error("Underlying value buffer is empty");
255 }
256 }
257
258 // now assign correct block
259
260 m_buffer = os.buf();
261 m_begin = m_buffer->begin();
262 m_end = m_buffer->end();
263 m_size = m_end - m_begin;
264
265 m_value_begin = m_buffer->begin();
266 m_value_end = m_buffer->end();
267
268 Tlv::readType(m_value_begin, m_value_end);
269 Tlv::readVarNumber(m_value_begin, m_value_end);
270}
271
Yingdi Yu4270f202014-01-28 14:19:16 -0800272Block
273Block::blockFromValue() const
274{
275 if (value_size()==0)
276 throw Error("Underlying value buffer is empty");
277
278 Buffer::const_iterator begin = value_begin(),
279 end = value_end();
280
281 Buffer::const_iterator element_begin = begin;
282
283 uint32_t type = Tlv::readType(begin, end);
284 uint64_t length = Tlv::readVarNumber(begin, end);
285
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -0800286 if (length != static_cast<uint64_t>(end - begin))
Yingdi Yu4270f202014-01-28 14:19:16 -0800287 throw Tlv::Error("TLV length mismatches buffer length");
288
289 return Block(m_buffer,
290 type,
291 element_begin, end,
292 begin, end);
293}
294
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800295} // namespace ndn