blob: 6a14a7ce7bdb8c7dd5cea21a94a0fb3c856eb09e [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 Afanasyev200dd6f2014-01-28 19:04:25 -080026#include "endian.hpp"
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080027
Junxiao Shi46a9bd32017-07-14 19:12:11 +000028#include <cstring>
Davide Pesaventoe1789892017-02-26 15:50:52 -050029#include <iterator>
Davide Pesavento4ab3be22017-07-18 00:38:52 -040030#include <ostream>
31#include <type_traits>
Davide Pesaventoe1789892017-02-26 15:50:52 -050032
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080033namespace ndn {
34
Junxiao Shi468abc32014-11-04 09:12:47 -070035/** @brief practical limit of network layer packet size
36 *
37 * If a packet is longer than this size, library and application MAY drop it.
38 */
39const size_t MAX_NDN_PACKET_SIZE = 8800;
40
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080041/**
Junxiao Shia2550a92018-04-10 05:07:48 +000042 * @brief Namespace defining NDN Packet Format related constants and procedures
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080043 */
Steve DiBenedetto54ce6682014-07-22 13:22:57 -060044namespace tlv {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080045
Junxiao Shi468abc32014-11-04 09:12:47 -070046/** @brief represents an error in TLV encoding or decoding
47 *
48 * Element::Error SHOULD inherit from this Error class.
49 */
Alexander Afanasyeva465e972014-03-22 17:21:49 -070050class Error : public std::runtime_error
51{
52public:
53 explicit
54 Error(const std::string& what)
55 : std::runtime_error(what)
56 {
57 }
58};
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080059
Junxiao Shia2550a92018-04-10 05:07:48 +000060/** @brief TLV-TYPE numbers defined in NDN Packet Format v0.3
61 * @sa https://named-data.net/doc/NDN-packet-spec/current/types.html
Junxiao Shi7d3c14b2017-08-05 16:34:39 +000062 */
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080063enum {
Junxiao Shia2550a92018-04-10 05:07:48 +000064 Interest = 5,
65 Data = 6,
66 Name = 7,
67 GenericNameComponent = 8,
Alexander Afanasyev6486d522014-10-23 14:14:11 -070068 ImplicitSha256DigestComponent = 1,
Junxiao Shia2550a92018-04-10 05:07:48 +000069 CanBePrefix = 33,
70 MustBeFresh = 18,
71 ForwardingHint = 30,
72 Nonce = 10,
73 InterestLifetime = 12,
74 HopLimit = 34,
75 Parameters = 35,
76 MetaInfo = 20,
77 Content = 21,
78 SignatureInfo = 22,
79 SignatureValue = 23,
80 ContentType = 24,
81 FreshnessPeriod = 25,
82 FinalBlockId = 26,
83 SignatureType = 27,
84 KeyLocator = 28,
85 KeyDigest = 29,
86 LinkDelegation = 31,
87 LinkPreference = 30,
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080088
Junxiao Shicf4ac5b2018-03-28 22:46:06 +000089 NameComponentMin = 1,
90 NameComponentMax = 65535,
91
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080092 AppPrivateBlock1 = 128,
93 AppPrivateBlock2 = 32767
94};
95
Junxiao Shia2550a92018-04-10 05:07:48 +000096/** @brief TLV-TYPE numbers defined in NDN Packet Format v0.2 but not in v0.3
97 * @sa https://named-data.net/doc/NDN-packet-spec/0.2.1/types.html
98 */
99enum {
100 Selectors = 9,
101 MinSuffixComponents = 13,
102 MaxSuffixComponents = 14,
103 PublisherPublicKeyLocator = 15,
104 Exclude = 16,
105 ChildSelector = 17,
106 Any = 19,
107};
108
Davide Pesavento1fd00242018-05-20 00:11:01 -0400109[[deprecated("use GenericNameComponent")]]
110constexpr int NameComponent = GenericNameComponent;
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000111
Davide Pesavento7e6f6f82017-10-31 18:05:28 -0400112enum SignatureTypeValue : uint16_t {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800113 DigestSha256 = 0,
Yingdi Yuebfa4cb2014-06-17 15:28:53 -0700114 SignatureSha256WithRsa = 1,
Alexander Afanasyev117f5ef2015-06-03 15:07:24 -0700115 // <Unassigned> = 2,
Yingdi Yuebfa4cb2014-06-17 15:28:53 -0700116 SignatureSha256WithEcdsa = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800117};
118
Alexander Afanasyev5f1820e2017-01-04 18:12:42 -0800119std::ostream&
Davide Pesavento7e6f6f82017-10-31 18:05:28 -0400120operator<<(std::ostream& os, SignatureTypeValue signatureType);
Alexander Afanasyev5f1820e2017-01-04 18:12:42 -0800121
Junxiao Shi7d3c14b2017-08-05 16:34:39 +0000122/** @brief TLV-TYPE numbers for SignatureInfo features
Yingdi Yu7a813892015-06-09 14:19:54 -0700123 * @sa docs/tutorials/certificate-format.rst
124 */
125enum {
Yingdi Yu7a813892015-06-09 14:19:54 -0700126 ValidityPeriod = 253,
127 NotBefore = 254,
Yingdi Yuea382942015-07-17 23:20:44 -0700128 NotAfter = 255,
129
130 AdditionalDescription = 258,
131 DescriptionEntry = 512,
132 DescriptionKey = 513,
133 DescriptionValue = 514
Yingdi Yu7a813892015-06-09 14:19:54 -0700134};
135
Junxiao Shia464b922014-11-12 21:13:06 -0700136/** @brief indicates a possible value of ContentType field
137 */
Yingdi Yuebfa4cb2014-06-17 15:28:53 -0700138enum ContentTypeValue {
Junxiao Shia464b922014-11-12 21:13:06 -0700139 /** @brief indicates content is the actual data bits
140 */
141 ContentType_Blob = 0,
142
143 /** @brief indicates content is another name which identifies actual data content
144 */
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800145 ContentType_Link = 1,
Junxiao Shia464b922014-11-12 21:13:06 -0700146
147 /** @brief indicates content is a public key
148 */
149 ContentType_Key = 2,
150
151 /** @brief indicates a producer generated NACK
Junxiao Shia464b922014-11-12 21:13:06 -0700152 */
153 ContentType_Nack = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800154};
155
156/**
Junxiao Shia2550a92018-04-10 05:07:48 +0000157 * @brief Determine whether a TLV-TYPE is "critical" for evolvability purpose.
158 * @sa https://named-data.net/doc/NDN-packet-spec/0.3/tlv.html#considerations-for-evolvability-of-tlv-based-encoding
159 */
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000160constexpr bool
Junxiao Shia2550a92018-04-10 05:07:48 +0000161isCriticalType(uint32_t type)
162{
163 return type <= 31 || (type & 0x01);
164}
165
166/**
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800167 * @brief Read VAR-NUMBER in NDN-TLV encoding
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000168 * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800169 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000170 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
171 * the read VAR-NUMBER
172 * @param [in] end End of the buffer
173 * @param [out] number Read VAR-NUMBER
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700174 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000175 * @return true if number was successfully read from input, false otherwise
176 * @note This call never throws exceptions
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700177 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000178template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000179bool
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000180readVarNumber(Iterator& begin, const Iterator& end, uint64_t& number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700181
182/**
Junxiao Shic18aa192017-07-07 06:06:38 +0000183 * @brief Read TLV-TYPE
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000184 * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700185 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000186 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
187 * the read TLV-TYPE
188 * @param [in] end End of the buffer
189 * @param [out] type Read TLV-TYPE
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700190 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000191 * @return true if TLV-TYPE was successfully read from input, false otherwise
192 * @note This call never throws exceptions
193 * @note This call is largely equivalent to tlv::readVarNumber, but it will return false if type
194 * is larger than 2^32-1 (TLV-TYPE in this library is implemented as uint32_t)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700195 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000196template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000197bool
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000198readType(Iterator& begin, const Iterator& end, uint32_t& type);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700199
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700200/**
201 * @brief Read VAR-NUMBER in NDN-TLV encoding
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000202 * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700203 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000204 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
205 * the read VAR-NUMBER
206 * @param [in] end End of the buffer
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800207 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000208 * @throw tlv::Error VAR-NUMBER cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800209 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000210template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000211uint64_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000212readVarNumber(Iterator& begin, const Iterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800213
214/**
215 * @brief Read TLV Type
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000216 * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800217 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000218 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
219 * the read TLV-TYPE
220 * @param [in] end End of the buffer
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700221 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000222 * @throw tlv::Error VAR-NUMBER cannot be read
223 * @note This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
224 * is larger than 2^32-1 (TLV-TYPE in this library is implemented as uint32_t)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800225 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000226template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000227uint32_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000228readType(Iterator& begin, const Iterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800229
230/**
231 * @brief Get number of bytes necessary to hold value of VAR-NUMBER
232 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000233constexpr size_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000234sizeOfVarNumber(uint64_t number);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800235
236/**
237 * @brief Write VAR-NUMBER to the specified stream
Junxiao Shic18aa192017-07-07 06:06:38 +0000238 * @return length of written VAR-NUMBER
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800239 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000240size_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000241writeVarNumber(std::ostream& os, uint64_t number);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800242
243/**
244 * @brief Read nonNegativeInteger in NDN-TLV encoding
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000245 * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800246 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000247 * @param [in] size size of the nonNegativeInteger
248 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
249 * the read nonNegativeInteger
250 * @param [in] end End of the buffer
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800251 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000252 * @throw tlv::Error number cannot be read
253 * @note How many bytes to read is directly controlled by \p size, which can be either 1, 2, 4, or 8.
254 * If \p size differs from \p std::distance(begin, end), tlv::Error exception will be thrown.
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800255 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000256template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000257uint64_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000258readNonNegativeInteger(size_t size, Iterator& begin, const Iterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800259
260/**
261 * @brief Get number of bytes necessary to hold value of nonNegativeInteger
262 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000263constexpr size_t
264sizeOfNonNegativeInteger(uint64_t integer);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800265
266/**
267 * @brief Write nonNegativeInteger to the specified stream
Junxiao Shic18aa192017-07-07 06:06:38 +0000268 * @return length of written nonNegativeInteger
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800269 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000270size_t
271writeNonNegativeInteger(std::ostream& os, uint64_t integer);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800272
273/////////////////////////////////////////////////////////////////////////////////
274/////////////////////////////////////////////////////////////////////////////////
275/////////////////////////////////////////////////////////////////////////////////
276
Davide Pesavento4ab3be22017-07-18 00:38:52 -0400277// Inline definitions
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800278
279/////////////////////////////////////////////////////////////////////////////////
280/////////////////////////////////////////////////////////////////////////////////
281/////////////////////////////////////////////////////////////////////////////////
282
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000283namespace detail {
284
285/** @brief Function object to read a number from InputIterator
286 */
287template<typename Iterator>
288class ReadNumberSlow
289{
290public:
291 bool
292 operator()(size_t size, Iterator& begin, const Iterator& end, uint64_t& number) const
293 {
294 number = 0;
295 size_t count = 0;
296 for (; begin != end && count < size; ++begin, ++count) {
297 number = (number << 8) | *begin;
298 }
299 return count == size;
300 }
301};
302
303/** @brief Function object to read a number from ContiguousIterator
304 */
305template<typename Iterator>
306class ReadNumberFast
307{
308public:
309 bool
310 operator()(size_t size, Iterator& begin, const Iterator& end, uint64_t& number) const
311 {
312 if (begin + size > end) {
313 return false;
314 }
315
316 switch (size) {
317 case 1: {
318 number = *begin;
319 ++begin;
320 return true;
321 }
322 case 2: {
323 uint16_t value = 0;
324 std::memcpy(&value, &*begin, 2);
325 begin += 2;
326 number = be16toh(value);
327 return true;
328 }
329 case 4: {
330 uint32_t value = 0;
331 std::memcpy(&value, &*begin, 4);
332 begin += 4;
333 number = be32toh(value);
334 return true;
335 }
336 case 8: {
337 uint64_t value = 0;
338 std::memcpy(&value, &*begin, 8);
339 begin += 8;
340 number = be64toh(value);
341 return true;
342 }
343 default: {
344 BOOST_ASSERT(false);
345 return false;
346 }
347 }
348 }
349};
350
351/** @brief Determine whether to select ReadNumber implementation for ContiguousIterator
352 *
353 * This is not a full ContiguousIterator detection implementation. It returns true for the most
354 * common ContiguousIterator types used with TLV decoding function templates.
355 */
356template<typename Iterator,
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400357 typename DecayedIterator = std::decay_t<Iterator>,
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000358 typename ValueType = typename std::iterator_traits<DecayedIterator>::value_type>
359constexpr bool
360shouldSelectContiguousReadNumber()
361{
362 return (std::is_convertible<DecayedIterator, const ValueType*>::value ||
363 std::is_convertible<DecayedIterator, typename std::basic_string<ValueType>::const_iterator>::value ||
364 std::is_convertible<DecayedIterator, typename std::vector<ValueType>::const_iterator>::value) &&
Davide Pesavento4ab3be22017-07-18 00:38:52 -0400365 sizeof(ValueType) == 1 &&
366 !std::is_same<ValueType, bool>::value;
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000367}
368
369template<typename Iterator>
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400370class ReadNumber : public std::conditional_t<shouldSelectContiguousReadNumber<Iterator>(),
371 ReadNumberFast<Iterator>, ReadNumberSlow<Iterator>>
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000372{
373};
374
375} // namespace detail
376
377template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000378bool
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000379readVarNumber(Iterator& begin, const Iterator& end, uint64_t& number)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700380{
381 if (begin == end)
382 return false;
383
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700384 uint8_t firstOctet = *begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700385 ++begin;
Junxiao Shic18aa192017-07-07 06:06:38 +0000386 if (firstOctet < 253) {
387 number = firstOctet;
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000388 return true;
Junxiao Shic18aa192017-07-07 06:06:38 +0000389 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700390
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000391 size_t size = firstOctet == 253 ? 2 :
392 firstOctet == 254 ? 4 : 8;
393 return detail::ReadNumber<Iterator>()(size, begin, end, number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700394}
395
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000396template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000397bool
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000398readType(Iterator& begin, const Iterator& end, uint32_t& type)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700399{
Mickey Sweatt632e0572014-04-20 00:36:32 -0700400 uint64_t number = 0;
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700401 bool isOk = readVarNumber(begin, end, number);
Junxiao Shic18aa192017-07-07 06:06:38 +0000402 if (!isOk || number > std::numeric_limits<uint32_t>::max()) {
403 return false;
404 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700405
Davide Pesavento8f5cbdc2015-09-13 00:59:28 +0200406 type = static_cast<uint32_t>(number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700407 return true;
408}
409
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000410template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000411uint64_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000412readVarNumber(Iterator& begin, const Iterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800413{
414 if (begin == end)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700415 BOOST_THROW_EXCEPTION(Error("Empty buffer during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700416
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000417 uint64_t value = 0;
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700418 bool isOk = readVarNumber(begin, end, value);
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000419 if (!isOk) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700420 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000421 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700422
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700423 return value;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800424}
425
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000426template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000427uint32_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000428readType(Iterator& begin, const Iterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800429{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700430 uint64_t type = readVarNumber(begin, end);
Junxiao Shic18aa192017-07-07 06:06:38 +0000431 if (type > std::numeric_limits<uint32_t>::max()) {
Junxiao Shi7d3c14b2017-08-05 16:34:39 +0000432 BOOST_THROW_EXCEPTION(Error("TLV-TYPE number exceeds allowed maximum"));
Junxiao Shic18aa192017-07-07 06:06:38 +0000433 }
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800434
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700435 return static_cast<uint32_t>(type);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800436}
437
Junxiao Shic18aa192017-07-07 06:06:38 +0000438constexpr size_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000439sizeOfVarNumber(uint64_t number)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800440{
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000441 return number < 253 ? 1 :
442 number <= std::numeric_limits<uint16_t>::max() ? 3 :
443 number <= std::numeric_limits<uint32_t>::max() ? 5 : 9;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800444}
445
446inline size_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000447writeVarNumber(std::ostream& os, uint64_t number)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800448{
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000449 if (number < 253) {
450 os.put(static_cast<char>(number));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800451 return 1;
452 }
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000453 else if (number <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200454 os.put(static_cast<char>(253));
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000455 uint16_t value = htobe16(static_cast<uint16_t>(number));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700456 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800457 return 3;
458 }
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000459 else if (number <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200460 os.put(static_cast<char>(254));
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000461 uint32_t value = htobe32(static_cast<uint32_t>(number));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700462 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800463 return 5;
464 }
465 else {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200466 os.put(static_cast<char>(255));
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000467 uint64_t value = htobe64(number);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700468 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800469 return 9;
470 }
471}
472
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000473template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000474uint64_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000475readNonNegativeInteger(size_t size, Iterator& begin, const Iterator& end)
Yingdi Yu27158392014-01-20 13:04:20 -0800476{
Junxiao Shic18aa192017-07-07 06:06:38 +0000477 if (size != 1 && size != 2 && size != 4 && size != 8) {
478 BOOST_THROW_EXCEPTION(Error("Invalid length for nonNegativeInteger "
479 "(only 1, 2, 4, and 8 are allowed)"));
Yingdi Yu27158392014-01-20 13:04:20 -0800480 }
Junxiao Shic18aa192017-07-07 06:06:38 +0000481
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000482 uint64_t number = 0;
483 bool isOk = detail::ReadNumber<Iterator>()(size, begin, end, number);
484 if (!isOk) {
Junxiao Shic18aa192017-07-07 06:06:38 +0000485 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
486 }
487
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000488 return number;
Junxiao Shic18aa192017-07-07 06:06:38 +0000489}
490
491constexpr size_t
492sizeOfNonNegativeInteger(uint64_t integer)
493{
494 return integer <= std::numeric_limits<uint8_t>::max() ? 1 :
495 integer <= std::numeric_limits<uint16_t>::max() ? 2 :
496 integer <= std::numeric_limits<uint32_t>::max() ? 4 : 8;
Yingdi Yu27158392014-01-20 13:04:20 -0800497}
498
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800499inline size_t
Junxiao Shic18aa192017-07-07 06:06:38 +0000500writeNonNegativeInteger(std::ostream& os, uint64_t integer)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800501{
Junxiao Shic18aa192017-07-07 06:06:38 +0000502 if (integer <= std::numeric_limits<uint8_t>::max()) {
503 os.put(static_cast<char>(integer));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800504 return 1;
505 }
Junxiao Shic18aa192017-07-07 06:06:38 +0000506 else if (integer <= std::numeric_limits<uint16_t>::max()) {
507 uint16_t value = htobe16(static_cast<uint16_t>(integer));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700508 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800509 return 2;
510 }
Junxiao Shic18aa192017-07-07 06:06:38 +0000511 else if (integer <= std::numeric_limits<uint32_t>::max()) {
512 uint32_t value = htobe32(static_cast<uint32_t>(integer));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700513 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800514 return 4;
515 }
516 else {
Junxiao Shic18aa192017-07-07 06:06:38 +0000517 uint64_t value = htobe64(integer);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700518 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800519 return 8;
520 }
521}
522
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600523} // namespace tlv
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800524} // namespace ndn
525
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700526#endif // NDN_ENCODING_TLV_HPP