blob: 5656b61780ed1c9bc55ebc71e57c5d8684cfde89 [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 Afanasyev09c613f2014-01-29 00:23:58 -080010#include "encoding/block.hpp"
11#include "encoding/tlv.hpp"
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080012
13namespace ndn {
14
15Block::Block()
16 : m_type(std::numeric_limits<uint32_t>::max())
17{
18}
19
20Block::Block(const ConstBufferPtr &wire,
21 uint32_t type,
Alexander Afanasyev187bc482014-02-06 15:04:04 -080022 const Buffer::const_iterator &begin, const Buffer::const_iterator &end,
23 const Buffer::const_iterator &valueBegin, const Buffer::const_iterator &valueEnd)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080024 : m_buffer(wire)
25 , m_type(type)
26 , m_begin(begin)
27 , m_end(end)
28 , m_size(m_end - m_begin)
29 , m_value_begin(valueBegin)
30 , m_value_end(valueEnd)
31{
32}
33
34Block::Block(const ConstBufferPtr &buffer)
35 : m_buffer(buffer)
36 , m_begin(m_buffer->begin())
37 , m_end(m_buffer->end())
38 , m_size(m_end - m_begin)
39{
40 m_value_begin = m_buffer->begin();
41 m_value_end = m_buffer->end();
42
43 m_type = Tlv::readType(m_value_begin, m_value_end);
44
45 uint64_t length = Tlv::readVarNumber(m_value_begin, m_value_end);
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -080046 if (length != static_cast<uint64_t>(m_value_end - m_value_begin))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080047 {
48 throw Tlv::Error("TLV length doesn't match buffer length");
49 }
50}
51
Alexander Afanasyev187bc482014-02-06 15:04:04 -080052Block::Block(const ConstBufferPtr &buffer,
53 const Buffer::const_iterator &begin, const Buffer::const_iterator &end)
54 : m_buffer(buffer)
55 , m_begin(begin)
56 , m_end(end)
57{
58 m_value_begin = m_buffer->begin();
59 m_value_end = m_buffer->end();
60
61 m_type = Tlv::readType(m_value_begin, m_value_end);
62 uint64_t length = Tlv::readVarNumber(m_value_begin, m_value_end);
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -080063 if (length != static_cast<uint64_t>(m_value_end - m_value_begin))
Alexander Afanasyev187bc482014-02-06 15:04:04 -080064 {
65 throw Tlv::Error("TLV length doesn't match buffer length");
66 }
67}
68
Yingdi Yu27158392014-01-20 13:04:20 -080069Block::Block(std::istream& is)
70{
71 std::istream_iterator<uint8_t> tmp_begin(is);
72 std::istream_iterator<uint8_t> tmp_end;
73
74 m_type = Tlv::readType(tmp_begin, tmp_end);
75 uint64_t length = Tlv::readVarNumber(tmp_begin, tmp_end);
76
77 // 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.
78
79 OBufferStream os;
80 size_t headerLength = Tlv::writeVarNumber(os, m_type);
81 headerLength += Tlv::writeVarNumber(os, length);
82
83 char* buf = new char[length];
84 buf[0] = *tmp_begin;
85 is.read(buf+1, length-1);
86
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -080087 if(length != static_cast<uint64_t>(is.gcount())+1)
Yingdi Yu27158392014-01-20 13:04:20 -080088 {
89 delete [] buf;
90 throw Tlv::Error("Not enough data in the buffer to fully parse TLV");
91 }
92
93 os.write(buf, length);
94 delete [] buf;
95
96 m_buffer = os.buf();
97
98 m_begin = m_buffer->begin();
99 m_end = m_buffer->end();
100 m_size = m_end - m_begin;
101
102 m_value_begin = m_buffer->begin() + headerLength;
103 m_value_end = m_buffer->end();
104}
105
106
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800107Block::Block(const uint8_t *buffer, size_t maxlength)
108{
109 const uint8_t * tmp_begin = buffer;
110 const uint8_t * tmp_end = buffer + maxlength;
111
112 m_type = Tlv::readType(tmp_begin, tmp_end);
113 uint64_t length = Tlv::readVarNumber(tmp_begin, tmp_end);
114
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -0800115 if (length > static_cast<uint64_t>(tmp_end - tmp_begin))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800116 {
117 throw Tlv::Error("Not enough data in the buffer to fully parse TLV");
118 }
119
120 m_buffer = ptr_lib::make_shared<Buffer> (buffer, (tmp_begin - buffer) + length);
121
122 m_begin = m_buffer->begin();
123 m_end = m_buffer->end();
124 m_size = m_end - m_begin;
125
126 m_value_begin = m_buffer->begin() + (tmp_begin - buffer);
127 m_value_end = m_buffer->end();
128}
129
130Block::Block(const void *bufferX, size_t maxlength)
131{
132 const uint8_t * buffer = reinterpret_cast<const uint8_t*>(bufferX);
133
134 const uint8_t * tmp_begin = buffer;
135 const uint8_t * tmp_end = buffer + maxlength;
136
137 m_type = Tlv::readType(tmp_begin, tmp_end);
138 uint64_t length = Tlv::readVarNumber(tmp_begin, tmp_end);
139
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -0800140 if (length > static_cast<uint64_t>(tmp_end - tmp_begin))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800141 {
142 throw Tlv::Error("Not enough data in the buffer to fully parse TLV");
143 }
144
145 m_buffer = ptr_lib::make_shared<Buffer> (buffer, (tmp_begin - buffer) + length);
146
147 m_begin = m_buffer->begin();
148 m_end = m_buffer->end();
149 m_size = m_end - m_begin;
150
151 m_value_begin = m_buffer->begin() + (tmp_begin - buffer);
152 m_value_end = m_buffer->end();
153}
154
155Block::Block(uint32_t type)
156 : m_type(type)
157{
158}
159
160Block::Block(uint32_t type, const ConstBufferPtr &value)
161 : m_buffer(value)
162 , m_type(type)
163 , m_begin(m_buffer->end())
164 , m_end(m_buffer->end())
165 , m_value_begin(m_buffer->begin())
166 , m_value_end(m_buffer->end())
167{
168 m_size = Tlv::sizeOfVarNumber(m_type) + Tlv::sizeOfVarNumber(value_size()) + value_size();
169}
170
171Block::Block(uint32_t type, const Block &value)
172 : m_buffer(value.m_buffer)
173 , m_type(type)
174 , m_begin(m_buffer->end())
175 , m_end(m_buffer->end())
176 , m_value_begin(m_buffer->begin())
177 , m_value_end(m_buffer->end())
178{
179 m_size = Tlv::sizeOfVarNumber(m_type) + Tlv::sizeOfVarNumber(value_size()) + value_size();
180}
181
182void
183Block::parse()
184{
185 if (!m_subBlocks.empty() || value_size()==0)
186 return;
187
188 Buffer::const_iterator begin = value_begin(),
189 end = value_end();
190
191 while (begin != end)
192 {
193 Buffer::const_iterator element_begin = begin;
194
195 uint32_t type = Tlv::readType(begin, end);
196 uint64_t length = Tlv::readVarNumber(begin, end);
197
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -0800198 if (length > static_cast<uint64_t>(end - begin))
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800199 {
200 m_subBlocks.clear();
201 throw Tlv::Error("TLV length exceeds buffer length");
202 }
203 Buffer::const_iterator element_end = begin + length;
204
205 m_subBlocks.push_back(Block(m_buffer,
206 type,
207 element_begin, element_end,
208 begin, element_end));
209
210 begin = element_end;
211 // don't do recursive parsing, just the top level
212 }
213}
214
215void
216Block::encode()
217{
218 if (hasWire())
219 return;
220
221 OBufferStream os;
222 Tlv::writeVarNumber(os, type());
223
224 if (hasValue())
225 {
226 Tlv::writeVarNumber(os, value_size());
227 os.write(reinterpret_cast<const char*>(value()), value_size());
228 }
Alexander Afanasyev8ea763d2014-02-06 20:32:52 -0800229 else if (m_subBlocks.size() == 0)
230 {
231 Tlv::writeVarNumber(os, 0);
232 }
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800233 else
234 {
235 size_t valueSize = 0;
236 for (element_const_iterator i = m_subBlocks.begin(); i != m_subBlocks.end(); ++i) {
237 valueSize += i->size();
238 }
239
240 Tlv::writeVarNumber(os, valueSize);
241
242 for (element_const_iterator i = m_subBlocks.begin(); i != m_subBlocks.end(); ++i) {
243 if (i->hasWire())
244 os.write(reinterpret_cast<const char*>(i->wire()), i->size());
245 else if (i->hasValue()) {
246 Tlv::writeVarNumber(os, i->type());
247 Tlv::writeVarNumber(os, i->value_size());
248 os.write(reinterpret_cast<const char*>(i->value()), i->value_size());
249 }
250 else
251 throw Error("Underlying value buffer is empty");
252 }
253 }
254
255 // now assign correct block
256
257 m_buffer = os.buf();
258 m_begin = m_buffer->begin();
259 m_end = m_buffer->end();
260 m_size = m_end - m_begin;
261
262 m_value_begin = m_buffer->begin();
263 m_value_end = m_buffer->end();
264
265 Tlv::readType(m_value_begin, m_value_end);
266 Tlv::readVarNumber(m_value_begin, m_value_end);
267}
268
Yingdi Yu4270f202014-01-28 14:19:16 -0800269Block
270Block::blockFromValue() const
271{
272 if (value_size()==0)
273 throw Error("Underlying value buffer is empty");
274
275 Buffer::const_iterator begin = value_begin(),
276 end = value_end();
277
278 Buffer::const_iterator element_begin = begin;
279
280 uint32_t type = Tlv::readType(begin, end);
281 uint64_t length = Tlv::readVarNumber(begin, end);
282
Alexander Afanasyev9c7ed112014-02-07 12:23:03 -0800283 if (length != static_cast<uint64_t>(end - begin))
Yingdi Yu4270f202014-01-28 14:19:16 -0800284 throw Tlv::Error("TLV length mismatches buffer length");
285
286 return Block(m_buffer,
287 type,
288 element_begin, end,
289 begin, end);
290}
291
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800292} // namespace ndn