blob: 77d62f56b032f2bb58f05495f123f1028c085893 [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Junxiao Shic18aa192017-07-07 06:06:38 +00002/*
Junxiao Shi1534b3d2018-01-22 08:47:03 +00003 * Copyright (c) 2013-2018 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_TLV_HPP
23#define NDN_ENCODING_TLV_HPP
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080024
Davide Pesavento570b20d2018-07-15 21:53:14 -040025#include "../common.hpp"
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080026
Junxiao Shi46a9bd32017-07-14 19:12:11 +000027#include <cstring>
Davide Pesaventoe1789892017-02-26 15:50:52 -050028#include <iterator>
Davide Pesavento4ab3be22017-07-18 00:38:52 -040029#include <ostream>
30#include <type_traits>
Davide Pesavento570b20d2018-07-15 21:53:14 -040031#include <vector>
Davide Pesaventoe1789892017-02-26 15:50:52 -050032
Davide Pesavento14883ad2018-07-14 16:31:39 -040033#include <boost/endian/conversion.hpp>
34
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080035namespace ndn {
36
Junxiao Shi468abc32014-11-04 09:12:47 -070037/** @brief practical limit of network layer packet size
38 *
39 * If a packet is longer than this size, library and application MAY drop it.
40 */
41const size_t MAX_NDN_PACKET_SIZE = 8800;
42
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080043/**
Junxiao Shia2550a92018-04-10 05:07:48 +000044 * @brief Namespace defining NDN Packet Format related constants and procedures
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080045 */
Steve DiBenedetto54ce6682014-07-22 13:22:57 -060046namespace tlv {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080047
Junxiao Shi468abc32014-11-04 09:12:47 -070048/** @brief represents an error in TLV encoding or decoding
49 *
50 * Element::Error SHOULD inherit from this Error class.
51 */
Alexander Afanasyeva465e972014-03-22 17:21:49 -070052class Error : public std::runtime_error
53{
54public:
55 explicit
56 Error(const std::string& what)
57 : std::runtime_error(what)
58 {
59 }
60};
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080061
Junxiao Shia2550a92018-04-10 05:07:48 +000062/** @brief TLV-TYPE numbers defined in NDN Packet Format v0.3
63 * @sa https://named-data.net/doc/NDN-packet-spec/current/types.html
Junxiao Shi7d3c14b2017-08-05 16:34:39 +000064 */
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080065enum {
Junxiao Shia2550a92018-04-10 05:07:48 +000066 Interest = 5,
67 Data = 6,
68 Name = 7,
69 GenericNameComponent = 8,
Alexander Afanasyev6486d522014-10-23 14:14:11 -070070 ImplicitSha256DigestComponent = 1,
Junxiao Shia2550a92018-04-10 05:07:48 +000071 CanBePrefix = 33,
72 MustBeFresh = 18,
73 ForwardingHint = 30,
74 Nonce = 10,
75 InterestLifetime = 12,
76 HopLimit = 34,
77 Parameters = 35,
78 MetaInfo = 20,
79 Content = 21,
80 SignatureInfo = 22,
81 SignatureValue = 23,
82 ContentType = 24,
83 FreshnessPeriod = 25,
84 FinalBlockId = 26,
85 SignatureType = 27,
86 KeyLocator = 28,
87 KeyDigest = 29,
88 LinkDelegation = 31,
89 LinkPreference = 30,
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080090
Junxiao Shicf4ac5b2018-03-28 22:46:06 +000091 NameComponentMin = 1,
92 NameComponentMax = 65535,
93
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080094 AppPrivateBlock1 = 128,
95 AppPrivateBlock2 = 32767
96};
97
Junxiao Shia2550a92018-04-10 05:07:48 +000098/** @brief TLV-TYPE numbers defined in NDN Packet Format v0.2 but not in v0.3
99 * @sa https://named-data.net/doc/NDN-packet-spec/0.2.1/types.html
100 */
101enum {
102 Selectors = 9,
103 MinSuffixComponents = 13,
104 MaxSuffixComponents = 14,
105 PublisherPublicKeyLocator = 15,
106 Exclude = 16,
107 ChildSelector = 17,
108 Any = 19,
109};
110
Davide Pesavento1fd00242018-05-20 00:11:01 -0400111[[deprecated("use GenericNameComponent")]]
112constexpr int NameComponent = GenericNameComponent;
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000113
Davide Pesavento7e6f6f82017-10-31 18:05:28 -0400114enum SignatureTypeValue : uint16_t {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800115 DigestSha256 = 0,
Yingdi Yuebfa4cb2014-06-17 15:28:53 -0700116 SignatureSha256WithRsa = 1,
Alexander Afanasyev117f5ef2015-06-03 15:07:24 -0700117 // <Unassigned> = 2,
Yingdi Yuebfa4cb2014-06-17 15:28:53 -0700118 SignatureSha256WithEcdsa = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800119};
120
Alexander Afanasyev5f1820e2017-01-04 18:12:42 -0800121std::ostream&
Davide Pesavento7e6f6f82017-10-31 18:05:28 -0400122operator<<(std::ostream& os, SignatureTypeValue signatureType);
Alexander Afanasyev5f1820e2017-01-04 18:12:42 -0800123
Junxiao Shi7d3c14b2017-08-05 16:34:39 +0000124/** @brief TLV-TYPE numbers for SignatureInfo features
Yingdi Yu7a813892015-06-09 14:19:54 -0700125 * @sa docs/tutorials/certificate-format.rst
126 */
127enum {
Yingdi Yu7a813892015-06-09 14:19:54 -0700128 ValidityPeriod = 253,
129 NotBefore = 254,
Yingdi Yuea382942015-07-17 23:20:44 -0700130 NotAfter = 255,
131
132 AdditionalDescription = 258,
133 DescriptionEntry = 512,
134 DescriptionKey = 513,
135 DescriptionValue = 514
Yingdi Yu7a813892015-06-09 14:19:54 -0700136};
137
Junxiao Shia464b922014-11-12 21:13:06 -0700138/** @brief indicates a possible value of ContentType field
139 */
Yingdi Yuebfa4cb2014-06-17 15:28:53 -0700140enum ContentTypeValue {
Junxiao Shia464b922014-11-12 21:13:06 -0700141 /** @brief indicates content is the actual data bits
142 */
143 ContentType_Blob = 0,
144
145 /** @brief indicates content is another name which identifies actual data content
146 */
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800147 ContentType_Link = 1,
Junxiao Shia464b922014-11-12 21:13:06 -0700148
149 /** @brief indicates content is a public key
150 */
151 ContentType_Key = 2,
152
153 /** @brief indicates a producer generated NACK
Junxiao Shia464b922014-11-12 21:13:06 -0700154 */
155 ContentType_Nack = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800156};
157
158/**
Junxiao Shia2550a92018-04-10 05:07:48 +0000159 * @brief Determine whether a TLV-TYPE is "critical" for evolvability purpose.
160 * @sa https://named-data.net/doc/NDN-packet-spec/0.3/tlv.html#considerations-for-evolvability-of-tlv-based-encoding
161 */
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000162constexpr bool
Junxiao Shia2550a92018-04-10 05:07:48 +0000163isCriticalType(uint32_t type)
164{
165 return type <= 31 || (type & 0x01);
166}
167
168/**
Davide Pesavento570b20d2018-07-15 21:53:14 -0400169 * @brief Read VAR-NUMBER in NDN-TLV encoding.
170 * @tparam Iterator an iterator or pointer that dereferences to uint8_t or compatible type
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800171 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000172 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
173 * the read VAR-NUMBER
174 * @param [in] end End of the buffer
175 * @param [out] number Read VAR-NUMBER
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700176 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000177 * @return true if number was successfully read from input, false otherwise
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700178 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000179template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000180bool
Davide Pesavento570b20d2018-07-15 21:53:14 -0400181readVarNumber(Iterator& begin, Iterator end, uint64_t& number) noexcept;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700182
183/**
Davide Pesavento570b20d2018-07-15 21:53:14 -0400184 * @brief Read TLV-TYPE.
185 * @tparam Iterator an iterator or pointer that dereferences to uint8_t or compatible type
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700186 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000187 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
188 * the read TLV-TYPE
189 * @param [in] end End of the buffer
190 * @param [out] type Read TLV-TYPE
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700191 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000192 * @return true if TLV-TYPE was successfully read from input, false otherwise
Davide Pesavento570b20d2018-07-15 21:53:14 -0400193 * @note This function is largely equivalent to readVarNumber(), except that it returns false if
194 * the TLV-TYPE is larger than 2^32-1 (TLV-TYPE in this library is implemented as `uint32_t`)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700195 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000196template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000197bool
Davide Pesavento570b20d2018-07-15 21:53:14 -0400198readType(Iterator& begin, Iterator end, uint32_t& type) noexcept;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700199
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700200/**
Davide Pesavento570b20d2018-07-15 21:53:14 -0400201 * @brief Read VAR-NUMBER in NDN-TLV encoding.
202 * @tparam Iterator an iterator or pointer that dereferences to uint8_t or compatible type
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700203 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000204 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
205 * the read VAR-NUMBER
206 * @param [in] end End of the buffer
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800207 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000208 * @throw tlv::Error VAR-NUMBER cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800209 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000210template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000211uint64_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400212readVarNumber(Iterator& begin, Iterator end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800213
214/**
Davide Pesavento570b20d2018-07-15 21:53:14 -0400215 * @brief Read TLV-TYPE.
216 * @tparam Iterator an iterator or pointer that dereferences to uint8_t or compatible type
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800217 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000218 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
219 * the read TLV-TYPE
220 * @param [in] end End of the buffer
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700221 *
Davide Pesavento570b20d2018-07-15 21:53:14 -0400222 * @throw tlv::Error TLV-TYPE cannot be read
223 * @note This function is largely equivalent to readVarNumber(), except that it throws if
224 * the TLV-TYPE is larger than 2^32-1 (TLV-TYPE in this library is implemented as `uint32_t`)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800225 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000226template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000227uint32_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400228readType(Iterator& begin, Iterator end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800229
230/**
Davide Pesavento570b20d2018-07-15 21:53:14 -0400231 * @brief Get the number of bytes necessary to hold the value of @p number encoded as VAR-NUMBER.
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800232 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000233constexpr size_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400234sizeOfVarNumber(uint64_t number) noexcept;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800235
236/**
Davide Pesavento570b20d2018-07-15 21:53:14 -0400237 * @brief Write VAR-NUMBER to the specified stream.
Junxiao Shic18aa192017-07-07 06:06:38 +0000238 * @return length of written VAR-NUMBER
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800239 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000240size_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000241writeVarNumber(std::ostream& os, uint64_t number);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800242
243/**
Davide Pesavento570b20d2018-07-15 21:53:14 -0400244 * @brief Read nonNegativeInteger in NDN-TLV encoding.
245 * @tparam Iterator an iterator or pointer that dereferences to uint8_t or compatible type
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800246 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000247 * @param [in] size size of the nonNegativeInteger
248 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
249 * the read nonNegativeInteger
250 * @param [in] end End of the buffer
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800251 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000252 * @throw tlv::Error number cannot be read
253 * @note How many bytes to read is directly controlled by \p size, which can be either 1, 2, 4, or 8.
Davide Pesavento570b20d2018-07-15 21:53:14 -0400254 * If \p size differs from `std::distance(begin, end)`, tlv::Error exception will be thrown.
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800255 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000256template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000257uint64_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400258readNonNegativeInteger(size_t size, Iterator& begin, Iterator end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800259
260/**
Davide Pesavento570b20d2018-07-15 21:53:14 -0400261 * @brief Get the number of bytes necessary to hold the value of @p integer encoded as nonNegativeInteger.
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800262 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000263constexpr size_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400264sizeOfNonNegativeInteger(uint64_t integer) noexcept;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800265
266/**
Davide Pesavento570b20d2018-07-15 21:53:14 -0400267 * @brief Write nonNegativeInteger to the specified stream.
Junxiao Shic18aa192017-07-07 06:06:38 +0000268 * @return length of written nonNegativeInteger
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800269 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000270size_t
271writeNonNegativeInteger(std::ostream& os, uint64_t integer);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800272
273/////////////////////////////////////////////////////////////////////////////////
274/////////////////////////////////////////////////////////////////////////////////
275/////////////////////////////////////////////////////////////////////////////////
276
Davide Pesavento4ab3be22017-07-18 00:38:52 -0400277// Inline definitions
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800278
279/////////////////////////////////////////////////////////////////////////////////
280/////////////////////////////////////////////////////////////////////////////////
281/////////////////////////////////////////////////////////////////////////////////
282
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000283namespace detail {
284
285/** @brief Function object to read a number from InputIterator
286 */
287template<typename Iterator>
288class ReadNumberSlow
289{
290public:
Davide Pesavento570b20d2018-07-15 21:53:14 -0400291 constexpr bool
292 operator()(size_t size, Iterator& begin, Iterator end, uint64_t& number) const noexcept
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000293 {
294 number = 0;
295 size_t count = 0;
296 for (; begin != end && count < size; ++begin, ++count) {
297 number = (number << 8) | *begin;
298 }
299 return count == size;
300 }
301};
302
303/** @brief Function object to read a number from ContiguousIterator
304 */
305template<typename Iterator>
306class ReadNumberFast
307{
308public:
Davide Pesavento570b20d2018-07-15 21:53:14 -0400309 constexpr bool
310 operator()(size_t size, Iterator& begin, Iterator end, uint64_t& number) const noexcept
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000311 {
312 if (begin + size > end) {
313 return false;
314 }
315
316 switch (size) {
317 case 1: {
318 number = *begin;
319 ++begin;
320 return true;
321 }
322 case 2: {
323 uint16_t value = 0;
324 std::memcpy(&value, &*begin, 2);
325 begin += 2;
Davide Pesavento14883ad2018-07-14 16:31:39 -0400326 number = boost::endian::big_to_native(value);
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000327 return true;
328 }
329 case 4: {
330 uint32_t value = 0;
331 std::memcpy(&value, &*begin, 4);
332 begin += 4;
Davide Pesavento14883ad2018-07-14 16:31:39 -0400333 number = boost::endian::big_to_native(value);
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000334 return true;
335 }
336 case 8: {
337 uint64_t value = 0;
338 std::memcpy(&value, &*begin, 8);
339 begin += 8;
Davide Pesavento14883ad2018-07-14 16:31:39 -0400340 number = boost::endian::big_to_native(value);
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000341 return true;
342 }
343 default: {
344 BOOST_ASSERT(false);
345 return false;
346 }
347 }
348 }
349};
350
351/** @brief Determine whether to select ReadNumber implementation for ContiguousIterator
352 *
353 * This is not a full ContiguousIterator detection implementation. It returns true for the most
354 * common ContiguousIterator types used with TLV decoding function templates.
355 */
356template<typename Iterator,
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400357 typename DecayedIterator = std::decay_t<Iterator>,
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000358 typename ValueType = typename std::iterator_traits<DecayedIterator>::value_type>
359constexpr bool
360shouldSelectContiguousReadNumber()
361{
362 return (std::is_convertible<DecayedIterator, const ValueType*>::value ||
363 std::is_convertible<DecayedIterator, typename std::basic_string<ValueType>::const_iterator>::value ||
364 std::is_convertible<DecayedIterator, typename std::vector<ValueType>::const_iterator>::value) &&
Davide Pesavento4ab3be22017-07-18 00:38:52 -0400365 sizeof(ValueType) == 1 &&
366 !std::is_same<ValueType, bool>::value;
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000367}
368
369template<typename Iterator>
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400370class ReadNumber : public std::conditional_t<shouldSelectContiguousReadNumber<Iterator>(),
371 ReadNumberFast<Iterator>, ReadNumberSlow<Iterator>>
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000372{
373};
374
375} // namespace detail
376
377template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000378bool
Davide Pesavento570b20d2018-07-15 21:53:14 -0400379readVarNumber(Iterator& begin, Iterator end, uint64_t& number) noexcept
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700380{
381 if (begin == end)
382 return false;
383
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700384 uint8_t firstOctet = *begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700385 ++begin;
Junxiao Shic18aa192017-07-07 06:06:38 +0000386 if (firstOctet < 253) {
387 number = firstOctet;
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000388 return true;
Junxiao Shic18aa192017-07-07 06:06:38 +0000389 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700390
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000391 size_t size = firstOctet == 253 ? 2 :
392 firstOctet == 254 ? 4 : 8;
393 return detail::ReadNumber<Iterator>()(size, begin, end, number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700394}
395
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000396template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000397bool
Davide Pesavento570b20d2018-07-15 21:53:14 -0400398readType(Iterator& begin, Iterator end, uint32_t& type) noexcept
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700399{
Mickey Sweatt632e0572014-04-20 00:36:32 -0700400 uint64_t number = 0;
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700401 bool isOk = readVarNumber(begin, end, number);
Junxiao Shic18aa192017-07-07 06:06:38 +0000402 if (!isOk || number > std::numeric_limits<uint32_t>::max()) {
403 return false;
404 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700405
Davide Pesavento8f5cbdc2015-09-13 00:59:28 +0200406 type = static_cast<uint32_t>(number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700407 return true;
408}
409
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000410template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000411uint64_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400412readVarNumber(Iterator& begin, Iterator end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800413{
Davide Pesavento570b20d2018-07-15 21:53:14 -0400414 if (begin == end) {
415 BOOST_THROW_EXCEPTION(Error("Empty buffer during TLV parsing"));
416 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700417
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000418 uint64_t value = 0;
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700419 bool isOk = readVarNumber(begin, end, value);
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000420 if (!isOk) {
Davide Pesavento570b20d2018-07-15 21:53:14 -0400421 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV parsing"));
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000422 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700423
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700424 return value;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800425}
426
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000427template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000428uint32_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400429readType(Iterator& begin, Iterator end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800430{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700431 uint64_t type = readVarNumber(begin, end);
Junxiao Shic18aa192017-07-07 06:06:38 +0000432 if (type > std::numeric_limits<uint32_t>::max()) {
Junxiao Shi7d3c14b2017-08-05 16:34:39 +0000433 BOOST_THROW_EXCEPTION(Error("TLV-TYPE number exceeds allowed maximum"));
Junxiao Shic18aa192017-07-07 06:06:38 +0000434 }
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800435
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700436 return static_cast<uint32_t>(type);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800437}
438
Junxiao Shic18aa192017-07-07 06:06:38 +0000439constexpr size_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400440sizeOfVarNumber(uint64_t number) noexcept
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800441{
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000442 return number < 253 ? 1 :
443 number <= std::numeric_limits<uint16_t>::max() ? 3 :
444 number <= std::numeric_limits<uint32_t>::max() ? 5 : 9;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800445}
446
447inline size_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000448writeVarNumber(std::ostream& os, uint64_t number)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800449{
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000450 if (number < 253) {
451 os.put(static_cast<char>(number));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800452 return 1;
453 }
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000454 else if (number <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200455 os.put(static_cast<char>(253));
Davide Pesavento14883ad2018-07-14 16:31:39 -0400456 uint16_t value = boost::endian::native_to_big(static_cast<uint16_t>(number));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700457 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800458 return 3;
459 }
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000460 else if (number <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200461 os.put(static_cast<char>(254));
Davide Pesavento14883ad2018-07-14 16:31:39 -0400462 uint32_t value = boost::endian::native_to_big(static_cast<uint32_t>(number));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700463 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800464 return 5;
465 }
466 else {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200467 os.put(static_cast<char>(255));
Davide Pesavento14883ad2018-07-14 16:31:39 -0400468 uint64_t value = boost::endian::native_to_big(number);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700469 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800470 return 9;
471 }
472}
473
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000474template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000475uint64_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400476readNonNegativeInteger(size_t size, Iterator& begin, Iterator end)
Yingdi Yu27158392014-01-20 13:04:20 -0800477{
Junxiao Shic18aa192017-07-07 06:06:38 +0000478 if (size != 1 && size != 2 && size != 4 && size != 8) {
479 BOOST_THROW_EXCEPTION(Error("Invalid length for nonNegativeInteger "
480 "(only 1, 2, 4, and 8 are allowed)"));
Yingdi Yu27158392014-01-20 13:04:20 -0800481 }
Junxiao Shic18aa192017-07-07 06:06:38 +0000482
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000483 uint64_t number = 0;
484 bool isOk = detail::ReadNumber<Iterator>()(size, begin, end, number);
485 if (!isOk) {
Davide Pesavento570b20d2018-07-15 21:53:14 -0400486 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV parsing"));
Junxiao Shic18aa192017-07-07 06:06:38 +0000487 }
488
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000489 return number;
Junxiao Shic18aa192017-07-07 06:06:38 +0000490}
491
492constexpr size_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400493sizeOfNonNegativeInteger(uint64_t integer) noexcept
Junxiao Shic18aa192017-07-07 06:06:38 +0000494{
495 return integer <= std::numeric_limits<uint8_t>::max() ? 1 :
496 integer <= std::numeric_limits<uint16_t>::max() ? 2 :
497 integer <= std::numeric_limits<uint32_t>::max() ? 4 : 8;
Yingdi Yu27158392014-01-20 13:04:20 -0800498}
499
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800500inline size_t
Junxiao Shic18aa192017-07-07 06:06:38 +0000501writeNonNegativeInteger(std::ostream& os, uint64_t integer)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800502{
Junxiao Shic18aa192017-07-07 06:06:38 +0000503 if (integer <= std::numeric_limits<uint8_t>::max()) {
504 os.put(static_cast<char>(integer));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800505 return 1;
506 }
Junxiao Shic18aa192017-07-07 06:06:38 +0000507 else if (integer <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento14883ad2018-07-14 16:31:39 -0400508 uint16_t value = boost::endian::native_to_big(static_cast<uint16_t>(integer));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700509 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800510 return 2;
511 }
Junxiao Shic18aa192017-07-07 06:06:38 +0000512 else if (integer <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento14883ad2018-07-14 16:31:39 -0400513 uint32_t value = boost::endian::native_to_big(static_cast<uint32_t>(integer));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700514 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800515 return 4;
516 }
517 else {
Davide Pesavento14883ad2018-07-14 16:31:39 -0400518 uint64_t value = boost::endian::native_to_big(integer);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700519 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800520 return 8;
521 }
522}
523
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600524} // namespace tlv
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800525} // namespace ndn
526
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700527#endif // NDN_ENCODING_TLV_HPP