blob: c105b70b00ffefeca7bf16d683da65028474a054 [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
Junxiao Shi426d5002018-08-23 10:52:29 +0000111/** @brief TLV-TYPE numbers for typed name components.
112 * @sa https://redmine.named-data.net/projects/ndn-tlv/wiki/NameComponentType
113 */
114enum {
115 KeywordNameComponent = 32,
116 SegmentNameComponent = 33,
117 ByteOffsetNameComponent = 34,
118 VersionNameComponent = 35,
119 TimestampNameComponent = 36,
120 SequenceNumNameComponent = 37,
121};
122
123/** @brief SignatureType values
124 * @sa https://named-data.net/doc/NDN-packet-spec/current/signature.html
125 */
Davide Pesavento7e6f6f82017-10-31 18:05:28 -0400126enum SignatureTypeValue : uint16_t {
Junxiao Shi426d5002018-08-23 10:52:29 +0000127 DigestSha256 = 0,
128 SignatureSha256WithRsa = 1,
129 SignatureSha256WithEcdsa = 3,
130 SignatureHmacWithSha256 = 4,
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800131};
132
Alexander Afanasyev5f1820e2017-01-04 18:12:42 -0800133std::ostream&
Junxiao Shi426d5002018-08-23 10:52:29 +0000134operator<<(std::ostream& os, SignatureTypeValue st);
Alexander Afanasyev5f1820e2017-01-04 18:12:42 -0800135
Junxiao Shi7d3c14b2017-08-05 16:34:39 +0000136/** @brief TLV-TYPE numbers for SignatureInfo features
Junxiao Shi426d5002018-08-23 10:52:29 +0000137 * @sa docs/specs/certificate-format.rst
Yingdi Yu7a813892015-06-09 14:19:54 -0700138 */
139enum {
Yingdi Yu7a813892015-06-09 14:19:54 -0700140 ValidityPeriod = 253,
141 NotBefore = 254,
Yingdi Yuea382942015-07-17 23:20:44 -0700142 NotAfter = 255,
143
144 AdditionalDescription = 258,
145 DescriptionEntry = 512,
146 DescriptionKey = 513,
147 DescriptionValue = 514
Yingdi Yu7a813892015-06-09 14:19:54 -0700148};
149
Junxiao Shi426d5002018-08-23 10:52:29 +0000150/** @brief ContentType values
151 * @sa https://redmine.named-data.net/projects/ndn-tlv/wiki/ContentType
Junxiao Shia464b922014-11-12 21:13:06 -0700152 */
Junxiao Shi426d5002018-08-23 10:52:29 +0000153enum ContentTypeValue : uint32_t {
154 ContentType_Blob = 0, ///< payload
155 ContentType_Link = 1, ///< another name that identifies the actual data content
156 ContentType_Key = 2, ///< public key, certificate
157 ContentType_Nack = 3, ///< application-level nack
158 ContentType_Manifest = 4,
159 ContentType_PrefixAnn = 5, ///< prefix announcement
160 ContentType_Flic = 1024, ///< File-Like ICN Collection
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800161};
162
Junxiao Shi426d5002018-08-23 10:52:29 +0000163std::ostream&
164operator<<(std::ostream& os, ContentTypeValue ct);
165
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800166/**
Junxiao Shia2550a92018-04-10 05:07:48 +0000167 * @brief Determine whether a TLV-TYPE is "critical" for evolvability purpose.
168 * @sa https://named-data.net/doc/NDN-packet-spec/0.3/tlv.html#considerations-for-evolvability-of-tlv-based-encoding
169 */
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000170constexpr bool
Junxiao Shia2550a92018-04-10 05:07:48 +0000171isCriticalType(uint32_t type)
172{
173 return type <= 31 || (type & 0x01);
174}
175
176/**
Davide Pesavento570b20d2018-07-15 21:53:14 -0400177 * @brief Read VAR-NUMBER in NDN-TLV encoding.
178 * @tparam Iterator an iterator or pointer that dereferences to uint8_t or compatible type
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800179 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000180 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
181 * the read VAR-NUMBER
182 * @param [in] end End of the buffer
183 * @param [out] number Read VAR-NUMBER
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700184 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000185 * @return true if number was successfully read from input, false otherwise
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700186 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000187template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000188bool
Davide Pesavento570b20d2018-07-15 21:53:14 -0400189readVarNumber(Iterator& begin, Iterator end, uint64_t& number) noexcept;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700190
191/**
Davide Pesavento570b20d2018-07-15 21:53:14 -0400192 * @brief Read TLV-TYPE.
193 * @tparam Iterator an iterator or pointer that dereferences to uint8_t or compatible type
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700194 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000195 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
196 * the read TLV-TYPE
197 * @param [in] end End of the buffer
198 * @param [out] type Read TLV-TYPE
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700199 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000200 * @return true if TLV-TYPE was successfully read from input, false otherwise
Davide Pesavento570b20d2018-07-15 21:53:14 -0400201 * @note This function is largely equivalent to readVarNumber(), except that it returns false if
202 * 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 -0700203 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000204template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000205bool
Davide Pesavento570b20d2018-07-15 21:53:14 -0400206readType(Iterator& begin, Iterator end, uint32_t& type) noexcept;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700207
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700208/**
Davide Pesavento570b20d2018-07-15 21:53:14 -0400209 * @brief Read VAR-NUMBER in NDN-TLV encoding.
210 * @tparam Iterator an iterator or pointer that dereferences to uint8_t or compatible type
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700211 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000212 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
213 * the read VAR-NUMBER
214 * @param [in] end End of the buffer
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800215 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000216 * @throw tlv::Error VAR-NUMBER cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800217 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000218template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000219uint64_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400220readVarNumber(Iterator& begin, Iterator end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800221
222/**
Davide Pesavento570b20d2018-07-15 21:53:14 -0400223 * @brief Read TLV-TYPE.
224 * @tparam Iterator an iterator or pointer that dereferences to uint8_t or compatible type
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800225 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000226 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
227 * the read TLV-TYPE
228 * @param [in] end End of the buffer
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700229 *
Davide Pesavento570b20d2018-07-15 21:53:14 -0400230 * @throw tlv::Error TLV-TYPE cannot be read
231 * @note This function is largely equivalent to readVarNumber(), except that it throws if
232 * 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 -0800233 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000234template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000235uint32_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400236readType(Iterator& begin, Iterator end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800237
238/**
Davide Pesavento570b20d2018-07-15 21:53:14 -0400239 * @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 -0800240 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000241constexpr size_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400242sizeOfVarNumber(uint64_t number) noexcept;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800243
244/**
Davide Pesavento570b20d2018-07-15 21:53:14 -0400245 * @brief Write VAR-NUMBER to the specified stream.
Junxiao Shic18aa192017-07-07 06:06:38 +0000246 * @return length of written VAR-NUMBER
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800247 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000248size_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000249writeVarNumber(std::ostream& os, uint64_t number);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800250
251/**
Davide Pesavento570b20d2018-07-15 21:53:14 -0400252 * @brief Read nonNegativeInteger in NDN-TLV encoding.
253 * @tparam Iterator an iterator or pointer that dereferences to uint8_t or compatible type
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800254 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000255 * @param [in] size size of the nonNegativeInteger
256 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
257 * the read nonNegativeInteger
258 * @param [in] end End of the buffer
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800259 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000260 * @throw tlv::Error number cannot be read
261 * @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 -0400262 * If \p size differs from `std::distance(begin, end)`, tlv::Error exception will be thrown.
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800263 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000264template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000265uint64_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400266readNonNegativeInteger(size_t size, Iterator& begin, Iterator end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800267
268/**
Davide Pesavento570b20d2018-07-15 21:53:14 -0400269 * @brief Get the number of bytes necessary to hold the value of @p integer encoded as nonNegativeInteger.
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800270 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000271constexpr size_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400272sizeOfNonNegativeInteger(uint64_t integer) noexcept;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800273
274/**
Davide Pesavento570b20d2018-07-15 21:53:14 -0400275 * @brief Write nonNegativeInteger to the specified stream.
Junxiao Shic18aa192017-07-07 06:06:38 +0000276 * @return length of written nonNegativeInteger
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800277 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000278size_t
279writeNonNegativeInteger(std::ostream& os, uint64_t integer);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800280
281/////////////////////////////////////////////////////////////////////////////////
282/////////////////////////////////////////////////////////////////////////////////
283/////////////////////////////////////////////////////////////////////////////////
284
Davide Pesavento4ab3be22017-07-18 00:38:52 -0400285// Inline definitions
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800286
287/////////////////////////////////////////////////////////////////////////////////
288/////////////////////////////////////////////////////////////////////////////////
289/////////////////////////////////////////////////////////////////////////////////
290
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000291namespace detail {
292
293/** @brief Function object to read a number from InputIterator
294 */
295template<typename Iterator>
296class ReadNumberSlow
297{
298public:
Davide Pesavento570b20d2018-07-15 21:53:14 -0400299 constexpr bool
300 operator()(size_t size, Iterator& begin, Iterator end, uint64_t& number) const noexcept
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000301 {
302 number = 0;
303 size_t count = 0;
304 for (; begin != end && count < size; ++begin, ++count) {
305 number = (number << 8) | *begin;
306 }
307 return count == size;
308 }
309};
310
311/** @brief Function object to read a number from ContiguousIterator
312 */
313template<typename Iterator>
314class ReadNumberFast
315{
316public:
Davide Pesavento570b20d2018-07-15 21:53:14 -0400317 constexpr bool
318 operator()(size_t size, Iterator& begin, Iterator end, uint64_t& number) const noexcept
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000319 {
320 if (begin + size > end) {
321 return false;
322 }
323
324 switch (size) {
325 case 1: {
326 number = *begin;
327 ++begin;
328 return true;
329 }
330 case 2: {
331 uint16_t value = 0;
332 std::memcpy(&value, &*begin, 2);
333 begin += 2;
Davide Pesavento14883ad2018-07-14 16:31:39 -0400334 number = boost::endian::big_to_native(value);
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000335 return true;
336 }
337 case 4: {
338 uint32_t value = 0;
339 std::memcpy(&value, &*begin, 4);
340 begin += 4;
Davide Pesavento14883ad2018-07-14 16:31:39 -0400341 number = boost::endian::big_to_native(value);
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000342 return true;
343 }
344 case 8: {
345 uint64_t value = 0;
346 std::memcpy(&value, &*begin, 8);
347 begin += 8;
Davide Pesavento14883ad2018-07-14 16:31:39 -0400348 number = boost::endian::big_to_native(value);
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000349 return true;
350 }
351 default: {
352 BOOST_ASSERT(false);
353 return false;
354 }
355 }
356 }
357};
358
359/** @brief Determine whether to select ReadNumber implementation for ContiguousIterator
360 *
361 * This is not a full ContiguousIterator detection implementation. It returns true for the most
362 * common ContiguousIterator types used with TLV decoding function templates.
363 */
364template<typename Iterator,
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400365 typename DecayedIterator = std::decay_t<Iterator>,
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000366 typename ValueType = typename std::iterator_traits<DecayedIterator>::value_type>
367constexpr bool
368shouldSelectContiguousReadNumber()
369{
370 return (std::is_convertible<DecayedIterator, const ValueType*>::value ||
371 std::is_convertible<DecayedIterator, typename std::basic_string<ValueType>::const_iterator>::value ||
372 std::is_convertible<DecayedIterator, typename std::vector<ValueType>::const_iterator>::value) &&
Davide Pesavento4ab3be22017-07-18 00:38:52 -0400373 sizeof(ValueType) == 1 &&
374 !std::is_same<ValueType, bool>::value;
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000375}
376
377template<typename Iterator>
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400378class ReadNumber : public std::conditional_t<shouldSelectContiguousReadNumber<Iterator>(),
379 ReadNumberFast<Iterator>, ReadNumberSlow<Iterator>>
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000380{
381};
382
383} // namespace detail
384
385template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000386bool
Davide Pesavento570b20d2018-07-15 21:53:14 -0400387readVarNumber(Iterator& begin, Iterator end, uint64_t& number) noexcept
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700388{
389 if (begin == end)
390 return false;
391
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700392 uint8_t firstOctet = *begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700393 ++begin;
Junxiao Shic18aa192017-07-07 06:06:38 +0000394 if (firstOctet < 253) {
395 number = firstOctet;
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000396 return true;
Junxiao Shic18aa192017-07-07 06:06:38 +0000397 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700398
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000399 size_t size = firstOctet == 253 ? 2 :
400 firstOctet == 254 ? 4 : 8;
401 return detail::ReadNumber<Iterator>()(size, begin, end, number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700402}
403
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000404template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000405bool
Davide Pesavento570b20d2018-07-15 21:53:14 -0400406readType(Iterator& begin, Iterator end, uint32_t& type) noexcept
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700407{
Mickey Sweatt632e0572014-04-20 00:36:32 -0700408 uint64_t number = 0;
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700409 bool isOk = readVarNumber(begin, end, number);
Junxiao Shic18aa192017-07-07 06:06:38 +0000410 if (!isOk || number > std::numeric_limits<uint32_t>::max()) {
411 return false;
412 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700413
Davide Pesavento8f5cbdc2015-09-13 00:59:28 +0200414 type = static_cast<uint32_t>(number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700415 return true;
416}
417
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000418template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000419uint64_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400420readVarNumber(Iterator& begin, Iterator end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800421{
Davide Pesavento570b20d2018-07-15 21:53:14 -0400422 if (begin == end) {
423 BOOST_THROW_EXCEPTION(Error("Empty buffer during TLV parsing"));
424 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700425
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000426 uint64_t value = 0;
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700427 bool isOk = readVarNumber(begin, end, value);
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000428 if (!isOk) {
Davide Pesavento570b20d2018-07-15 21:53:14 -0400429 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV parsing"));
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000430 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700431
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700432 return value;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800433}
434
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000435template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000436uint32_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400437readType(Iterator& begin, Iterator end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800438{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700439 uint64_t type = readVarNumber(begin, end);
Junxiao Shic18aa192017-07-07 06:06:38 +0000440 if (type > std::numeric_limits<uint32_t>::max()) {
Junxiao Shi7d3c14b2017-08-05 16:34:39 +0000441 BOOST_THROW_EXCEPTION(Error("TLV-TYPE number exceeds allowed maximum"));
Junxiao Shic18aa192017-07-07 06:06:38 +0000442 }
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800443
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700444 return static_cast<uint32_t>(type);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800445}
446
Junxiao Shic18aa192017-07-07 06:06:38 +0000447constexpr size_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400448sizeOfVarNumber(uint64_t number) noexcept
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800449{
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000450 return number < 253 ? 1 :
451 number <= std::numeric_limits<uint16_t>::max() ? 3 :
452 number <= std::numeric_limits<uint32_t>::max() ? 5 : 9;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800453}
454
455inline size_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000456writeVarNumber(std::ostream& os, uint64_t number)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800457{
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000458 if (number < 253) {
459 os.put(static_cast<char>(number));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800460 return 1;
461 }
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000462 else if (number <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200463 os.put(static_cast<char>(253));
Davide Pesavento14883ad2018-07-14 16:31:39 -0400464 uint16_t value = boost::endian::native_to_big(static_cast<uint16_t>(number));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700465 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800466 return 3;
467 }
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000468 else if (number <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200469 os.put(static_cast<char>(254));
Davide Pesavento14883ad2018-07-14 16:31:39 -0400470 uint32_t value = boost::endian::native_to_big(static_cast<uint32_t>(number));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700471 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800472 return 5;
473 }
474 else {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200475 os.put(static_cast<char>(255));
Davide Pesavento14883ad2018-07-14 16:31:39 -0400476 uint64_t value = boost::endian::native_to_big(number);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700477 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800478 return 9;
479 }
480}
481
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000482template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000483uint64_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400484readNonNegativeInteger(size_t size, Iterator& begin, Iterator end)
Yingdi Yu27158392014-01-20 13:04:20 -0800485{
Junxiao Shic18aa192017-07-07 06:06:38 +0000486 if (size != 1 && size != 2 && size != 4 && size != 8) {
487 BOOST_THROW_EXCEPTION(Error("Invalid length for nonNegativeInteger "
488 "(only 1, 2, 4, and 8 are allowed)"));
Yingdi Yu27158392014-01-20 13:04:20 -0800489 }
Junxiao Shic18aa192017-07-07 06:06:38 +0000490
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000491 uint64_t number = 0;
492 bool isOk = detail::ReadNumber<Iterator>()(size, begin, end, number);
493 if (!isOk) {
Davide Pesavento570b20d2018-07-15 21:53:14 -0400494 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV parsing"));
Junxiao Shic18aa192017-07-07 06:06:38 +0000495 }
496
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000497 return number;
Junxiao Shic18aa192017-07-07 06:06:38 +0000498}
499
500constexpr size_t
Davide Pesavento570b20d2018-07-15 21:53:14 -0400501sizeOfNonNegativeInteger(uint64_t integer) noexcept
Junxiao Shic18aa192017-07-07 06:06:38 +0000502{
503 return integer <= std::numeric_limits<uint8_t>::max() ? 1 :
504 integer <= std::numeric_limits<uint16_t>::max() ? 2 :
505 integer <= std::numeric_limits<uint32_t>::max() ? 4 : 8;
Yingdi Yu27158392014-01-20 13:04:20 -0800506}
507
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800508inline size_t
Junxiao Shic18aa192017-07-07 06:06:38 +0000509writeNonNegativeInteger(std::ostream& os, uint64_t integer)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800510{
Junxiao Shic18aa192017-07-07 06:06:38 +0000511 if (integer <= std::numeric_limits<uint8_t>::max()) {
512 os.put(static_cast<char>(integer));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800513 return 1;
514 }
Junxiao Shic18aa192017-07-07 06:06:38 +0000515 else if (integer <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento14883ad2018-07-14 16:31:39 -0400516 uint16_t value = boost::endian::native_to_big(static_cast<uint16_t>(integer));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700517 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800518 return 2;
519 }
Junxiao Shic18aa192017-07-07 06:06:38 +0000520 else if (integer <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento14883ad2018-07-14 16:31:39 -0400521 uint32_t value = boost::endian::native_to_big(static_cast<uint32_t>(integer));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700522 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800523 return 4;
524 }
525 else {
Davide Pesavento14883ad2018-07-14 16:31:39 -0400526 uint64_t value = boost::endian::native_to_big(integer);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700527 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800528 return 8;
529 }
530}
531
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600532} // namespace tlv
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800533} // namespace ndn
534
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700535#endif // NDN_ENCODING_TLV_HPP