blob: c19cee7a8116d3a4cbb9ce9721d46af772083d30 [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
10#include <ndn-cpp/encoding/block.hpp>
11#include <ndn-cpp/encoding/tlv.hpp>
12
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
52Block::Block(const uint8_t *buffer, size_t maxlength)
53{
54 const uint8_t * tmp_begin = buffer;
55 const uint8_t * tmp_end = buffer + maxlength;
56
57 m_type = Tlv::readType(tmp_begin, tmp_end);
58 uint64_t length = Tlv::readVarNumber(tmp_begin, tmp_end);
59
60 if (length > (tmp_end - tmp_begin))
61 {
62 throw Tlv::Error("Not enough data in the buffer to fully parse TLV");
63 }
64
65 m_buffer = ptr_lib::make_shared<Buffer> (buffer, (tmp_begin - buffer) + length);
66
67 m_begin = m_buffer->begin();
68 m_end = m_buffer->end();
69 m_size = m_end - m_begin;
70
71 m_value_begin = m_buffer->begin() + (tmp_begin - buffer);
72 m_value_end = m_buffer->end();
73}
74
75Block::Block(const void *bufferX, size_t maxlength)
76{
77 const uint8_t * buffer = reinterpret_cast<const uint8_t*>(bufferX);
78
79 const uint8_t * tmp_begin = buffer;
80 const uint8_t * tmp_end = buffer + maxlength;
81
82 m_type = Tlv::readType(tmp_begin, tmp_end);
83 uint64_t length = Tlv::readVarNumber(tmp_begin, tmp_end);
84
85 if (length > (tmp_end - tmp_begin))
86 {
87 throw Tlv::Error("Not enough data in the buffer to fully parse TLV");
88 }
89
90 m_buffer = ptr_lib::make_shared<Buffer> (buffer, (tmp_begin - buffer) + length);
91
92 m_begin = m_buffer->begin();
93 m_end = m_buffer->end();
94 m_size = m_end - m_begin;
95
96 m_value_begin = m_buffer->begin() + (tmp_begin - buffer);
97 m_value_end = m_buffer->end();
98}
99
100Block::Block(uint32_t type)
101 : m_type(type)
102{
103}
104
105Block::Block(uint32_t type, const ConstBufferPtr &value)
106 : m_buffer(value)
107 , m_type(type)
108 , m_begin(m_buffer->end())
109 , m_end(m_buffer->end())
110 , m_value_begin(m_buffer->begin())
111 , m_value_end(m_buffer->end())
112{
113 m_size = Tlv::sizeOfVarNumber(m_type) + Tlv::sizeOfVarNumber(value_size()) + value_size();
114}
115
116Block::Block(uint32_t type, const Block &value)
117 : m_buffer(value.m_buffer)
118 , m_type(type)
119 , m_begin(m_buffer->end())
120 , m_end(m_buffer->end())
121 , m_value_begin(m_buffer->begin())
122 , m_value_end(m_buffer->end())
123{
124 m_size = Tlv::sizeOfVarNumber(m_type) + Tlv::sizeOfVarNumber(value_size()) + value_size();
125}
126
127void
128Block::parse()
129{
130 if (!m_subBlocks.empty() || value_size()==0)
131 return;
132
133 Buffer::const_iterator begin = value_begin(),
134 end = value_end();
135
136 while (begin != end)
137 {
138 Buffer::const_iterator element_begin = begin;
139
140 uint32_t type = Tlv::readType(begin, end);
141 uint64_t length = Tlv::readVarNumber(begin, end);
142
143 if (end-begin < length)
144 {
145 m_subBlocks.clear();
146 throw Tlv::Error("TLV length exceeds buffer length");
147 }
148 Buffer::const_iterator element_end = begin + length;
149
150 m_subBlocks.push_back(Block(m_buffer,
151 type,
152 element_begin, element_end,
153 begin, element_end));
154
155 begin = element_end;
156 // don't do recursive parsing, just the top level
157 }
158}
159
160void
161Block::encode()
162{
163 if (hasWire())
164 return;
165
166 OBufferStream os;
167 Tlv::writeVarNumber(os, type());
168
169 if (hasValue())
170 {
171 Tlv::writeVarNumber(os, value_size());
172 os.write(reinterpret_cast<const char*>(value()), value_size());
173 }
174 else
175 {
176 size_t valueSize = 0;
177 for (element_const_iterator i = m_subBlocks.begin(); i != m_subBlocks.end(); ++i) {
178 valueSize += i->size();
179 }
180
181 Tlv::writeVarNumber(os, valueSize);
182
183 for (element_const_iterator i = m_subBlocks.begin(); i != m_subBlocks.end(); ++i) {
184 if (i->hasWire())
185 os.write(reinterpret_cast<const char*>(i->wire()), i->size());
186 else if (i->hasValue()) {
187 Tlv::writeVarNumber(os, i->type());
188 Tlv::writeVarNumber(os, i->value_size());
189 os.write(reinterpret_cast<const char*>(i->value()), i->value_size());
190 }
191 else
192 throw Error("Underlying value buffer is empty");
193 }
194 }
195
196 // now assign correct block
197
198 m_buffer = os.buf();
199 m_begin = m_buffer->begin();
200 m_end = m_buffer->end();
201 m_size = m_end - m_begin;
202
203 m_value_begin = m_buffer->begin();
204 m_value_end = m_buffer->end();
205
206 Tlv::readType(m_value_begin, m_value_end);
207 Tlv::readVarNumber(m_value_begin, m_value_end);
208}
209
210} // namespace ndn