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