blob: d4abdc10d14ea300700d50ee1949fafae593ea8a [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 Shia2550a92018-04-10 05:07:48 +000062 Interest = 5,
63 Data = 6,
64 Name = 7,
65 GenericNameComponent = 8,
Alexander Afanasyev6486d522014-10-23 14:14:11 -070066 ImplicitSha256DigestComponent = 1,
Junxiao Shia2550a92018-04-10 05:07:48 +000067 CanBePrefix = 33,
68 MustBeFresh = 18,
69 ForwardingHint = 30,
70 Nonce = 10,
71 InterestLifetime = 12,
72 HopLimit = 34,
73 Parameters = 35,
74 MetaInfo = 20,
75 Content = 21,
76 SignatureInfo = 22,
77 SignatureValue = 23,
78 ContentType = 24,
79 FreshnessPeriod = 25,
80 FinalBlockId = 26,
81 SignatureType = 27,
82 KeyLocator = 28,
83 KeyDigest = 29,
84 LinkDelegation = 31,
85 LinkPreference = 30,
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080086
Junxiao Shicf4ac5b2018-03-28 22:46:06 +000087 NameComponentMin = 1,
88 NameComponentMax = 65535,
89
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080090 AppPrivateBlock1 = 128,
91 AppPrivateBlock2 = 32767
92};
93
Junxiao Shia2550a92018-04-10 05:07:48 +000094/** @brief TLV-TYPE numbers defined in NDN Packet Format v0.2 but not in v0.3
95 * @sa https://named-data.net/doc/NDN-packet-spec/0.2.1/types.html
96 */
97enum {
98 Selectors = 9,
99 MinSuffixComponents = 13,
100 MaxSuffixComponents = 14,
101 PublisherPublicKeyLocator = 15,
102 Exclude = 16,
103 ChildSelector = 17,
104 Any = 19,
105};
106
Davide Pesavento1fd00242018-05-20 00:11:01 -0400107[[deprecated("use GenericNameComponent")]]
108constexpr int NameComponent = GenericNameComponent;
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000109
Davide Pesavento7e6f6f82017-10-31 18:05:28 -0400110enum SignatureTypeValue : uint16_t {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800111 DigestSha256 = 0,
Yingdi Yuebfa4cb2014-06-17 15:28:53 -0700112 SignatureSha256WithRsa = 1,
Alexander Afanasyev117f5ef2015-06-03 15:07:24 -0700113 // <Unassigned> = 2,
Yingdi Yuebfa4cb2014-06-17 15:28:53 -0700114 SignatureSha256WithEcdsa = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800115};
116
Alexander Afanasyev5f1820e2017-01-04 18:12:42 -0800117std::ostream&
Davide Pesavento7e6f6f82017-10-31 18:05:28 -0400118operator<<(std::ostream& os, SignatureTypeValue signatureType);
Alexander Afanasyev5f1820e2017-01-04 18:12:42 -0800119
Junxiao Shi7d3c14b2017-08-05 16:34:39 +0000120/** @brief TLV-TYPE numbers for SignatureInfo features
Yingdi Yu7a813892015-06-09 14:19:54 -0700121 * @sa docs/tutorials/certificate-format.rst
122 */
123enum {
Yingdi Yu7a813892015-06-09 14:19:54 -0700124 ValidityPeriod = 253,
125 NotBefore = 254,
Yingdi Yuea382942015-07-17 23:20:44 -0700126 NotAfter = 255,
127
128 AdditionalDescription = 258,
129 DescriptionEntry = 512,
130 DescriptionKey = 513,
131 DescriptionValue = 514
Yingdi Yu7a813892015-06-09 14:19:54 -0700132};
133
Junxiao Shia464b922014-11-12 21:13:06 -0700134/** @brief indicates a possible value of ContentType field
135 */
Yingdi Yuebfa4cb2014-06-17 15:28:53 -0700136enum ContentTypeValue {
Junxiao Shia464b922014-11-12 21:13:06 -0700137 /** @brief indicates content is the actual data bits
138 */
139 ContentType_Blob = 0,
140
141 /** @brief indicates content is another name which identifies actual data content
142 */
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800143 ContentType_Link = 1,
Junxiao Shia464b922014-11-12 21:13:06 -0700144
145 /** @brief indicates content is a public key
146 */
147 ContentType_Key = 2,
148
149 /** @brief indicates a producer generated NACK
Junxiao Shia464b922014-11-12 21:13:06 -0700150 */
151 ContentType_Nack = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800152};
153
154/**
Junxiao Shia2550a92018-04-10 05:07:48 +0000155 * @brief Determine whether a TLV-TYPE is "critical" for evolvability purpose.
156 * @sa https://named-data.net/doc/NDN-packet-spec/0.3/tlv.html#considerations-for-evolvability-of-tlv-based-encoding
157 */
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000158constexpr bool
Junxiao Shia2550a92018-04-10 05:07:48 +0000159isCriticalType(uint32_t type)
160{
161 return type <= 31 || (type & 0x01);
162}
163
164/**
Davide Pesavento570b20d2018-07-15 21:53:14 -0400165 * @brief Read VAR-NUMBER in NDN-TLV encoding.
166 * @tparam Iterator an iterator or pointer that dereferences to uint8_t or compatible type
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800167 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000168 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
169 * the read VAR-NUMBER
170 * @param [in] end End of the buffer
171 * @param [out] number Read VAR-NUMBER
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700172 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000173 * @return true if number was successfully read from input, false otherwise
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700174 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000175template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000176bool
Davide Pesavento570b20d2018-07-15 21:53:14 -0400177readVarNumber(Iterator& begin, Iterator end, uint64_t& number) noexcept;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700178
179/**
Davide Pesavento570b20d2018-07-15 21:53:14 -0400180 * @brief Read TLV-TYPE.
181 * @tparam Iterator an iterator or pointer that dereferences to uint8_t or compatible type
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700182 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000183 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
184 * the read TLV-TYPE
185 * @param [in] end End of the buffer
186 * @param [out] type Read TLV-TYPE
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700187 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000188 * @return true if TLV-TYPE was successfully read from input, false otherwise
Davide Pesavento570b20d2018-07-15 21:53:14 -0400189 * @note This function is largely equivalent to readVarNumber(), except that it returns false if
190 * 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 -0700191 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000192template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000193bool
Davide Pesavento570b20d2018-07-15 21:53:14 -0400194readType(Iterator& begin, Iterator end, uint32_t& type) noexcept;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700195
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700196/**
Davide Pesavento570b20d2018-07-15 21:53:14 -0400197 * @brief Read VAR-NUMBER in NDN-TLV encoding.
198 * @tparam Iterator an iterator or pointer that dereferences to uint8_t or compatible type
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700199 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000200 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
201 * the read VAR-NUMBER
202 * @param [in] end End of the buffer
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800203 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000204 * @throw tlv::Error VAR-NUMBER cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800205 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000206template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000207uint64_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400208readVarNumber(Iterator& begin, Iterator end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800209
210/**
Davide Pesavento570b20d2018-07-15 21:53:14 -0400211 * @brief Read TLV-TYPE.
212 * @tparam Iterator an iterator or pointer that dereferences to uint8_t or compatible type
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800213 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000214 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
215 * the read TLV-TYPE
216 * @param [in] end End of the buffer
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700217 *
Davide Pesavento570b20d2018-07-15 21:53:14 -0400218 * @throw tlv::Error TLV-TYPE cannot be read
219 * @note This function is largely equivalent to readVarNumber(), except that it throws if
220 * 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 -0800221 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000222template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000223uint32_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400224readType(Iterator& begin, Iterator end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800225
226/**
Davide Pesavento570b20d2018-07-15 21:53:14 -0400227 * @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 -0800228 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000229constexpr size_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400230sizeOfVarNumber(uint64_t number) noexcept;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800231
232/**
Davide Pesavento570b20d2018-07-15 21:53:14 -0400233 * @brief Write VAR-NUMBER to the specified stream.
Junxiao Shic18aa192017-07-07 06:06:38 +0000234 * @return length of written VAR-NUMBER
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800235 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000236size_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000237writeVarNumber(std::ostream& os, uint64_t number);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800238
239/**
Davide Pesavento570b20d2018-07-15 21:53:14 -0400240 * @brief Read nonNegativeInteger in NDN-TLV encoding.
241 * @tparam Iterator an iterator or pointer that dereferences to uint8_t or compatible type
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800242 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000243 * @param [in] size size of the nonNegativeInteger
244 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
245 * the read nonNegativeInteger
246 * @param [in] end End of the buffer
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800247 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000248 * @throw tlv::Error number cannot be read
249 * @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 -0400250 * If \p size differs from `std::distance(begin, end)`, tlv::Error exception will be thrown.
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800251 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000252template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000253uint64_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400254readNonNegativeInteger(size_t size, Iterator& begin, Iterator end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800255
256/**
Davide Pesavento570b20d2018-07-15 21:53:14 -0400257 * @brief Get the number of bytes necessary to hold the value of @p integer encoded as nonNegativeInteger.
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800258 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000259constexpr size_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400260sizeOfNonNegativeInteger(uint64_t integer) noexcept;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800261
262/**
Davide Pesavento570b20d2018-07-15 21:53:14 -0400263 * @brief Write nonNegativeInteger to the specified stream.
Junxiao Shic18aa192017-07-07 06:06:38 +0000264 * @return length of written nonNegativeInteger
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800265 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000266size_t
267writeNonNegativeInteger(std::ostream& os, uint64_t integer);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800268
269/////////////////////////////////////////////////////////////////////////////////
270/////////////////////////////////////////////////////////////////////////////////
271/////////////////////////////////////////////////////////////////////////////////
272
Davide Pesavento4ab3be22017-07-18 00:38:52 -0400273// Inline definitions
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800274
275/////////////////////////////////////////////////////////////////////////////////
276/////////////////////////////////////////////////////////////////////////////////
277/////////////////////////////////////////////////////////////////////////////////
278
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000279namespace detail {
280
281/** @brief Function object to read a number from InputIterator
282 */
283template<typename Iterator>
284class ReadNumberSlow
285{
286public:
Davide Pesavento570b20d2018-07-15 21:53:14 -0400287 constexpr bool
288 operator()(size_t size, Iterator& begin, Iterator end, uint64_t& number) const noexcept
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000289 {
290 number = 0;
291 size_t count = 0;
292 for (; begin != end && count < size; ++begin, ++count) {
293 number = (number << 8) | *begin;
294 }
295 return count == size;
296 }
297};
298
299/** @brief Function object to read a number from ContiguousIterator
300 */
301template<typename Iterator>
302class ReadNumberFast
303{
304public:
Davide Pesavento570b20d2018-07-15 21:53:14 -0400305 constexpr bool
306 operator()(size_t size, Iterator& begin, Iterator end, uint64_t& number) const noexcept
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000307 {
308 if (begin + size > end) {
309 return false;
310 }
311
312 switch (size) {
313 case 1: {
314 number = *begin;
315 ++begin;
316 return true;
317 }
318 case 2: {
319 uint16_t value = 0;
320 std::memcpy(&value, &*begin, 2);
321 begin += 2;
Davide Pesavento14883ad2018-07-14 16:31:39 -0400322 number = boost::endian::big_to_native(value);
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000323 return true;
324 }
325 case 4: {
326 uint32_t value = 0;
327 std::memcpy(&value, &*begin, 4);
328 begin += 4;
Davide Pesavento14883ad2018-07-14 16:31:39 -0400329 number = boost::endian::big_to_native(value);
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000330 return true;
331 }
332 case 8: {
333 uint64_t value = 0;
334 std::memcpy(&value, &*begin, 8);
335 begin += 8;
Davide Pesavento14883ad2018-07-14 16:31:39 -0400336 number = boost::endian::big_to_native(value);
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000337 return true;
338 }
339 default: {
340 BOOST_ASSERT(false);
341 return false;
342 }
343 }
344 }
345};
346
347/** @brief Determine whether to select ReadNumber implementation for ContiguousIterator
348 *
349 * This is not a full ContiguousIterator detection implementation. It returns true for the most
350 * common ContiguousIterator types used with TLV decoding function templates.
351 */
352template<typename Iterator,
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400353 typename DecayedIterator = std::decay_t<Iterator>,
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000354 typename ValueType = typename std::iterator_traits<DecayedIterator>::value_type>
355constexpr bool
356shouldSelectContiguousReadNumber()
357{
358 return (std::is_convertible<DecayedIterator, const ValueType*>::value ||
359 std::is_convertible<DecayedIterator, typename std::basic_string<ValueType>::const_iterator>::value ||
360 std::is_convertible<DecayedIterator, typename std::vector<ValueType>::const_iterator>::value) &&
Davide Pesavento4ab3be22017-07-18 00:38:52 -0400361 sizeof(ValueType) == 1 &&
362 !std::is_same<ValueType, bool>::value;
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000363}
364
365template<typename Iterator>
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400366class ReadNumber : public std::conditional_t<shouldSelectContiguousReadNumber<Iterator>(),
367 ReadNumberFast<Iterator>, ReadNumberSlow<Iterator>>
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000368{
369};
370
371} // namespace detail
372
373template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000374bool
Davide Pesavento570b20d2018-07-15 21:53:14 -0400375readVarNumber(Iterator& begin, Iterator end, uint64_t& number) noexcept
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700376{
377 if (begin == end)
378 return false;
379
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700380 uint8_t firstOctet = *begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700381 ++begin;
Junxiao Shic18aa192017-07-07 06:06:38 +0000382 if (firstOctet < 253) {
383 number = firstOctet;
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000384 return true;
Junxiao Shic18aa192017-07-07 06:06:38 +0000385 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700386
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000387 size_t size = firstOctet == 253 ? 2 :
388 firstOctet == 254 ? 4 : 8;
389 return detail::ReadNumber<Iterator>()(size, begin, end, number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700390}
391
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000392template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000393bool
Davide Pesavento570b20d2018-07-15 21:53:14 -0400394readType(Iterator& begin, Iterator end, uint32_t& type) noexcept
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700395{
Mickey Sweatt632e0572014-04-20 00:36:32 -0700396 uint64_t number = 0;
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700397 bool isOk = readVarNumber(begin, end, number);
Junxiao Shic18aa192017-07-07 06:06:38 +0000398 if (!isOk || number > std::numeric_limits<uint32_t>::max()) {
399 return false;
400 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700401
Davide Pesavento8f5cbdc2015-09-13 00:59:28 +0200402 type = static_cast<uint32_t>(number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700403 return true;
404}
405
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000406template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000407uint64_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400408readVarNumber(Iterator& begin, Iterator end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800409{
Davide Pesavento570b20d2018-07-15 21:53:14 -0400410 if (begin == end) {
411 BOOST_THROW_EXCEPTION(Error("Empty buffer during TLV parsing"));
412 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700413
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000414 uint64_t value = 0;
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700415 bool isOk = readVarNumber(begin, end, value);
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000416 if (!isOk) {
Davide Pesavento570b20d2018-07-15 21:53:14 -0400417 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV parsing"));
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000418 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700419
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700420 return value;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800421}
422
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000423template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000424uint32_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400425readType(Iterator& begin, Iterator end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800426{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700427 uint64_t type = readVarNumber(begin, end);
Junxiao Shic18aa192017-07-07 06:06:38 +0000428 if (type > std::numeric_limits<uint32_t>::max()) {
Junxiao Shi7d3c14b2017-08-05 16:34:39 +0000429 BOOST_THROW_EXCEPTION(Error("TLV-TYPE number exceeds allowed maximum"));
Junxiao Shic18aa192017-07-07 06:06:38 +0000430 }
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800431
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700432 return static_cast<uint32_t>(type);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800433}
434
Junxiao Shic18aa192017-07-07 06:06:38 +0000435constexpr size_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400436sizeOfVarNumber(uint64_t number) noexcept
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800437{
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000438 return number < 253 ? 1 :
439 number <= std::numeric_limits<uint16_t>::max() ? 3 :
440 number <= std::numeric_limits<uint32_t>::max() ? 5 : 9;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800441}
442
443inline size_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000444writeVarNumber(std::ostream& os, uint64_t number)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800445{
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000446 if (number < 253) {
447 os.put(static_cast<char>(number));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800448 return 1;
449 }
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000450 else if (number <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200451 os.put(static_cast<char>(253));
Davide Pesavento14883ad2018-07-14 16:31:39 -0400452 uint16_t value = boost::endian::native_to_big(static_cast<uint16_t>(number));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700453 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800454 return 3;
455 }
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000456 else if (number <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200457 os.put(static_cast<char>(254));
Davide Pesavento14883ad2018-07-14 16:31:39 -0400458 uint32_t value = boost::endian::native_to_big(static_cast<uint32_t>(number));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700459 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800460 return 5;
461 }
462 else {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200463 os.put(static_cast<char>(255));
Davide Pesavento14883ad2018-07-14 16:31:39 -0400464 uint64_t value = boost::endian::native_to_big(number);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700465 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800466 return 9;
467 }
468}
469
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000470template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000471uint64_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400472readNonNegativeInteger(size_t size, Iterator& begin, Iterator end)
Yingdi Yu27158392014-01-20 13:04:20 -0800473{
Junxiao Shic18aa192017-07-07 06:06:38 +0000474 if (size != 1 && size != 2 && size != 4 && size != 8) {
475 BOOST_THROW_EXCEPTION(Error("Invalid length for nonNegativeInteger "
476 "(only 1, 2, 4, and 8 are allowed)"));
Yingdi Yu27158392014-01-20 13:04:20 -0800477 }
Junxiao Shic18aa192017-07-07 06:06:38 +0000478
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000479 uint64_t number = 0;
480 bool isOk = detail::ReadNumber<Iterator>()(size, begin, end, number);
481 if (!isOk) {
Davide Pesavento570b20d2018-07-15 21:53:14 -0400482 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV parsing"));
Junxiao Shic18aa192017-07-07 06:06:38 +0000483 }
484
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000485 return number;
Junxiao Shic18aa192017-07-07 06:06:38 +0000486}
487
488constexpr size_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400489sizeOfNonNegativeInteger(uint64_t integer) noexcept
Junxiao Shic18aa192017-07-07 06:06:38 +0000490{
491 return integer <= std::numeric_limits<uint8_t>::max() ? 1 :
492 integer <= std::numeric_limits<uint16_t>::max() ? 2 :
493 integer <= std::numeric_limits<uint32_t>::max() ? 4 : 8;
Yingdi Yu27158392014-01-20 13:04:20 -0800494}
495
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800496inline size_t
Junxiao Shic18aa192017-07-07 06:06:38 +0000497writeNonNegativeInteger(std::ostream& os, uint64_t integer)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800498{
Junxiao Shic18aa192017-07-07 06:06:38 +0000499 if (integer <= std::numeric_limits<uint8_t>::max()) {
500 os.put(static_cast<char>(integer));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800501 return 1;
502 }
Junxiao Shic18aa192017-07-07 06:06:38 +0000503 else if (integer <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento14883ad2018-07-14 16:31:39 -0400504 uint16_t value = boost::endian::native_to_big(static_cast<uint16_t>(integer));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700505 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800506 return 2;
507 }
Junxiao Shic18aa192017-07-07 06:06:38 +0000508 else if (integer <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento14883ad2018-07-14 16:31:39 -0400509 uint32_t value = boost::endian::native_to_big(static_cast<uint32_t>(integer));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700510 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800511 return 4;
512 }
513 else {
Davide Pesavento14883ad2018-07-14 16:31:39 -0400514 uint64_t value = boost::endian::native_to_big(integer);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700515 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800516 return 8;
517 }
518}
519
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600520} // namespace tlv
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800521} // namespace ndn
522
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700523#endif // NDN_ENCODING_TLV_HPP