blob: c66c0b9562031a0a0bfcb1251e27178cb02f49f1 [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
29namespace ndn {
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070030namespace encoding {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080031
Junxiao Shi9da07c52017-08-06 16:59:30 +000032/** @brief Prepend a TLV element containing a non-negative integer
33 * @param encoder an EncodingBuffer or EncodingEstimator
34 * @param type TLV-TYPE number
35 * @param value non-negative integer value
36 * @sa makeNonNegativeIntegerBlock, readNonNegativeInteger
Alexander Afanasyev74633892015-02-08 18:08:46 -080037 */
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070038template<Tag TAG>
39size_t
40prependNonNegativeIntegerBlock(EncodingImpl<TAG>& encoder, uint32_t type, uint64_t value);
Alexander Afanasyev74633892015-02-08 18:08:46 -080041
Junxiao Shi9da07c52017-08-06 16:59:30 +000042extern template size_t
43prependNonNegativeIntegerBlock<EstimatorTag>(EncodingImpl<EstimatorTag>&, uint32_t, uint64_t);
44
45extern template size_t
46prependNonNegativeIntegerBlock<EncoderTag>(EncodingImpl<EncoderTag>&, uint32_t, uint64_t);
47
48/** @brief Create a TLV block containing a non-negative integer
49 * @param type TLV-TYPE number
50 * @param value non-negative integer value
51 * @sa prependNonNegativeIntegerBlock, readNonNegativeInteger
Alexander Afanasyev74633892015-02-08 18:08:46 -080052 */
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070053Block
54makeNonNegativeIntegerBlock(uint32_t type, uint64_t value);
Alexander Afanasyev74633892015-02-08 18:08:46 -080055
Junxiao Shi9da07c52017-08-06 16:59:30 +000056/** @brief Read a non-negative integer from a TLV element
57 * @param block the TLV element
58 * @throw tlv::Error block does not contain a non-negative integer
59 * @sa prependNonNegativeIntegerBlock, makeNonNegativeIntegerBlock
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070060 */
61uint64_t
62readNonNegativeInteger(const Block& block);
Alexander Afanasyev74633892015-02-08 18:08:46 -080063
Junxiao Shi5d75fd92017-08-08 18:09:20 +000064/** @brief Read a non-negative integer from a TLV element and cast to the specified type
65 * @tparam R result type, must be an integral type
66 * @param block the TLV element
67 * @throw tlv::Error block does not contain a valid non-negative integer or the number cannot be
68 * represented in R
69 */
70template<typename R>
71typename std::enable_if<std::is_integral<R>::value, R>::type
72readNonNegativeIntegerAs(const Block& block)
73{
74 uint64_t value = readNonNegativeInteger(block);
75 if (value > std::numeric_limits<R>::max()) {
76 BOOST_THROW_EXCEPTION(tlv::Error("Value in TLV element of type " + to_string(block.type()) +
77 " is too large"));
78 }
79 return static_cast<R>(value);
80}
81
82/** @brief Read a non-negative integer from a TLV element and cast to the specified type
83 * @tparam R result type, must be an enumeration type
84 * @param block the TLV element
85 * @throw tlv::Error block does not contain a valid non-negative integer or the number cannot be
86 * represented in R
87 * @warning If R is an unscoped enum type, it must have a fixed underlying type. Otherwise, this
88 * function may trigger unspecified behavior.
89 */
90template<typename R>
91typename std::enable_if<std::is_enum<R>::value, R>::type
92readNonNegativeIntegerAs(const Block& block)
93{
94 return static_cast<R>(readNonNegativeIntegerAs<typename std::underlying_type<R>::type>(block));
95}
96
Junxiao Shi9da07c52017-08-06 16:59:30 +000097/** @brief Prepend an empty TLV element
98 * @param encoder an EncodingBuffer or EncodingEstimator
99 * @param type TLV-TYPE number
100 * @details The TLV element has zero-length TLV-VALUE.
101 * @sa makeEmptyBlock
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700102 */
103template<Tag TAG>
104size_t
105prependEmptyBlock(EncodingImpl<TAG>& encoder, uint32_t type);
Alexander Afanasyev74633892015-02-08 18:08:46 -0800106
Junxiao Shi9da07c52017-08-06 16:59:30 +0000107extern template size_t
108prependEmptyBlock<EstimatorTag>(EncodingImpl<EstimatorTag>&, uint32_t);
109
110extern template size_t
111prependEmptyBlock<EncoderTag>(EncodingImpl<EncoderTag>&, uint32_t);
112
113/** @brief Create an empty TLV block
114 * @param type TLV-TYPE number
115 * @return A TLV block with zero-length TLV-VALUE
116 * @sa prependEmptyBlock
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700117 */
118Block
119makeEmptyBlock(uint32_t type);
Alexander Afanasyev74633892015-02-08 18:08:46 -0800120
Junxiao Shi9da07c52017-08-06 16:59:30 +0000121/** @brief Prepend a TLV element containing a string.
122 * @param encoder an EncodingBuffer or EncodingEstimator
123 * @param type TLV-TYPE number
124 * @param value string value, may contain NUL octets
125 * @sa makeStringBlock, readString
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700126 */
127template<Tag TAG>
128size_t
129prependStringBlock(EncodingImpl<TAG>& encoder, uint32_t type, const std::string& value);
Alexander Afanasyev74633892015-02-08 18:08:46 -0800130
Junxiao Shi9da07c52017-08-06 16:59:30 +0000131extern template size_t
132prependStringBlock<EstimatorTag>(EncodingImpl<EstimatorTag>&, uint32_t, const std::string&);
133
134extern template size_t
135prependStringBlock<EncoderTag>(EncodingImpl<EncoderTag>&, uint32_t, const std::string&);
136
137/** @brief Create a TLV block containing a string.
138 * @param type TLV-TYPE number
139 * @param value string value, may contain NUL octets
140 * @sa prependStringBlock, readString
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700141 */
142Block
143makeStringBlock(uint32_t type, const std::string& value);
Alexander Afanasyev74633892015-02-08 18:08:46 -0800144
Junxiao Shi9da07c52017-08-06 16:59:30 +0000145/** @brief Read TLV-VALUE of a TLV element as a string.
146 * @param block the TLV element
147 * @return a string, may contain NUL octets
148 * @sa prependStringBlock, makeStringBlock
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700149 */
150std::string
151readString(const Block& block);
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700152
Junxiao Shi9da07c52017-08-06 16:59:30 +0000153/** @brief Create a TLV block copying TLV-VALUE from raw buffer.
154 * @param type TLV-TYPE number
155 * @param value raw buffer as TLV-VALUE
156 * @param length length of value buffer
157 * @sa Encoder::prependByteArrayBlock
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700158 */
159Block
160makeBinaryBlock(uint32_t type, const uint8_t* value, size_t length);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800161
Junxiao Shi9da07c52017-08-06 16:59:30 +0000162/** @brief Create a TLV block copying TLV-VALUE from raw buffer.
163 * @param type TLV-TYPE number
164 * @param value raw buffer as TLV-VALUE
165 * @param length length of value buffer
166 * @sa Encoder::prependByteArrayBlock
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700167 */
168Block
169makeBinaryBlock(uint32_t type, const char* value, size_t length);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800170
Junxiao Shi9da07c52017-08-06 16:59:30 +0000171namespace detail {
172
173/** @brief Create a binary block copying from RandomAccessIterator
Alexander Afanasyev74633892015-02-08 18:08:46 -0800174 */
175template<class Iterator>
Junxiao Shi9da07c52017-08-06 16:59:30 +0000176class BinaryBlockFast
Alexander Afanasyev74633892015-02-08 18:08:46 -0800177{
178public:
179 BOOST_CONCEPT_ASSERT((boost::RandomAccessIterator<Iterator>));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800180
Alexander Afanasyev74633892015-02-08 18:08:46 -0800181 static Block
182 makeBlock(uint32_t type, Iterator first, Iterator last)
183 {
184 EncodingEstimator estimator;
185 size_t valueLength = last - first;
186 size_t totalLength = valueLength;
187 totalLength += estimator.prependVarNumber(valueLength);
188 totalLength += estimator.prependVarNumber(type);
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700189
Alexander Afanasyev74633892015-02-08 18:08:46 -0800190 EncodingBuffer encoder(totalLength, 0);
191 encoder.prependRange(first, last);
192 encoder.prependVarNumber(valueLength);
193 encoder.prependVarNumber(type);
194
195 return encoder.block();
196 }
197};
198
Junxiao Shi9da07c52017-08-06 16:59:30 +0000199/** @brief Create a binary block copying from generic InputIterator
Alexander Afanasyev74633892015-02-08 18:08:46 -0800200 */
201template<class Iterator>
Junxiao Shi9da07c52017-08-06 16:59:30 +0000202class BinaryBlockSlow
Alexander Afanasyev74633892015-02-08 18:08:46 -0800203{
204public:
205 BOOST_CONCEPT_ASSERT((boost::InputIterator<Iterator>));
206
207 static Block
208 makeBlock(uint32_t type, Iterator first, Iterator last)
209 {
210 // reserve 4 bytes in front (common for 1(type)-3(length) encoding
211 // Actual size will be adjusted as necessary by the encoder
212 EncodingBuffer encoder(4, 4);
213 size_t valueLength = encoder.appendRange(first, last);
214 encoder.prependVarNumber(valueLength);
215 encoder.prependVarNumber(type);
216
217 return encoder.block();
218 }
219};
220
Junxiao Shi9da07c52017-08-06 16:59:30 +0000221} // namespace detail
222
223/** @brief Create a TLV block copying TLV-VALUE from iterators.
224 * @tparam Iterator an InputIterator dereferencable to an 1-octet type; faster implementation is
225 * available for RandomAccessIterator
226 * @param type TLV-TYPE number
227 * @param first begin iterator
228 * @param last past-the-end iterator
Alexander Afanasyev74633892015-02-08 18:08:46 -0800229 */
230template<class Iterator>
Junxiao Shi9da07c52017-08-06 16:59:30 +0000231Block
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700232makeBinaryBlock(uint32_t type, Iterator first, Iterator last)
Alexander Afanasyev74633892015-02-08 18:08:46 -0800233{
Junxiao Shi9da07c52017-08-06 16:59:30 +0000234 using BinaryBlockHelper = typename std::conditional<
Alexander Afanasyev74633892015-02-08 18:08:46 -0800235 std::is_base_of<std::random_access_iterator_tag,
Junxiao Shi9da07c52017-08-06 16:59:30 +0000236 typename std::iterator_traits<Iterator>::iterator_category>::value,
237 detail::BinaryBlockFast<Iterator>,
238 detail::BinaryBlockSlow<Iterator>>::type;
Alexander Afanasyev74633892015-02-08 18:08:46 -0800239
Junxiao Shi9da07c52017-08-06 16:59:30 +0000240 return BinaryBlockHelper::makeBlock(type, first, last);
Alexander Afanasyev74633892015-02-08 18:08:46 -0800241}
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700242
Junxiao Shi9da07c52017-08-06 16:59:30 +0000243/** @brief Prepend a TLV element containing a nested TLV element.
244 * @tparam U type that satisfies WireEncodableWithEncodingBuffer concept
245 * @param encoder an EncodingBuffer or EncodingEstimator
246 * @param type TLV-TYPE number for outer TLV element
247 * @param value an object to be encoded as inner TLV element
248 * @sa makeNestedBlock
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700249 */
250template<Tag TAG, class U>
Junxiao Shi9da07c52017-08-06 16:59:30 +0000251size_t
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700252prependNestedBlock(EncodingImpl<TAG>& encoder, uint32_t type, const U& value)
253{
254 BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer<U>));
255
256 size_t valueLength = value.wireEncode(encoder);
257 size_t totalLength = valueLength;
258 totalLength += encoder.prependVarNumber(valueLength);
259 totalLength += encoder.prependVarNumber(type);
260
261 return totalLength;
262}
263
Junxiao Shi9da07c52017-08-06 16:59:30 +0000264/** @brief Create a TLV block containing a nested TLV element.
265 * @tparam U type that satisfies WireEncodableWithEncodingBuffer concept
266 * @param type TLV-TYPE number for outer TLV element
267 * @param value an object to be encoded as inner TLV element
268 * @sa prependNestedBlock
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700269 */
270template<class U>
Junxiao Shi9da07c52017-08-06 16:59:30 +0000271Block
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700272makeNestedBlock(uint32_t type, const U& value)
273{
274 EncodingEstimator estimator;
275 size_t totalLength = prependNestedBlock(estimator, type, value);
276
277 EncodingBuffer encoder(totalLength, 0);
278 prependNestedBlock(encoder, type, value);
279
280 return encoder.block();
281}
282
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700283} // namespace encoding
284
285using encoding::makeNonNegativeIntegerBlock;
286using encoding::readNonNegativeInteger;
Junxiao Shi5d75fd92017-08-08 18:09:20 +0000287using encoding::readNonNegativeIntegerAs;
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700288using encoding::makeEmptyBlock;
289using encoding::makeStringBlock;
290using encoding::readString;
291using encoding::makeBinaryBlock;
292using encoding::makeNestedBlock;
293
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800294} // namespace ndn
295
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700296#endif // NDN_ENCODING_BLOCK_HELPERS_HPP