blob: 5fb2b2486be58dee31c028268f038870ab231aca [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
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080025#include "buffer.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 Pesaventoe1789892017-02-26 15:50:52 -050031
Davide Pesavento14883ad2018-07-14 16:31:39 -040032#include <boost/endian/conversion.hpp>
33
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080034namespace ndn {
35
Junxiao Shi468abc32014-11-04 09:12:47 -070036/** @brief practical limit of network layer packet size
37 *
38 * If a packet is longer than this size, library and application MAY drop it.
39 */
40const size_t MAX_NDN_PACKET_SIZE = 8800;
41
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080042/**
Junxiao Shia2550a92018-04-10 05:07:48 +000043 * @brief Namespace defining NDN Packet Format related constants and procedures
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080044 */
Steve DiBenedetto54ce6682014-07-22 13:22:57 -060045namespace tlv {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080046
Junxiao Shi468abc32014-11-04 09:12:47 -070047/** @brief represents an error in TLV encoding or decoding
48 *
49 * Element::Error SHOULD inherit from this Error class.
50 */
Alexander Afanasyeva465e972014-03-22 17:21:49 -070051class Error : public std::runtime_error
52{
53public:
54 explicit
55 Error(const std::string& what)
56 : std::runtime_error(what)
57 {
58 }
59};
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080060
Junxiao Shia2550a92018-04-10 05:07:48 +000061/** @brief TLV-TYPE numbers defined in NDN Packet Format v0.3
62 * @sa https://named-data.net/doc/NDN-packet-spec/current/types.html
Junxiao Shi7d3c14b2017-08-05 16:34:39 +000063 */
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080064enum {
Junxiao Shia2550a92018-04-10 05:07:48 +000065 Interest = 5,
66 Data = 6,
67 Name = 7,
68 GenericNameComponent = 8,
Alexander Afanasyev6486d522014-10-23 14:14:11 -070069 ImplicitSha256DigestComponent = 1,
Junxiao Shia2550a92018-04-10 05:07:48 +000070 CanBePrefix = 33,
71 MustBeFresh = 18,
72 ForwardingHint = 30,
73 Nonce = 10,
74 InterestLifetime = 12,
75 HopLimit = 34,
76 Parameters = 35,
77 MetaInfo = 20,
78 Content = 21,
79 SignatureInfo = 22,
80 SignatureValue = 23,
81 ContentType = 24,
82 FreshnessPeriod = 25,
83 FinalBlockId = 26,
84 SignatureType = 27,
85 KeyLocator = 28,
86 KeyDigest = 29,
87 LinkDelegation = 31,
88 LinkPreference = 30,
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080089
Junxiao Shicf4ac5b2018-03-28 22:46:06 +000090 NameComponentMin = 1,
91 NameComponentMax = 65535,
92
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080093 AppPrivateBlock1 = 128,
94 AppPrivateBlock2 = 32767
95};
96
Junxiao Shia2550a92018-04-10 05:07:48 +000097/** @brief TLV-TYPE numbers defined in NDN Packet Format v0.2 but not in v0.3
98 * @sa https://named-data.net/doc/NDN-packet-spec/0.2.1/types.html
99 */
100enum {
101 Selectors = 9,
102 MinSuffixComponents = 13,
103 MaxSuffixComponents = 14,
104 PublisherPublicKeyLocator = 15,
105 Exclude = 16,
106 ChildSelector = 17,
107 Any = 19,
108};
109
Davide Pesavento1fd00242018-05-20 00:11:01 -0400110[[deprecated("use GenericNameComponent")]]
111constexpr int NameComponent = GenericNameComponent;
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000112
Davide Pesavento7e6f6f82017-10-31 18:05:28 -0400113enum SignatureTypeValue : uint16_t {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800114 DigestSha256 = 0,
Yingdi Yuebfa4cb2014-06-17 15:28:53 -0700115 SignatureSha256WithRsa = 1,
Alexander Afanasyev117f5ef2015-06-03 15:07:24 -0700116 // <Unassigned> = 2,
Yingdi Yuebfa4cb2014-06-17 15:28:53 -0700117 SignatureSha256WithEcdsa = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800118};
119
Alexander Afanasyev5f1820e2017-01-04 18:12:42 -0800120std::ostream&
Davide Pesavento7e6f6f82017-10-31 18:05:28 -0400121operator<<(std::ostream& os, SignatureTypeValue signatureType);
Alexander Afanasyev5f1820e2017-01-04 18:12:42 -0800122
Junxiao Shi7d3c14b2017-08-05 16:34:39 +0000123/** @brief TLV-TYPE numbers for SignatureInfo features
Yingdi Yu7a813892015-06-09 14:19:54 -0700124 * @sa docs/tutorials/certificate-format.rst
125 */
126enum {
Yingdi Yu7a813892015-06-09 14:19:54 -0700127 ValidityPeriod = 253,
128 NotBefore = 254,
Yingdi Yuea382942015-07-17 23:20:44 -0700129 NotAfter = 255,
130
131 AdditionalDescription = 258,
132 DescriptionEntry = 512,
133 DescriptionKey = 513,
134 DescriptionValue = 514
Yingdi Yu7a813892015-06-09 14:19:54 -0700135};
136
Junxiao Shia464b922014-11-12 21:13:06 -0700137/** @brief indicates a possible value of ContentType field
138 */
Yingdi Yuebfa4cb2014-06-17 15:28:53 -0700139enum ContentTypeValue {
Junxiao Shia464b922014-11-12 21:13:06 -0700140 /** @brief indicates content is the actual data bits
141 */
142 ContentType_Blob = 0,
143
144 /** @brief indicates content is another name which identifies actual data content
145 */
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800146 ContentType_Link = 1,
Junxiao Shia464b922014-11-12 21:13:06 -0700147
148 /** @brief indicates content is a public key
149 */
150 ContentType_Key = 2,
151
152 /** @brief indicates a producer generated NACK
Junxiao Shia464b922014-11-12 21:13:06 -0700153 */
154 ContentType_Nack = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800155};
156
157/**
Junxiao Shia2550a92018-04-10 05:07:48 +0000158 * @brief Determine whether a TLV-TYPE is "critical" for evolvability purpose.
159 * @sa https://named-data.net/doc/NDN-packet-spec/0.3/tlv.html#considerations-for-evolvability-of-tlv-based-encoding
160 */
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000161constexpr bool
Junxiao Shia2550a92018-04-10 05:07:48 +0000162isCriticalType(uint32_t type)
163{
164 return type <= 31 || (type & 0x01);
165}
166
167/**
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800168 * @brief Read VAR-NUMBER in NDN-TLV encoding
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000169 * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800170 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000171 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
172 * the read VAR-NUMBER
173 * @param [in] end End of the buffer
174 * @param [out] number Read VAR-NUMBER
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700175 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000176 * @return true if number was successfully read from input, false otherwise
177 * @note This call never throws exceptions
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
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000181readVarNumber(Iterator& begin, const Iterator& end, uint64_t& number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700182
183/**
Junxiao Shic18aa192017-07-07 06:06:38 +0000184 * @brief Read TLV-TYPE
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000185 * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
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
193 * @note This call never throws exceptions
194 * @note This call is largely equivalent to tlv::readVarNumber, but it will return false if type
195 * is larger than 2^32-1 (TLV-TYPE in this library is implemented as uint32_t)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700196 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000197template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000198bool
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000199readType(Iterator& begin, const Iterator& end, uint32_t& type);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700200
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700201/**
202 * @brief Read VAR-NUMBER in NDN-TLV encoding
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000203 * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700204 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000205 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
206 * the read VAR-NUMBER
207 * @param [in] end End of the buffer
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800208 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000209 * @throw tlv::Error VAR-NUMBER cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800210 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000211template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000212uint64_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000213readVarNumber(Iterator& begin, const Iterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800214
215/**
216 * @brief Read TLV Type
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000217 * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800218 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000219 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
220 * the read TLV-TYPE
221 * @param [in] end End of the buffer
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700222 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000223 * @throw tlv::Error VAR-NUMBER cannot be read
224 * @note This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
225 * is larger than 2^32-1 (TLV-TYPE in this library is implemented as uint32_t)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800226 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000227template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000228uint32_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000229readType(Iterator& begin, const Iterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800230
231/**
232 * @brief Get number of bytes necessary to hold value of VAR-NUMBER
233 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000234constexpr size_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000235sizeOfVarNumber(uint64_t number);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800236
237/**
238 * @brief Write VAR-NUMBER to the specified stream
Junxiao Shic18aa192017-07-07 06:06:38 +0000239 * @return length of written VAR-NUMBER
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800240 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000241size_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000242writeVarNumber(std::ostream& os, uint64_t number);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800243
244/**
245 * @brief Read nonNegativeInteger in NDN-TLV encoding
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000246 * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800247 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000248 * @param [in] size size of the nonNegativeInteger
249 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
250 * the read nonNegativeInteger
251 * @param [in] end End of the buffer
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800252 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000253 * @throw tlv::Error number cannot be read
254 * @note How many bytes to read is directly controlled by \p size, which can be either 1, 2, 4, or 8.
255 * If \p size differs from \p std::distance(begin, end), tlv::Error exception will be thrown.
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800256 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000257template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000258uint64_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000259readNonNegativeInteger(size_t size, Iterator& begin, const Iterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800260
261/**
262 * @brief Get number of bytes necessary to hold value of nonNegativeInteger
263 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000264constexpr size_t
265sizeOfNonNegativeInteger(uint64_t integer);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800266
267/**
268 * @brief Write nonNegativeInteger to the specified stream
Junxiao Shic18aa192017-07-07 06:06:38 +0000269 * @return length of written nonNegativeInteger
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800270 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000271size_t
272writeNonNegativeInteger(std::ostream& os, uint64_t integer);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800273
274/////////////////////////////////////////////////////////////////////////////////
275/////////////////////////////////////////////////////////////////////////////////
276/////////////////////////////////////////////////////////////////////////////////
277
Davide Pesavento4ab3be22017-07-18 00:38:52 -0400278// Inline definitions
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800279
280/////////////////////////////////////////////////////////////////////////////////
281/////////////////////////////////////////////////////////////////////////////////
282/////////////////////////////////////////////////////////////////////////////////
283
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000284namespace detail {
285
286/** @brief Function object to read a number from InputIterator
287 */
288template<typename Iterator>
289class ReadNumberSlow
290{
291public:
292 bool
293 operator()(size_t size, Iterator& begin, const Iterator& end, uint64_t& number) const
294 {
295 number = 0;
296 size_t count = 0;
297 for (; begin != end && count < size; ++begin, ++count) {
298 number = (number << 8) | *begin;
299 }
300 return count == size;
301 }
302};
303
304/** @brief Function object to read a number from ContiguousIterator
305 */
306template<typename Iterator>
307class ReadNumberFast
308{
309public:
310 bool
311 operator()(size_t size, Iterator& begin, const Iterator& end, uint64_t& number) const
312 {
313 if (begin + size > end) {
314 return false;
315 }
316
317 switch (size) {
318 case 1: {
319 number = *begin;
320 ++begin;
321 return true;
322 }
323 case 2: {
324 uint16_t value = 0;
325 std::memcpy(&value, &*begin, 2);
326 begin += 2;
Davide Pesavento14883ad2018-07-14 16:31:39 -0400327 number = boost::endian::big_to_native(value);
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000328 return true;
329 }
330 case 4: {
331 uint32_t value = 0;
332 std::memcpy(&value, &*begin, 4);
333 begin += 4;
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 8: {
338 uint64_t value = 0;
339 std::memcpy(&value, &*begin, 8);
340 begin += 8;
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 default: {
345 BOOST_ASSERT(false);
346 return false;
347 }
348 }
349 }
350};
351
352/** @brief Determine whether to select ReadNumber implementation for ContiguousIterator
353 *
354 * This is not a full ContiguousIterator detection implementation. It returns true for the most
355 * common ContiguousIterator types used with TLV decoding function templates.
356 */
357template<typename Iterator,
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400358 typename DecayedIterator = std::decay_t<Iterator>,
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000359 typename ValueType = typename std::iterator_traits<DecayedIterator>::value_type>
360constexpr bool
361shouldSelectContiguousReadNumber()
362{
363 return (std::is_convertible<DecayedIterator, const ValueType*>::value ||
364 std::is_convertible<DecayedIterator, typename std::basic_string<ValueType>::const_iterator>::value ||
365 std::is_convertible<DecayedIterator, typename std::vector<ValueType>::const_iterator>::value) &&
Davide Pesavento4ab3be22017-07-18 00:38:52 -0400366 sizeof(ValueType) == 1 &&
367 !std::is_same<ValueType, bool>::value;
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000368}
369
370template<typename Iterator>
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400371class ReadNumber : public std::conditional_t<shouldSelectContiguousReadNumber<Iterator>(),
372 ReadNumberFast<Iterator>, ReadNumberSlow<Iterator>>
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000373{
374};
375
376} // namespace detail
377
378template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000379bool
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000380readVarNumber(Iterator& begin, const Iterator& end, uint64_t& number)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700381{
382 if (begin == end)
383 return false;
384
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700385 uint8_t firstOctet = *begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700386 ++begin;
Junxiao Shic18aa192017-07-07 06:06:38 +0000387 if (firstOctet < 253) {
388 number = firstOctet;
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000389 return true;
Junxiao Shic18aa192017-07-07 06:06:38 +0000390 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700391
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000392 size_t size = firstOctet == 253 ? 2 :
393 firstOctet == 254 ? 4 : 8;
394 return detail::ReadNumber<Iterator>()(size, begin, end, number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700395}
396
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000397template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000398bool
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000399readType(Iterator& begin, const Iterator& end, uint32_t& type)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700400{
Mickey Sweatt632e0572014-04-20 00:36:32 -0700401 uint64_t number = 0;
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700402 bool isOk = readVarNumber(begin, end, number);
Junxiao Shic18aa192017-07-07 06:06:38 +0000403 if (!isOk || number > std::numeric_limits<uint32_t>::max()) {
404 return false;
405 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700406
Davide Pesavento8f5cbdc2015-09-13 00:59:28 +0200407 type = static_cast<uint32_t>(number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700408 return true;
409}
410
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000411template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000412uint64_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000413readVarNumber(Iterator& begin, const Iterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800414{
415 if (begin == end)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700416 BOOST_THROW_EXCEPTION(Error("Empty buffer during TLV processing"));
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) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700421 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
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
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000429readType(Iterator& begin, const 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
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000440sizeOfVarNumber(uint64_t number)
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
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000476readNonNegativeInteger(size_t size, Iterator& begin, const 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) {
Junxiao Shic18aa192017-07-07 06:06:38 +0000486 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
487 }
488
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000489 return number;
Junxiao Shic18aa192017-07-07 06:06:38 +0000490}
491
492constexpr size_t
493sizeOfNonNegativeInteger(uint64_t integer)
494{
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