blob: f7b724007d520113cdd013c68650924a974d7d7d [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:
Junxiao Shi68b53852018-07-25 13:56:38 -060055 using std::runtime_error::runtime_error;
Alexander Afanasyeva465e972014-03-22 17:21:49 -070056};
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080057
Junxiao Shia2550a92018-04-10 05:07:48 +000058/** @brief TLV-TYPE numbers defined in NDN Packet Format v0.3
59 * @sa https://named-data.net/doc/NDN-packet-spec/current/types.html
Junxiao Shi7d3c14b2017-08-05 16:34:39 +000060 */
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080061enum {
Junxiao Shi4053bd52018-08-16 13:39:25 -060062 Interest = 5,
63 Data = 6,
64 Name = 7,
65 GenericNameComponent = 8,
66 ImplicitSha256DigestComponent = 1,
67 ParametersSha256DigestComponent = 2,
68 CanBePrefix = 33,
69 MustBeFresh = 18,
70 ForwardingHint = 30,
71 Nonce = 10,
72 InterestLifetime = 12,
73 HopLimit = 34,
74 Parameters = 35,
75 MetaInfo = 20,
76 Content = 21,
77 SignatureInfo = 22,
78 SignatureValue = 23,
79 ContentType = 24,
80 FreshnessPeriod = 25,
81 FinalBlockId = 26,
82 SignatureType = 27,
83 KeyLocator = 28,
84 KeyDigest = 29,
85 LinkDelegation = 31,
86 LinkPreference = 30,
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080087
Junxiao Shicf4ac5b2018-03-28 22:46:06 +000088 NameComponentMin = 1,
89 NameComponentMax = 65535,
90
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080091 AppPrivateBlock1 = 128,
92 AppPrivateBlock2 = 32767
93};
94
Junxiao Shia2550a92018-04-10 05:07:48 +000095/** @brief TLV-TYPE numbers defined in NDN Packet Format v0.2 but not in v0.3
96 * @sa https://named-data.net/doc/NDN-packet-spec/0.2.1/types.html
97 */
98enum {
99 Selectors = 9,
100 MinSuffixComponents = 13,
101 MaxSuffixComponents = 14,
102 PublisherPublicKeyLocator = 15,
103 Exclude = 16,
104 ChildSelector = 17,
105 Any = 19,
106};
107
Davide Pesavento1fd00242018-05-20 00:11:01 -0400108[[deprecated("use GenericNameComponent")]]
109constexpr int NameComponent = GenericNameComponent;
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000110
Davide Pesavento7e6f6f82017-10-31 18:05:28 -0400111enum SignatureTypeValue : uint16_t {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800112 DigestSha256 = 0,
Yingdi Yuebfa4cb2014-06-17 15:28:53 -0700113 SignatureSha256WithRsa = 1,
Alexander Afanasyev117f5ef2015-06-03 15:07:24 -0700114 // <Unassigned> = 2,
Yingdi Yuebfa4cb2014-06-17 15:28:53 -0700115 SignatureSha256WithEcdsa = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800116};
117
Alexander Afanasyev5f1820e2017-01-04 18:12:42 -0800118std::ostream&
Davide Pesavento7e6f6f82017-10-31 18:05:28 -0400119operator<<(std::ostream& os, SignatureTypeValue signatureType);
Alexander Afanasyev5f1820e2017-01-04 18:12:42 -0800120
Junxiao Shi7d3c14b2017-08-05 16:34:39 +0000121/** @brief TLV-TYPE numbers for SignatureInfo features
Yingdi Yu7a813892015-06-09 14:19:54 -0700122 * @sa docs/tutorials/certificate-format.rst
123 */
124enum {
Yingdi Yu7a813892015-06-09 14:19:54 -0700125 ValidityPeriod = 253,
126 NotBefore = 254,
Yingdi Yuea382942015-07-17 23:20:44 -0700127 NotAfter = 255,
128
129 AdditionalDescription = 258,
130 DescriptionEntry = 512,
131 DescriptionKey = 513,
132 DescriptionValue = 514
Yingdi Yu7a813892015-06-09 14:19:54 -0700133};
134
Junxiao Shia464b922014-11-12 21:13:06 -0700135/** @brief indicates a possible value of ContentType field
136 */
Yingdi Yuebfa4cb2014-06-17 15:28:53 -0700137enum ContentTypeValue {
Junxiao Shia464b922014-11-12 21:13:06 -0700138 /** @brief indicates content is the actual data bits
139 */
140 ContentType_Blob = 0,
141
142 /** @brief indicates content is another name which identifies actual data content
143 */
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800144 ContentType_Link = 1,
Junxiao Shia464b922014-11-12 21:13:06 -0700145
146 /** @brief indicates content is a public key
147 */
148 ContentType_Key = 2,
149
150 /** @brief indicates a producer generated NACK
Junxiao Shia464b922014-11-12 21:13:06 -0700151 */
152 ContentType_Nack = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800153};
154
155/**
Junxiao Shia2550a92018-04-10 05:07:48 +0000156 * @brief Determine whether a TLV-TYPE is "critical" for evolvability purpose.
157 * @sa https://named-data.net/doc/NDN-packet-spec/0.3/tlv.html#considerations-for-evolvability-of-tlv-based-encoding
158 */
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000159constexpr bool
Junxiao Shia2550a92018-04-10 05:07:48 +0000160isCriticalType(uint32_t type)
161{
162 return type <= 31 || (type & 0x01);
163}
164
165/**
Davide Pesavento570b20d2018-07-15 21:53:14 -0400166 * @brief Read VAR-NUMBER in NDN-TLV encoding.
167 * @tparam Iterator an iterator or pointer that dereferences to uint8_t or compatible type
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800168 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000169 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
170 * the read VAR-NUMBER
171 * @param [in] end End of the buffer
172 * @param [out] number Read VAR-NUMBER
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700173 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000174 * @return true if number was successfully read from input, false otherwise
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700175 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000176template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000177bool
Davide Pesavento570b20d2018-07-15 21:53:14 -0400178readVarNumber(Iterator& begin, Iterator end, uint64_t& number) noexcept;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700179
180/**
Davide Pesavento570b20d2018-07-15 21:53:14 -0400181 * @brief Read TLV-TYPE.
182 * @tparam Iterator an iterator or pointer that dereferences to uint8_t or compatible type
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700183 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000184 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
185 * the read TLV-TYPE
186 * @param [in] end End of the buffer
187 * @param [out] type Read TLV-TYPE
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700188 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000189 * @return true if TLV-TYPE was successfully read from input, false otherwise
Davide Pesavento570b20d2018-07-15 21:53:14 -0400190 * @note This function is largely equivalent to readVarNumber(), except that it returns false if
191 * 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 -0700192 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000193template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000194bool
Davide Pesavento570b20d2018-07-15 21:53:14 -0400195readType(Iterator& begin, Iterator end, uint32_t& type) noexcept;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700196
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700197/**
Davide Pesavento570b20d2018-07-15 21:53:14 -0400198 * @brief Read VAR-NUMBER in NDN-TLV encoding.
199 * @tparam Iterator an iterator or pointer that dereferences to uint8_t or compatible type
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700200 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000201 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
202 * the read VAR-NUMBER
203 * @param [in] end End of the buffer
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800204 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000205 * @throw tlv::Error VAR-NUMBER cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800206 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000207template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000208uint64_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400209readVarNumber(Iterator& begin, Iterator end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800210
211/**
Davide Pesavento570b20d2018-07-15 21:53:14 -0400212 * @brief Read TLV-TYPE.
213 * @tparam Iterator an iterator or pointer that dereferences to uint8_t or compatible type
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800214 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000215 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
216 * the read TLV-TYPE
217 * @param [in] end End of the buffer
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700218 *
Davide Pesavento570b20d2018-07-15 21:53:14 -0400219 * @throw tlv::Error TLV-TYPE cannot be read
220 * @note This function is largely equivalent to readVarNumber(), except that it throws if
221 * 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 -0800222 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000223template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000224uint32_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400225readType(Iterator& begin, Iterator end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800226
227/**
Davide Pesavento570b20d2018-07-15 21:53:14 -0400228 * @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 -0800229 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000230constexpr size_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400231sizeOfVarNumber(uint64_t number) noexcept;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800232
233/**
Davide Pesavento570b20d2018-07-15 21:53:14 -0400234 * @brief Write VAR-NUMBER to the specified stream.
Junxiao Shic18aa192017-07-07 06:06:38 +0000235 * @return length of written VAR-NUMBER
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800236 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000237size_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000238writeVarNumber(std::ostream& os, uint64_t number);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800239
240/**
Davide Pesavento570b20d2018-07-15 21:53:14 -0400241 * @brief Read nonNegativeInteger in NDN-TLV encoding.
242 * @tparam Iterator an iterator or pointer that dereferences to uint8_t or compatible type
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800243 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000244 * @param [in] size size of the nonNegativeInteger
245 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
246 * the read nonNegativeInteger
247 * @param [in] end End of the buffer
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800248 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000249 * @throw tlv::Error number cannot be read
250 * @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 -0400251 * If \p size differs from `std::distance(begin, end)`, tlv::Error exception will be thrown.
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800252 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000253template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000254uint64_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400255readNonNegativeInteger(size_t size, Iterator& begin, Iterator end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800256
257/**
Davide Pesavento570b20d2018-07-15 21:53:14 -0400258 * @brief Get the number of bytes necessary to hold the value of @p integer encoded as nonNegativeInteger.
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800259 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000260constexpr size_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400261sizeOfNonNegativeInteger(uint64_t integer) noexcept;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800262
263/**
Davide Pesavento570b20d2018-07-15 21:53:14 -0400264 * @brief Write nonNegativeInteger to the specified stream.
Junxiao Shic18aa192017-07-07 06:06:38 +0000265 * @return length of written nonNegativeInteger
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800266 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000267size_t
268writeNonNegativeInteger(std::ostream& os, uint64_t integer);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800269
270/////////////////////////////////////////////////////////////////////////////////
271/////////////////////////////////////////////////////////////////////////////////
272/////////////////////////////////////////////////////////////////////////////////
273
Davide Pesavento4ab3be22017-07-18 00:38:52 -0400274// Inline definitions
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800275
276/////////////////////////////////////////////////////////////////////////////////
277/////////////////////////////////////////////////////////////////////////////////
278/////////////////////////////////////////////////////////////////////////////////
279
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000280namespace detail {
281
282/** @brief Function object to read a number from InputIterator
283 */
284template<typename Iterator>
285class ReadNumberSlow
286{
287public:
Davide Pesavento570b20d2018-07-15 21:53:14 -0400288 constexpr bool
289 operator()(size_t size, Iterator& begin, Iterator end, uint64_t& number) const noexcept
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000290 {
291 number = 0;
292 size_t count = 0;
293 for (; begin != end && count < size; ++begin, ++count) {
294 number = (number << 8) | *begin;
295 }
296 return count == size;
297 }
298};
299
300/** @brief Function object to read a number from ContiguousIterator
301 */
302template<typename Iterator>
303class ReadNumberFast
304{
305public:
Davide Pesavento570b20d2018-07-15 21:53:14 -0400306 constexpr bool
307 operator()(size_t size, Iterator& begin, Iterator end, uint64_t& number) const noexcept
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000308 {
309 if (begin + size > end) {
310 return false;
311 }
312
313 switch (size) {
314 case 1: {
315 number = *begin;
316 ++begin;
317 return true;
318 }
319 case 2: {
320 uint16_t value = 0;
321 std::memcpy(&value, &*begin, 2);
322 begin += 2;
Davide Pesavento14883ad2018-07-14 16:31:39 -0400323 number = boost::endian::big_to_native(value);
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000324 return true;
325 }
326 case 4: {
327 uint32_t value = 0;
328 std::memcpy(&value, &*begin, 4);
329 begin += 4;
Davide Pesavento14883ad2018-07-14 16:31:39 -0400330 number = boost::endian::big_to_native(value);
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000331 return true;
332 }
333 case 8: {
334 uint64_t value = 0;
335 std::memcpy(&value, &*begin, 8);
336 begin += 8;
Davide Pesavento14883ad2018-07-14 16:31:39 -0400337 number = boost::endian::big_to_native(value);
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000338 return true;
339 }
340 default: {
341 BOOST_ASSERT(false);
342 return false;
343 }
344 }
345 }
346};
347
348/** @brief Determine whether to select ReadNumber implementation for ContiguousIterator
349 *
350 * This is not a full ContiguousIterator detection implementation. It returns true for the most
351 * common ContiguousIterator types used with TLV decoding function templates.
352 */
353template<typename Iterator,
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400354 typename DecayedIterator = std::decay_t<Iterator>,
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000355 typename ValueType = typename std::iterator_traits<DecayedIterator>::value_type>
356constexpr bool
357shouldSelectContiguousReadNumber()
358{
359 return (std::is_convertible<DecayedIterator, const ValueType*>::value ||
360 std::is_convertible<DecayedIterator, typename std::basic_string<ValueType>::const_iterator>::value ||
361 std::is_convertible<DecayedIterator, typename std::vector<ValueType>::const_iterator>::value) &&
Davide Pesavento4ab3be22017-07-18 00:38:52 -0400362 sizeof(ValueType) == 1 &&
363 !std::is_same<ValueType, bool>::value;
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000364}
365
366template<typename Iterator>
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400367class ReadNumber : public std::conditional_t<shouldSelectContiguousReadNumber<Iterator>(),
368 ReadNumberFast<Iterator>, ReadNumberSlow<Iterator>>
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000369{
370};
371
372} // namespace detail
373
374template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000375bool
Davide Pesavento570b20d2018-07-15 21:53:14 -0400376readVarNumber(Iterator& begin, Iterator end, uint64_t& number) noexcept
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700377{
378 if (begin == end)
379 return false;
380
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700381 uint8_t firstOctet = *begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700382 ++begin;
Junxiao Shic18aa192017-07-07 06:06:38 +0000383 if (firstOctet < 253) {
384 number = firstOctet;
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000385 return true;
Junxiao Shic18aa192017-07-07 06:06:38 +0000386 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700387
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000388 size_t size = firstOctet == 253 ? 2 :
389 firstOctet == 254 ? 4 : 8;
390 return detail::ReadNumber<Iterator>()(size, begin, end, number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700391}
392
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000393template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000394bool
Davide Pesavento570b20d2018-07-15 21:53:14 -0400395readType(Iterator& begin, Iterator end, uint32_t& type) noexcept
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700396{
Mickey Sweatt632e0572014-04-20 00:36:32 -0700397 uint64_t number = 0;
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700398 bool isOk = readVarNumber(begin, end, number);
Junxiao Shic18aa192017-07-07 06:06:38 +0000399 if (!isOk || number > std::numeric_limits<uint32_t>::max()) {
400 return false;
401 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700402
Davide Pesavento8f5cbdc2015-09-13 00:59:28 +0200403 type = static_cast<uint32_t>(number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700404 return true;
405}
406
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000407template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000408uint64_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400409readVarNumber(Iterator& begin, Iterator end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800410{
Davide Pesavento570b20d2018-07-15 21:53:14 -0400411 if (begin == end) {
412 BOOST_THROW_EXCEPTION(Error("Empty buffer during TLV parsing"));
413 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700414
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000415 uint64_t value = 0;
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700416 bool isOk = readVarNumber(begin, end, value);
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000417 if (!isOk) {
Davide Pesavento570b20d2018-07-15 21:53:14 -0400418 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV parsing"));
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000419 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700420
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700421 return value;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800422}
423
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000424template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000425uint32_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400426readType(Iterator& begin, Iterator end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800427{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700428 uint64_t type = readVarNumber(begin, end);
Junxiao Shic18aa192017-07-07 06:06:38 +0000429 if (type > std::numeric_limits<uint32_t>::max()) {
Junxiao Shi7d3c14b2017-08-05 16:34:39 +0000430 BOOST_THROW_EXCEPTION(Error("TLV-TYPE number exceeds allowed maximum"));
Junxiao Shic18aa192017-07-07 06:06:38 +0000431 }
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800432
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700433 return static_cast<uint32_t>(type);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800434}
435
Junxiao Shic18aa192017-07-07 06:06:38 +0000436constexpr size_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400437sizeOfVarNumber(uint64_t number) noexcept
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800438{
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000439 return number < 253 ? 1 :
440 number <= std::numeric_limits<uint16_t>::max() ? 3 :
441 number <= std::numeric_limits<uint32_t>::max() ? 5 : 9;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800442}
443
444inline size_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000445writeVarNumber(std::ostream& os, uint64_t number)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800446{
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000447 if (number < 253) {
448 os.put(static_cast<char>(number));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800449 return 1;
450 }
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000451 else if (number <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200452 os.put(static_cast<char>(253));
Davide Pesavento14883ad2018-07-14 16:31:39 -0400453 uint16_t value = boost::endian::native_to_big(static_cast<uint16_t>(number));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700454 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800455 return 3;
456 }
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000457 else if (number <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200458 os.put(static_cast<char>(254));
Davide Pesavento14883ad2018-07-14 16:31:39 -0400459 uint32_t value = boost::endian::native_to_big(static_cast<uint32_t>(number));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700460 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800461 return 5;
462 }
463 else {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200464 os.put(static_cast<char>(255));
Davide Pesavento14883ad2018-07-14 16:31:39 -0400465 uint64_t value = boost::endian::native_to_big(number);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700466 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800467 return 9;
468 }
469}
470
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000471template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000472uint64_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400473readNonNegativeInteger(size_t size, Iterator& begin, Iterator end)
Yingdi Yu27158392014-01-20 13:04:20 -0800474{
Junxiao Shic18aa192017-07-07 06:06:38 +0000475 if (size != 1 && size != 2 && size != 4 && size != 8) {
476 BOOST_THROW_EXCEPTION(Error("Invalid length for nonNegativeInteger "
477 "(only 1, 2, 4, and 8 are allowed)"));
Yingdi Yu27158392014-01-20 13:04:20 -0800478 }
Junxiao Shic18aa192017-07-07 06:06:38 +0000479
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000480 uint64_t number = 0;
481 bool isOk = detail::ReadNumber<Iterator>()(size, begin, end, number);
482 if (!isOk) {
Davide Pesavento570b20d2018-07-15 21:53:14 -0400483 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV parsing"));
Junxiao Shic18aa192017-07-07 06:06:38 +0000484 }
485
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000486 return number;
Junxiao Shic18aa192017-07-07 06:06:38 +0000487}
488
489constexpr size_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400490sizeOfNonNegativeInteger(uint64_t integer) noexcept
Junxiao Shic18aa192017-07-07 06:06:38 +0000491{
492 return integer <= std::numeric_limits<uint8_t>::max() ? 1 :
493 integer <= std::numeric_limits<uint16_t>::max() ? 2 :
494 integer <= std::numeric_limits<uint32_t>::max() ? 4 : 8;
Yingdi Yu27158392014-01-20 13:04:20 -0800495}
496
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800497inline size_t
Junxiao Shic18aa192017-07-07 06:06:38 +0000498writeNonNegativeInteger(std::ostream& os, uint64_t integer)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800499{
Junxiao Shic18aa192017-07-07 06:06:38 +0000500 if (integer <= std::numeric_limits<uint8_t>::max()) {
501 os.put(static_cast<char>(integer));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800502 return 1;
503 }
Junxiao Shic18aa192017-07-07 06:06:38 +0000504 else if (integer <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento14883ad2018-07-14 16:31:39 -0400505 uint16_t value = boost::endian::native_to_big(static_cast<uint16_t>(integer));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700506 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800507 return 2;
508 }
Junxiao Shic18aa192017-07-07 06:06:38 +0000509 else if (integer <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento14883ad2018-07-14 16:31:39 -0400510 uint32_t value = boost::endian::native_to_big(static_cast<uint32_t>(integer));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700511 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800512 return 4;
513 }
514 else {
Davide Pesavento14883ad2018-07-14 16:31:39 -0400515 uint64_t value = boost::endian::native_to_big(integer);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700516 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800517 return 8;
518 }
519}
520
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600521} // namespace tlv
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800522} // namespace ndn
523
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700524#endif // NDN_ENCODING_TLV_HPP