blob: 10961c58e8b71bfff6991900e71de5968bec3efd [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
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000109constexpr int NameComponent NDN_CXX_DEPRECATED = GenericNameComponent;
110
Davide Pesavento7e6f6f82017-10-31 18:05:28 -0400111enum SignatureTypeValue : uint16_t {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800112 DigestSha256 = 0,
Yingdi Yuebfa4cb2014-06-17 15:28:53 -0700113 SignatureSha256WithRsa = 1,
Alexander Afanasyev117f5ef2015-06-03 15:07:24 -0700114 // <Unassigned> = 2,
Yingdi Yuebfa4cb2014-06-17 15:28:53 -0700115 SignatureSha256WithEcdsa = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800116};
117
Alexander Afanasyev5f1820e2017-01-04 18:12:42 -0800118std::ostream&
Davide Pesavento7e6f6f82017-10-31 18:05:28 -0400119operator<<(std::ostream& os, SignatureTypeValue signatureType);
Alexander Afanasyev5f1820e2017-01-04 18:12:42 -0800120
Junxiao Shi7d3c14b2017-08-05 16:34:39 +0000121/** @brief TLV-TYPE numbers for SignatureInfo features
Yingdi Yu7a813892015-06-09 14:19:54 -0700122 * @sa docs/tutorials/certificate-format.rst
123 */
124enum {
Yingdi Yu7a813892015-06-09 14:19:54 -0700125 ValidityPeriod = 253,
126 NotBefore = 254,
Yingdi Yuea382942015-07-17 23:20:44 -0700127 NotAfter = 255,
128
129 AdditionalDescription = 258,
130 DescriptionEntry = 512,
131 DescriptionKey = 513,
132 DescriptionValue = 514
Yingdi Yu7a813892015-06-09 14:19:54 -0700133};
134
Junxiao Shia464b922014-11-12 21:13:06 -0700135/** @brief indicates a possible value of ContentType field
136 */
Yingdi Yuebfa4cb2014-06-17 15:28:53 -0700137enum ContentTypeValue {
Junxiao Shia464b922014-11-12 21:13:06 -0700138 /** @brief indicates content is the actual data bits
139 */
140 ContentType_Blob = 0,
141
142 /** @brief indicates content is another name which identifies actual data content
143 */
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800144 ContentType_Link = 1,
Junxiao Shia464b922014-11-12 21:13:06 -0700145
146 /** @brief indicates content is a public key
147 */
148 ContentType_Key = 2,
149
150 /** @brief indicates a producer generated NACK
Junxiao Shia464b922014-11-12 21:13:06 -0700151 */
152 ContentType_Nack = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800153};
154
155/**
Junxiao Shia2550a92018-04-10 05:07:48 +0000156 * @brief Determine whether a TLV-TYPE is "critical" for evolvability purpose.
157 * @sa https://named-data.net/doc/NDN-packet-spec/0.3/tlv.html#considerations-for-evolvability-of-tlv-based-encoding
158 */
Junxiao Shi6efa3b72018-04-14 15:54:08 +0000159constexpr bool
Junxiao Shia2550a92018-04-10 05:07:48 +0000160isCriticalType(uint32_t type)
161{
162 return type <= 31 || (type & 0x01);
163}
164
165/**
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800166 * @brief Read VAR-NUMBER in NDN-TLV encoding
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000167 * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800168 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000169 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
170 * the read VAR-NUMBER
171 * @param [in] end End of the buffer
172 * @param [out] number Read VAR-NUMBER
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700173 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000174 * @return true if number was successfully read from input, false otherwise
175 * @note This call never throws exceptions
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700176 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000177template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000178bool
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000179readVarNumber(Iterator& begin, const Iterator& end, uint64_t& number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700180
181/**
Junxiao Shic18aa192017-07-07 06:06:38 +0000182 * @brief Read TLV-TYPE
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000183 * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700184 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000185 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
186 * the read TLV-TYPE
187 * @param [in] end End of the buffer
188 * @param [out] type Read TLV-TYPE
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700189 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000190 * @return true if TLV-TYPE was successfully read from input, false otherwise
191 * @note This call never throws exceptions
192 * @note This call is largely equivalent to tlv::readVarNumber, but it will return false if type
193 * is larger than 2^32-1 (TLV-TYPE in this library is implemented as uint32_t)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700194 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000195template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000196bool
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000197readType(Iterator& begin, const Iterator& end, uint32_t& type);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700198
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700199/**
200 * @brief Read VAR-NUMBER in NDN-TLV encoding
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000201 * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700202 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000203 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
204 * the read VAR-NUMBER
205 * @param [in] end End of the buffer
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800206 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000207 * @throw tlv::Error VAR-NUMBER cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800208 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000209template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000210uint64_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000211readVarNumber(Iterator& begin, const Iterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800212
213/**
214 * @brief Read TLV Type
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000215 * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800216 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000217 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
218 * the read TLV-TYPE
219 * @param [in] end End of the buffer
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700220 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000221 * @throw tlv::Error VAR-NUMBER cannot be read
222 * @note This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
223 * is larger than 2^32-1 (TLV-TYPE in this library is implemented as uint32_t)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800224 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000225template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000226uint32_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000227readType(Iterator& begin, const Iterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800228
229/**
230 * @brief Get number of bytes necessary to hold value of VAR-NUMBER
231 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000232constexpr size_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000233sizeOfVarNumber(uint64_t number);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800234
235/**
236 * @brief Write VAR-NUMBER to the specified stream
Junxiao Shic18aa192017-07-07 06:06:38 +0000237 * @return length of written VAR-NUMBER
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800238 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000239size_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000240writeVarNumber(std::ostream& os, uint64_t number);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800241
242/**
243 * @brief Read nonNegativeInteger in NDN-TLV encoding
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000244 * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800245 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000246 * @param [in] size size of the nonNegativeInteger
247 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
248 * the read nonNegativeInteger
249 * @param [in] end End of the buffer
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800250 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000251 * @throw tlv::Error number cannot be read
252 * @note How many bytes to read is directly controlled by \p size, which can be either 1, 2, 4, or 8.
253 * If \p size differs from \p std::distance(begin, end), tlv::Error exception will be thrown.
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800254 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000255template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000256uint64_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000257readNonNegativeInteger(size_t size, Iterator& begin, const Iterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800258
259/**
260 * @brief Get number of bytes necessary to hold value of nonNegativeInteger
261 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000262constexpr size_t
263sizeOfNonNegativeInteger(uint64_t integer);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800264
265/**
266 * @brief Write nonNegativeInteger to the specified stream
Junxiao Shic18aa192017-07-07 06:06:38 +0000267 * @return length of written nonNegativeInteger
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800268 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000269size_t
270writeNonNegativeInteger(std::ostream& os, uint64_t integer);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800271
272/////////////////////////////////////////////////////////////////////////////////
273/////////////////////////////////////////////////////////////////////////////////
274/////////////////////////////////////////////////////////////////////////////////
275
Davide Pesavento4ab3be22017-07-18 00:38:52 -0400276// Inline definitions
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800277
278/////////////////////////////////////////////////////////////////////////////////
279/////////////////////////////////////////////////////////////////////////////////
280/////////////////////////////////////////////////////////////////////////////////
281
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000282namespace detail {
283
284/** @brief Function object to read a number from InputIterator
285 */
286template<typename Iterator>
287class ReadNumberSlow
288{
289public:
290 bool
291 operator()(size_t size, Iterator& begin, const Iterator& end, uint64_t& number) const
292 {
293 number = 0;
294 size_t count = 0;
295 for (; begin != end && count < size; ++begin, ++count) {
296 number = (number << 8) | *begin;
297 }
298 return count == size;
299 }
300};
301
302/** @brief Function object to read a number from ContiguousIterator
303 */
304template<typename Iterator>
305class ReadNumberFast
306{
307public:
308 bool
309 operator()(size_t size, Iterator& begin, const Iterator& end, uint64_t& number) const
310 {
311 if (begin + size > end) {
312 return false;
313 }
314
315 switch (size) {
316 case 1: {
317 number = *begin;
318 ++begin;
319 return true;
320 }
321 case 2: {
322 uint16_t value = 0;
323 std::memcpy(&value, &*begin, 2);
324 begin += 2;
325 number = be16toh(value);
326 return true;
327 }
328 case 4: {
329 uint32_t value = 0;
330 std::memcpy(&value, &*begin, 4);
331 begin += 4;
332 number = be32toh(value);
333 return true;
334 }
335 case 8: {
336 uint64_t value = 0;
337 std::memcpy(&value, &*begin, 8);
338 begin += 8;
339 number = be64toh(value);
340 return true;
341 }
342 default: {
343 BOOST_ASSERT(false);
344 return false;
345 }
346 }
347 }
348};
349
350/** @brief Determine whether to select ReadNumber implementation for ContiguousIterator
351 *
352 * This is not a full ContiguousIterator detection implementation. It returns true for the most
353 * common ContiguousIterator types used with TLV decoding function templates.
354 */
355template<typename Iterator,
356 typename DecayedIterator = typename std::decay<Iterator>::type,
357 typename ValueType = typename std::iterator_traits<DecayedIterator>::value_type>
358constexpr bool
359shouldSelectContiguousReadNumber()
360{
361 return (std::is_convertible<DecayedIterator, const ValueType*>::value ||
362 std::is_convertible<DecayedIterator, typename std::basic_string<ValueType>::const_iterator>::value ||
363 std::is_convertible<DecayedIterator, typename std::vector<ValueType>::const_iterator>::value) &&
Davide Pesavento4ab3be22017-07-18 00:38:52 -0400364 sizeof(ValueType) == 1 &&
365 !std::is_same<ValueType, bool>::value;
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000366}
367
368template<typename Iterator>
369class ReadNumber : public std::conditional<shouldSelectContiguousReadNumber<Iterator>(),
370 ReadNumberFast<Iterator>, ReadNumberSlow<Iterator>>::type
371{
372};
373
374} // namespace detail
375
376template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000377bool
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000378readVarNumber(Iterator& begin, const Iterator& end, uint64_t& number)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700379{
380 if (begin == end)
381 return false;
382
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700383 uint8_t firstOctet = *begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700384 ++begin;
Junxiao Shic18aa192017-07-07 06:06:38 +0000385 if (firstOctet < 253) {
386 number = firstOctet;
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000387 return true;
Junxiao Shic18aa192017-07-07 06:06:38 +0000388 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700389
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000390 size_t size = firstOctet == 253 ? 2 :
391 firstOctet == 254 ? 4 : 8;
392 return detail::ReadNumber<Iterator>()(size, begin, end, number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700393}
394
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000395template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000396bool
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000397readType(Iterator& begin, const Iterator& end, uint32_t& type)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700398{
Mickey Sweatt632e0572014-04-20 00:36:32 -0700399 uint64_t number = 0;
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700400 bool isOk = readVarNumber(begin, end, number);
Junxiao Shic18aa192017-07-07 06:06:38 +0000401 if (!isOk || number > std::numeric_limits<uint32_t>::max()) {
402 return false;
403 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700404
Davide Pesavento8f5cbdc2015-09-13 00:59:28 +0200405 type = static_cast<uint32_t>(number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700406 return true;
407}
408
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000409template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000410uint64_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000411readVarNumber(Iterator& begin, const Iterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800412{
413 if (begin == end)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700414 BOOST_THROW_EXCEPTION(Error("Empty buffer during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700415
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000416 uint64_t value = 0;
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700417 bool isOk = readVarNumber(begin, end, value);
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000418 if (!isOk) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700419 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000420 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700421
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700422 return value;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800423}
424
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000425template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000426uint32_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000427readType(Iterator& begin, const Iterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800428{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700429 uint64_t type = readVarNumber(begin, end);
Junxiao Shic18aa192017-07-07 06:06:38 +0000430 if (type > std::numeric_limits<uint32_t>::max()) {
Junxiao Shi7d3c14b2017-08-05 16:34:39 +0000431 BOOST_THROW_EXCEPTION(Error("TLV-TYPE number exceeds allowed maximum"));
Junxiao Shic18aa192017-07-07 06:06:38 +0000432 }
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800433
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700434 return static_cast<uint32_t>(type);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800435}
436
Junxiao Shic18aa192017-07-07 06:06:38 +0000437constexpr size_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000438sizeOfVarNumber(uint64_t number)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800439{
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000440 return number < 253 ? 1 :
441 number <= std::numeric_limits<uint16_t>::max() ? 3 :
442 number <= std::numeric_limits<uint32_t>::max() ? 5 : 9;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800443}
444
445inline size_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000446writeVarNumber(std::ostream& os, uint64_t number)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800447{
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000448 if (number < 253) {
449 os.put(static_cast<char>(number));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800450 return 1;
451 }
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000452 else if (number <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200453 os.put(static_cast<char>(253));
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000454 uint16_t value = htobe16(static_cast<uint16_t>(number));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700455 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800456 return 3;
457 }
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000458 else if (number <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200459 os.put(static_cast<char>(254));
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000460 uint32_t value = htobe32(static_cast<uint32_t>(number));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700461 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800462 return 5;
463 }
464 else {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200465 os.put(static_cast<char>(255));
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000466 uint64_t value = htobe64(number);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700467 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800468 return 9;
469 }
470}
471
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000472template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000473uint64_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000474readNonNegativeInteger(size_t size, Iterator& begin, const Iterator& end)
Yingdi Yu27158392014-01-20 13:04:20 -0800475{
Junxiao Shic18aa192017-07-07 06:06:38 +0000476 if (size != 1 && size != 2 && size != 4 && size != 8) {
477 BOOST_THROW_EXCEPTION(Error("Invalid length for nonNegativeInteger "
478 "(only 1, 2, 4, and 8 are allowed)"));
Yingdi Yu27158392014-01-20 13:04:20 -0800479 }
Junxiao Shic18aa192017-07-07 06:06:38 +0000480
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000481 uint64_t number = 0;
482 bool isOk = detail::ReadNumber<Iterator>()(size, begin, end, number);
483 if (!isOk) {
Junxiao Shic18aa192017-07-07 06:06:38 +0000484 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
485 }
486
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000487 return number;
Junxiao Shic18aa192017-07-07 06:06:38 +0000488}
489
490constexpr size_t
491sizeOfNonNegativeInteger(uint64_t integer)
492{
493 return integer <= std::numeric_limits<uint8_t>::max() ? 1 :
494 integer <= std::numeric_limits<uint16_t>::max() ? 2 :
495 integer <= std::numeric_limits<uint32_t>::max() ? 4 : 8;
Yingdi Yu27158392014-01-20 13:04:20 -0800496}
497
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800498inline size_t
Junxiao Shic18aa192017-07-07 06:06:38 +0000499writeNonNegativeInteger(std::ostream& os, uint64_t integer)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800500{
Junxiao Shic18aa192017-07-07 06:06:38 +0000501 if (integer <= std::numeric_limits<uint8_t>::max()) {
502 os.put(static_cast<char>(integer));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800503 return 1;
504 }
Junxiao Shic18aa192017-07-07 06:06:38 +0000505 else if (integer <= std::numeric_limits<uint16_t>::max()) {
506 uint16_t value = htobe16(static_cast<uint16_t>(integer));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700507 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800508 return 2;
509 }
Junxiao Shic18aa192017-07-07 06:06:38 +0000510 else if (integer <= std::numeric_limits<uint32_t>::max()) {
511 uint32_t value = htobe32(static_cast<uint32_t>(integer));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700512 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800513 return 4;
514 }
515 else {
Junxiao Shic18aa192017-07-07 06:06:38 +0000516 uint64_t value = htobe64(integer);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700517 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800518 return 8;
519 }
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