blob: 1fdddecaf54a7e6b59e9b0c8209efc153055089e [file] [log] [blame]
Alexander Afanasyev74633892015-02-08 18:08:46 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesavento14883ad2018-07-14 16:31:39 -04002/*
3 * Copyright (c) 2013-2018 Regents of the University of California.
Alexander Afanasyev74633892015-02-08 18:08:46 -08004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20 */
21
22#include "encoder.hpp"
23
Davide Pesavento14883ad2018-07-14 16:31:39 -040024#include <boost/endian/conversion.hpp>
25
Alexander Afanasyev74633892015-02-08 18:08:46 -080026namespace ndn {
27namespace encoding {
28
Davide Pesavento14883ad2018-07-14 16:31:39 -040029namespace endian = boost::endian;
30
31Encoder::Encoder(size_t totalReserve, size_t reserveFromBack)
32 : m_buffer(make_shared<Buffer>(totalReserve))
Alexander Afanasyev74633892015-02-08 18:08:46 -080033{
34 m_begin = m_end = m_buffer->end() - (reserveFromBack < totalReserve ? reserveFromBack : 0);
35}
36
Alexander Afanasyev74633892015-02-08 18:08:46 -080037Encoder::Encoder(const Block& block)
38 : m_buffer(const_pointer_cast<Buffer>(block.getBuffer()))
39 , m_begin(m_buffer->begin() + (block.begin() - m_buffer->begin()))
40 , m_end(m_buffer->begin() + (block.end() - m_buffer->begin()))
41{
42}
43
Alexander Afanasyev74633892015-02-08 18:08:46 -080044void
45Encoder::reserveBack(size_t size)
46{
Davide Pesavento14883ad2018-07-14 16:31:39 -040047 if (m_end + size > m_buffer->end())
Alexander Afanasyev74633892015-02-08 18:08:46 -080048 reserve(m_buffer->size() * 2 + size, false);
49}
50
51void
52Encoder::reserveFront(size_t size)
53{
Davide Pesavento14883ad2018-07-14 16:31:39 -040054 if (m_buffer->begin() + size > m_begin)
Alexander Afanasyev74633892015-02-08 18:08:46 -080055 reserve(m_buffer->size() * 2 + size, true);
56}
57
Alexander Afanasyev74633892015-02-08 18:08:46 -080058Block
Davide Pesavento14883ad2018-07-14 16:31:39 -040059Encoder::block(bool verifyLength) const
Alexander Afanasyev74633892015-02-08 18:08:46 -080060{
Davide Pesavento14883ad2018-07-14 16:31:39 -040061 return Block(m_buffer, m_begin, m_end, verifyLength);
Alexander Afanasyev74633892015-02-08 18:08:46 -080062}
63
64void
65Encoder::reserve(size_t size, bool addInFront)
66{
67 if (size < m_buffer->size()) {
68 size = m_buffer->size();
69 }
70
71 if (addInFront) {
72 size_t diffEnd = m_buffer->end() - m_end;
73 size_t diffBegin = m_buffer->end() - m_begin;
74
75 Buffer* buf = new Buffer(size);
76 std::copy_backward(m_buffer->begin(), m_buffer->end(), buf->end());
77
78 m_buffer.reset(buf);
79
80 m_end = m_buffer->end() - diffEnd;
81 m_begin = m_buffer->end() - diffBegin;
82 }
83 else {
84 size_t diffEnd = m_end - m_buffer->begin();
85 size_t diffBegin = m_begin - m_buffer->begin();
86
87 Buffer* buf = new Buffer(size);
88 std::copy(m_buffer->begin(), m_buffer->end(), buf->begin());
89
90 m_buffer.reset(buf);
91
92 m_end = m_buffer->begin() + diffEnd;
93 m_begin = m_buffer->begin() + diffBegin;
94 }
95}
96
Alexander Afanasyev74633892015-02-08 18:08:46 -080097size_t
98Encoder::prependByte(uint8_t value)
99{
100 reserveFront(1);
101
102 m_begin--;
103 *m_begin = value;
104 return 1;
105}
106
107size_t
108Encoder::appendByte(uint8_t value)
109{
110 reserveBack(1);
111
112 *m_end = value;
113 m_end++;
114 return 1;
115}
116
Alexander Afanasyev74633892015-02-08 18:08:46 -0800117size_t
118Encoder::prependByteArray(const uint8_t* array, size_t length)
119{
120 reserveFront(length);
121
122 m_begin -= length;
123 std::copy(array, array + length, m_begin);
124 return length;
125}
126
127size_t
128Encoder::appendByteArray(const uint8_t* array, size_t length)
129{
130 reserveBack(length);
131
132 std::copy(array, array + length, m_end);
133 m_end += length;
134 return length;
135}
136
Alexander Afanasyev74633892015-02-08 18:08:46 -0800137size_t
138Encoder::prependVarNumber(uint64_t varNumber)
139{
140 if (varNumber < 253) {
141 prependByte(static_cast<uint8_t>(varNumber));
142 return 1;
143 }
144 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento14883ad2018-07-14 16:31:39 -0400145 uint16_t value = endian::native_to_big(static_cast<uint16_t>(varNumber));
Alexander Afanasyev74633892015-02-08 18:08:46 -0800146 prependByteArray(reinterpret_cast<const uint8_t*>(&value), 2);
147 prependByte(253);
148 return 3;
149 }
150 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento14883ad2018-07-14 16:31:39 -0400151 uint32_t value = endian::native_to_big(static_cast<uint32_t>(varNumber));
Alexander Afanasyev74633892015-02-08 18:08:46 -0800152 prependByteArray(reinterpret_cast<const uint8_t*>(&value), 4);
153 prependByte(254);
154 return 5;
155 }
156 else {
Davide Pesavento14883ad2018-07-14 16:31:39 -0400157 uint64_t value = endian::native_to_big(varNumber);
Alexander Afanasyev74633892015-02-08 18:08:46 -0800158 prependByteArray(reinterpret_cast<const uint8_t*>(&value), 8);
159 prependByte(255);
160 return 9;
161 }
162}
163
164size_t
165Encoder::appendVarNumber(uint64_t varNumber)
166{
167 if (varNumber < 253) {
168 appendByte(static_cast<uint8_t>(varNumber));
169 return 1;
170 }
171 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
172 appendByte(253);
Davide Pesavento14883ad2018-07-14 16:31:39 -0400173 uint16_t value = endian::native_to_big(static_cast<uint16_t>(varNumber));
Alexander Afanasyev74633892015-02-08 18:08:46 -0800174 appendByteArray(reinterpret_cast<const uint8_t*>(&value), 2);
175 return 3;
176 }
177 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
178 appendByte(254);
Davide Pesavento14883ad2018-07-14 16:31:39 -0400179 uint32_t value = endian::native_to_big(static_cast<uint32_t>(varNumber));
Alexander Afanasyev74633892015-02-08 18:08:46 -0800180 appendByteArray(reinterpret_cast<const uint8_t*>(&value), 4);
181 return 5;
182 }
183 else {
184 appendByte(255);
Davide Pesavento14883ad2018-07-14 16:31:39 -0400185 uint64_t value = endian::native_to_big(varNumber);
Alexander Afanasyev74633892015-02-08 18:08:46 -0800186 appendByteArray(reinterpret_cast<const uint8_t*>(&value), 8);
187 return 9;
188 }
189}
190
Alexander Afanasyev74633892015-02-08 18:08:46 -0800191size_t
192Encoder::prependNonNegativeInteger(uint64_t varNumber)
193{
194 if (varNumber <= std::numeric_limits<uint8_t>::max()) {
195 return prependByte(static_cast<uint8_t>(varNumber));
196 }
197 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento14883ad2018-07-14 16:31:39 -0400198 uint16_t value = endian::native_to_big(static_cast<uint16_t>(varNumber));
Alexander Afanasyev74633892015-02-08 18:08:46 -0800199 return prependByteArray(reinterpret_cast<const uint8_t*>(&value), 2);
200 }
201 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento14883ad2018-07-14 16:31:39 -0400202 uint32_t value = endian::native_to_big(static_cast<uint32_t>(varNumber));
Alexander Afanasyev74633892015-02-08 18:08:46 -0800203 return prependByteArray(reinterpret_cast<const uint8_t*>(&value), 4);
204 }
205 else {
Davide Pesavento14883ad2018-07-14 16:31:39 -0400206 uint64_t value = endian::native_to_big(varNumber);
Alexander Afanasyev74633892015-02-08 18:08:46 -0800207 return prependByteArray(reinterpret_cast<const uint8_t*>(&value), 8);
208 }
209}
210
211size_t
212Encoder::appendNonNegativeInteger(uint64_t varNumber)
213{
214 if (varNumber <= std::numeric_limits<uint8_t>::max()) {
215 return appendByte(static_cast<uint8_t>(varNumber));
216 }
217 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento14883ad2018-07-14 16:31:39 -0400218 uint16_t value = endian::native_to_big(static_cast<uint16_t>(varNumber));
Alexander Afanasyev74633892015-02-08 18:08:46 -0800219 return appendByteArray(reinterpret_cast<const uint8_t*>(&value), 2);
220 }
221 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento14883ad2018-07-14 16:31:39 -0400222 uint32_t value = endian::native_to_big(static_cast<uint32_t>(varNumber));
Alexander Afanasyev74633892015-02-08 18:08:46 -0800223 return appendByteArray(reinterpret_cast<const uint8_t*>(&value), 4);
224 }
225 else {
Davide Pesavento14883ad2018-07-14 16:31:39 -0400226 uint64_t value = endian::native_to_big(varNumber);
Alexander Afanasyev74633892015-02-08 18:08:46 -0800227 return appendByteArray(reinterpret_cast<const uint8_t*>(&value), 8);
228 }
229}
230
231size_t
232Encoder::prependByteArrayBlock(uint32_t type, const uint8_t* array, size_t arraySize)
233{
234 size_t totalLength = prependByteArray(array, arraySize);
235 totalLength += prependVarNumber(arraySize);
236 totalLength += prependVarNumber(type);
237
238 return totalLength;
239}
240
241size_t
242Encoder::appendByteArrayBlock(uint32_t type, const uint8_t* array, size_t arraySize)
243{
244 size_t totalLength = appendVarNumber(type);
245 totalLength += appendVarNumber(arraySize);
246 totalLength += appendByteArray(array, arraySize);
247
248 return totalLength;
249}
250
251size_t
252Encoder::prependBlock(const Block& block)
253{
254 if (block.hasWire()) {
255 return prependByteArray(block.wire(), block.size());
256 }
257 else {
258 return prependByteArrayBlock(block.type(), block.value(), block.value_size());
259 }
260}
261
262size_t
263Encoder::appendBlock(const Block& block)
264{
265 if (block.hasWire()) {
266 return appendByteArray(block.wire(), block.size());
267 }
268 else {
269 return appendByteArrayBlock(block.type(), block.value(), block.value_size());
270 }
271}
272
273} // namespace encoding
274} // namespace ndn