blob: fbd5838880ce1d361323de8b41b69e3bc765790c [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)
59{
60 m_value_begin = m_buffer->begin();
61 m_value_end = m_buffer->end();
62
63 m_type = Tlv::readType(m_value_begin, m_value_end);
64 uint64_t length = Tlv::readVarNumber(m_value_begin, m_value_end);
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -080065 if (length != static_cast<uint64_t>(m_value_end - m_value_begin))
Alexander Afanasyev187bc482014-02-06 15:04:04 -080066 {
67 throw Tlv::Error("TLV length doesn't match buffer length");
68 }
69}
70
Yingdi Yu27158392014-01-20 13:04:20 -080071Block::Block(std::istream& is)
72{
73 std::istream_iterator<uint8_t> tmp_begin(is);
74 std::istream_iterator<uint8_t> tmp_end;
75
76 m_type = Tlv::readType(tmp_begin, tmp_end);
77 uint64_t length = Tlv::readVarNumber(tmp_begin, tmp_end);
78
79 // 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.
80
81 OBufferStream os;
82 size_t headerLength = Tlv::writeVarNumber(os, m_type);
83 headerLength += Tlv::writeVarNumber(os, length);
84
85 char* buf = new char[length];
86 buf[0] = *tmp_begin;
87 is.read(buf+1, length-1);
88
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -080089 if(length != static_cast<uint64_t>(is.gcount())+1)
Yingdi Yu27158392014-01-20 13:04:20 -080090 {
91 delete [] buf;
92 throw Tlv::Error("Not enough data in the buffer to fully parse TLV");
93 }
94
95 os.write(buf, length);
96 delete [] buf;
97
98 m_buffer = os.buf();
99
100 m_begin = m_buffer->begin();
101 m_end = m_buffer->end();
102 m_size = m_end - m_begin;
103
104 m_value_begin = m_buffer->begin() + headerLength;
105 m_value_end = m_buffer->end();
106}
107
108
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800109Block::Block(const uint8_t *buffer, size_t maxlength)
110{
111 const uint8_t * tmp_begin = buffer;
112 const uint8_t * tmp_end = buffer + maxlength;
113
114 m_type = Tlv::readType(tmp_begin, tmp_end);
115 uint64_t length = Tlv::readVarNumber(tmp_begin, tmp_end);
116
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -0800117 if (length > static_cast<uint64_t>(tmp_end - tmp_begin))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800118 {
119 throw Tlv::Error("Not enough data in the buffer to fully parse TLV");
120 }
121
122 m_buffer = ptr_lib::make_shared<Buffer> (buffer, (tmp_begin - buffer) + length);
123
124 m_begin = m_buffer->begin();
125 m_end = m_buffer->end();
126 m_size = m_end - m_begin;
127
128 m_value_begin = m_buffer->begin() + (tmp_begin - buffer);
129 m_value_end = m_buffer->end();
130}
131
132Block::Block(const void *bufferX, size_t maxlength)
133{
134 const uint8_t * buffer = reinterpret_cast<const uint8_t*>(bufferX);
135
136 const uint8_t * tmp_begin = buffer;
137 const uint8_t * tmp_end = buffer + maxlength;
138
139 m_type = Tlv::readType(tmp_begin, tmp_end);
140 uint64_t length = Tlv::readVarNumber(tmp_begin, tmp_end);
141
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -0800142 if (length > static_cast<uint64_t>(tmp_end - tmp_begin))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800143 {
144 throw Tlv::Error("Not enough data in the buffer to fully parse TLV");
145 }
146
147 m_buffer = ptr_lib::make_shared<Buffer> (buffer, (tmp_begin - buffer) + length);
148
149 m_begin = m_buffer->begin();
150 m_end = m_buffer->end();
151 m_size = m_end - m_begin;
152
153 m_value_begin = m_buffer->begin() + (tmp_begin - buffer);
154 m_value_end = m_buffer->end();
155}
156
157Block::Block(uint32_t type)
158 : m_type(type)
159{
160}
161
162Block::Block(uint32_t type, const ConstBufferPtr &value)
163 : m_buffer(value)
164 , m_type(type)
165 , m_begin(m_buffer->end())
166 , m_end(m_buffer->end())
167 , m_value_begin(m_buffer->begin())
168 , m_value_end(m_buffer->end())
169{
170 m_size = Tlv::sizeOfVarNumber(m_type) + Tlv::sizeOfVarNumber(value_size()) + value_size();
171}
172
173Block::Block(uint32_t type, const Block &value)
174 : m_buffer(value.m_buffer)
175 , m_type(type)
176 , m_begin(m_buffer->end())
177 , m_end(m_buffer->end())
178 , m_value_begin(m_buffer->begin())
179 , m_value_end(m_buffer->end())
180{
181 m_size = Tlv::sizeOfVarNumber(m_type) + Tlv::sizeOfVarNumber(value_size()) + value_size();
182}
183
184void
185Block::parse()
186{
187 if (!m_subBlocks.empty() || value_size()==0)
188 return;
189
190 Buffer::const_iterator begin = value_begin(),
191 end = value_end();
192
193 while (begin != end)
194 {
195 Buffer::const_iterator element_begin = begin;
196
197 uint32_t type = Tlv::readType(begin, end);
198 uint64_t length = Tlv::readVarNumber(begin, end);
199
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -0800200 if (length > static_cast<uint64_t>(end - begin))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800201 {
202 m_subBlocks.clear();
203 throw Tlv::Error("TLV length exceeds buffer length");
204 }
205 Buffer::const_iterator element_end = begin + length;
206
207 m_subBlocks.push_back(Block(m_buffer,
208 type,
209 element_begin, element_end,
210 begin, element_end));
211
212 begin = element_end;
213 // don't do recursive parsing, just the top level
214 }
215}
216
217void
218Block::encode()
219{
220 if (hasWire())
221 return;
222
223 OBufferStream os;
224 Tlv::writeVarNumber(os, type());
225
226 if (hasValue())
227 {
228 Tlv::writeVarNumber(os, value_size());
229 os.write(reinterpret_cast<const char*>(value()), value_size());
230 }
Alexander Afanasyev8ea763d2014-02-06 20:32:52 -0800231 else if (m_subBlocks.size() == 0)
232 {
233 Tlv::writeVarNumber(os, 0);
234 }
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800235 else
236 {
237 size_t valueSize = 0;
238 for (element_const_iterator i = m_subBlocks.begin(); i != m_subBlocks.end(); ++i) {
239 valueSize += i->size();
240 }
241
242 Tlv::writeVarNumber(os, valueSize);
243
244 for (element_const_iterator i = m_subBlocks.begin(); i != m_subBlocks.end(); ++i) {
245 if (i->hasWire())
246 os.write(reinterpret_cast<const char*>(i->wire()), i->size());
247 else if (i->hasValue()) {
248 Tlv::writeVarNumber(os, i->type());
249 Tlv::writeVarNumber(os, i->value_size());
250 os.write(reinterpret_cast<const char*>(i->value()), i->value_size());
251 }
252 else
253 throw Error("Underlying value buffer is empty");
254 }
255 }
256
257 // now assign correct block
258
259 m_buffer = os.buf();
260 m_begin = m_buffer->begin();
261 m_end = m_buffer->end();
262 m_size = m_end - m_begin;
263
264 m_value_begin = m_buffer->begin();
265 m_value_end = m_buffer->end();
266
267 Tlv::readType(m_value_begin, m_value_end);
268 Tlv::readVarNumber(m_value_begin, m_value_end);
269}
270
Yingdi Yu4270f202014-01-28 14:19:16 -0800271Block
272Block::blockFromValue() const
273{
274 if (value_size()==0)
275 throw Error("Underlying value buffer is empty");
276
277 Buffer::const_iterator begin = value_begin(),
278 end = value_end();
279
280 Buffer::const_iterator element_begin = begin;
281
282 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))
Yingdi Yu4270f202014-01-28 14:19:16 -0800286 throw Tlv::Error("TLV length mismatches buffer length");
287
288 return Block(m_buffer,
289 type,
290 element_begin, end,
291 begin, end);
292}
293
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800294} // namespace ndn