blob: 5634ed61cfae134c99b86beb20f71102f847d8fe [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Junxiao Shi9da07c52017-08-06 16:59:30 +00002/*
3 * Copyright (c) 2013-2017 Regents of the University of California.
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -08004 *
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07005 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -08006 *
Alexander Afanasyevc169a812014-05-20 20:37:29 -04007 * 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.
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080020 */
21
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070022#ifndef NDN_ENCODING_BLOCK_HELPERS_HPP
23#define NDN_ENCODING_BLOCK_HELPERS_HPP
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080024
25#include "block.hpp"
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070026#include "encoding-buffer.hpp"
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070027#include "../util/concepts.hpp"
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080028
Alexander Afanasyev74633892015-02-08 18:08:46 -080029#include <iterator>
30
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080031namespace ndn {
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070032namespace encoding {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080033
Junxiao Shi9da07c52017-08-06 16:59:30 +000034/** @brief Prepend a TLV element containing a non-negative integer
35 * @param encoder an EncodingBuffer or EncodingEstimator
36 * @param type TLV-TYPE number
37 * @param value non-negative integer value
38 * @sa makeNonNegativeIntegerBlock, readNonNegativeInteger
Alexander Afanasyev74633892015-02-08 18:08:46 -080039 */
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070040template<Tag TAG>
41size_t
42prependNonNegativeIntegerBlock(EncodingImpl<TAG>& encoder, uint32_t type, uint64_t value);
Alexander Afanasyev74633892015-02-08 18:08:46 -080043
Junxiao Shi9da07c52017-08-06 16:59:30 +000044extern template size_t
45prependNonNegativeIntegerBlock<EstimatorTag>(EncodingImpl<EstimatorTag>&, uint32_t, uint64_t);
46
47extern template size_t
48prependNonNegativeIntegerBlock<EncoderTag>(EncodingImpl<EncoderTag>&, uint32_t, uint64_t);
49
50/** @brief Create a TLV block containing a non-negative integer
51 * @param type TLV-TYPE number
52 * @param value non-negative integer value
53 * @sa prependNonNegativeIntegerBlock, readNonNegativeInteger
Alexander Afanasyev74633892015-02-08 18:08:46 -080054 */
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070055Block
56makeNonNegativeIntegerBlock(uint32_t type, uint64_t value);
Alexander Afanasyev74633892015-02-08 18:08:46 -080057
Junxiao Shi9da07c52017-08-06 16:59:30 +000058/** @brief Read a non-negative integer from a TLV element
59 * @param block the TLV element
60 * @throw tlv::Error block does not contain a non-negative integer
61 * @sa prependNonNegativeIntegerBlock, makeNonNegativeIntegerBlock
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070062 */
63uint64_t
64readNonNegativeInteger(const Block& block);
Alexander Afanasyev74633892015-02-08 18:08:46 -080065
Junxiao Shi5d75fd92017-08-08 18:09:20 +000066/** @brief Read a non-negative integer from a TLV element and cast to the specified type
67 * @tparam R result type, must be an integral type
68 * @param block the TLV element
69 * @throw tlv::Error block does not contain a valid non-negative integer or the number cannot be
70 * represented in R
71 */
72template<typename R>
73typename std::enable_if<std::is_integral<R>::value, R>::type
74readNonNegativeIntegerAs(const Block& block)
75{
76 uint64_t value = readNonNegativeInteger(block);
77 if (value > std::numeric_limits<R>::max()) {
78 BOOST_THROW_EXCEPTION(tlv::Error("Value in TLV element of type " + to_string(block.type()) +
79 " is too large"));
80 }
81 return static_cast<R>(value);
82}
83
84/** @brief Read a non-negative integer from a TLV element and cast to the specified type
85 * @tparam R result type, must be an enumeration type
86 * @param block the TLV element
87 * @throw tlv::Error block does not contain a valid non-negative integer or the number cannot be
88 * represented in R
89 * @warning If R is an unscoped enum type, it must have a fixed underlying type. Otherwise, this
90 * function may trigger unspecified behavior.
91 */
92template<typename R>
93typename std::enable_if<std::is_enum<R>::value, R>::type
94readNonNegativeIntegerAs(const Block& block)
95{
96 return static_cast<R>(readNonNegativeIntegerAs<typename std::underlying_type<R>::type>(block));
97}
98
Junxiao Shi9da07c52017-08-06 16:59:30 +000099/** @brief Prepend an empty TLV element
100 * @param encoder an EncodingBuffer or EncodingEstimator
101 * @param type TLV-TYPE number
102 * @details The TLV element has zero-length TLV-VALUE.
103 * @sa makeEmptyBlock
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700104 */
105template<Tag TAG>
106size_t
107prependEmptyBlock(EncodingImpl<TAG>& encoder, uint32_t type);
Alexander Afanasyev74633892015-02-08 18:08:46 -0800108
Junxiao Shi9da07c52017-08-06 16:59:30 +0000109extern template size_t
110prependEmptyBlock<EstimatorTag>(EncodingImpl<EstimatorTag>&, uint32_t);
111
112extern template size_t
113prependEmptyBlock<EncoderTag>(EncodingImpl<EncoderTag>&, uint32_t);
114
115/** @brief Create an empty TLV block
116 * @param type TLV-TYPE number
117 * @return A TLV block with zero-length TLV-VALUE
118 * @sa prependEmptyBlock
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700119 */
120Block
121makeEmptyBlock(uint32_t type);
Alexander Afanasyev74633892015-02-08 18:08:46 -0800122
Junxiao Shi9da07c52017-08-06 16:59:30 +0000123/** @brief Prepend a TLV element containing a string.
124 * @param encoder an EncodingBuffer or EncodingEstimator
125 * @param type TLV-TYPE number
126 * @param value string value, may contain NUL octets
127 * @sa makeStringBlock, readString
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700128 */
129template<Tag TAG>
130size_t
131prependStringBlock(EncodingImpl<TAG>& encoder, uint32_t type, const std::string& value);
Alexander Afanasyev74633892015-02-08 18:08:46 -0800132
Junxiao Shi9da07c52017-08-06 16:59:30 +0000133extern template size_t
134prependStringBlock<EstimatorTag>(EncodingImpl<EstimatorTag>&, uint32_t, const std::string&);
135
136extern template size_t
137prependStringBlock<EncoderTag>(EncodingImpl<EncoderTag>&, uint32_t, const std::string&);
138
139/** @brief Create a TLV block containing a string.
140 * @param type TLV-TYPE number
141 * @param value string value, may contain NUL octets
142 * @sa prependStringBlock, readString
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700143 */
144Block
145makeStringBlock(uint32_t type, const std::string& value);
Alexander Afanasyev74633892015-02-08 18:08:46 -0800146
Junxiao Shi9da07c52017-08-06 16:59:30 +0000147/** @brief Read TLV-VALUE of a TLV element as a string.
148 * @param block the TLV element
149 * @return a string, may contain NUL octets
150 * @sa prependStringBlock, makeStringBlock
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700151 */
152std::string
153readString(const Block& block);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700154
Junxiao Shi9da07c52017-08-06 16:59:30 +0000155/** @brief Create a TLV block copying TLV-VALUE from raw buffer.
156 * @param type TLV-TYPE number
157 * @param value raw buffer as TLV-VALUE
158 * @param length length of value buffer
159 * @sa Encoder::prependByteArrayBlock
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700160 */
161Block
162makeBinaryBlock(uint32_t type, const uint8_t* value, size_t length);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800163
Junxiao Shi9da07c52017-08-06 16:59:30 +0000164/** @brief Create a TLV block copying TLV-VALUE from raw buffer.
165 * @param type TLV-TYPE number
166 * @param value raw buffer as TLV-VALUE
167 * @param length length of value buffer
168 * @sa Encoder::prependByteArrayBlock
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700169 */
170Block
171makeBinaryBlock(uint32_t type, const char* value, size_t length);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800172
Junxiao Shi9da07c52017-08-06 16:59:30 +0000173namespace detail {
174
175/** @brief Create a binary block copying from RandomAccessIterator
Alexander Afanasyev74633892015-02-08 18:08:46 -0800176 */
177template<class Iterator>
Junxiao Shi9da07c52017-08-06 16:59:30 +0000178class BinaryBlockFast
Alexander Afanasyev74633892015-02-08 18:08:46 -0800179{
180public:
181 BOOST_CONCEPT_ASSERT((boost::RandomAccessIterator<Iterator>));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800182
Alexander Afanasyev74633892015-02-08 18:08:46 -0800183 static Block
184 makeBlock(uint32_t type, Iterator first, Iterator last)
185 {
186 EncodingEstimator estimator;
187 size_t valueLength = last - first;
188 size_t totalLength = valueLength;
189 totalLength += estimator.prependVarNumber(valueLength);
190 totalLength += estimator.prependVarNumber(type);
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700191
Alexander Afanasyev74633892015-02-08 18:08:46 -0800192 EncodingBuffer encoder(totalLength, 0);
193 encoder.prependRange(first, last);
194 encoder.prependVarNumber(valueLength);
195 encoder.prependVarNumber(type);
196
197 return encoder.block();
198 }
199};
200
Junxiao Shi9da07c52017-08-06 16:59:30 +0000201/** @brief Create a binary block copying from generic InputIterator
Alexander Afanasyev74633892015-02-08 18:08:46 -0800202 */
203template<class Iterator>
Junxiao Shi9da07c52017-08-06 16:59:30 +0000204class BinaryBlockSlow
Alexander Afanasyev74633892015-02-08 18:08:46 -0800205{
206public:
207 BOOST_CONCEPT_ASSERT((boost::InputIterator<Iterator>));
208
209 static Block
210 makeBlock(uint32_t type, Iterator first, Iterator last)
211 {
212 // reserve 4 bytes in front (common for 1(type)-3(length) encoding
213 // Actual size will be adjusted as necessary by the encoder
214 EncodingBuffer encoder(4, 4);
215 size_t valueLength = encoder.appendRange(first, last);
216 encoder.prependVarNumber(valueLength);
217 encoder.prependVarNumber(type);
218
219 return encoder.block();
220 }
221};
222
Junxiao Shi9da07c52017-08-06 16:59:30 +0000223} // namespace detail
224
225/** @brief Create a TLV block copying TLV-VALUE from iterators.
226 * @tparam Iterator an InputIterator dereferencable to an 1-octet type; faster implementation is
227 * available for RandomAccessIterator
228 * @param type TLV-TYPE number
229 * @param first begin iterator
230 * @param last past-the-end iterator
Alexander Afanasyev74633892015-02-08 18:08:46 -0800231 */
232template<class Iterator>
Junxiao Shi9da07c52017-08-06 16:59:30 +0000233Block
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700234makeBinaryBlock(uint32_t type, Iterator first, Iterator last)
Alexander Afanasyev74633892015-02-08 18:08:46 -0800235{
Junxiao Shi9da07c52017-08-06 16:59:30 +0000236 static_assert(sizeof(typename std::iterator_traits<Iterator>::value_type) == 1, "");
Alexander Afanasyev74633892015-02-08 18:08:46 -0800237
Junxiao Shi9da07c52017-08-06 16:59:30 +0000238 using BinaryBlockHelper = typename std::conditional<
Alexander Afanasyev74633892015-02-08 18:08:46 -0800239 std::is_base_of<std::random_access_iterator_tag,
Junxiao Shi9da07c52017-08-06 16:59:30 +0000240 typename std::iterator_traits<Iterator>::iterator_category>::value,
241 detail::BinaryBlockFast<Iterator>,
242 detail::BinaryBlockSlow<Iterator>>::type;
Alexander Afanasyev74633892015-02-08 18:08:46 -0800243
Junxiao Shi9da07c52017-08-06 16:59:30 +0000244 return BinaryBlockHelper::makeBlock(type, first, last);
Alexander Afanasyev74633892015-02-08 18:08:46 -0800245}
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700246
Junxiao Shi9da07c52017-08-06 16:59:30 +0000247/** @brief Prepend a TLV element containing a nested TLV element.
248 * @tparam U type that satisfies WireEncodableWithEncodingBuffer concept
249 * @param encoder an EncodingBuffer or EncodingEstimator
250 * @param type TLV-TYPE number for outer TLV element
251 * @param value an object to be encoded as inner TLV element
252 * @sa makeNestedBlock
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700253 */
254template<Tag TAG, class U>
Junxiao Shi9da07c52017-08-06 16:59:30 +0000255size_t
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700256prependNestedBlock(EncodingImpl<TAG>& encoder, uint32_t type, const U& value)
257{
258 BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer<U>));
259
260 size_t valueLength = value.wireEncode(encoder);
261 size_t totalLength = valueLength;
262 totalLength += encoder.prependVarNumber(valueLength);
263 totalLength += encoder.prependVarNumber(type);
264
265 return totalLength;
266}
267
Junxiao Shi9da07c52017-08-06 16:59:30 +0000268/** @brief Create a TLV block containing a nested TLV element.
269 * @tparam U type that satisfies WireEncodableWithEncodingBuffer concept
270 * @param type TLV-TYPE number for outer TLV element
271 * @param value an object to be encoded as inner TLV element
272 * @sa prependNestedBlock
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700273 */
274template<class U>
Junxiao Shi9da07c52017-08-06 16:59:30 +0000275Block
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700276makeNestedBlock(uint32_t type, const U& value)
277{
278 EncodingEstimator estimator;
279 size_t totalLength = prependNestedBlock(estimator, type, value);
280
281 EncodingBuffer encoder(totalLength, 0);
282 prependNestedBlock(encoder, type, value);
283
284 return encoder.block();
285}
286
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700287} // namespace encoding
288
289using encoding::makeNonNegativeIntegerBlock;
290using encoding::readNonNegativeInteger;
Junxiao Shi5d75fd92017-08-08 18:09:20 +0000291using encoding::readNonNegativeIntegerAs;
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700292using encoding::makeEmptyBlock;
293using encoding::makeStringBlock;
294using encoding::readString;
295using encoding::makeBinaryBlock;
296using encoding::makeNestedBlock;
297
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800298} // namespace ndn
299
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700300#endif // NDN_ENCODING_BLOCK_HELPERS_HPP