blob: 57ee509eea4e0f4d4ce2f13b9c7b13c6c998852b [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/**
42 * @brief Namespace defining NDN-TLV related constants and procedures
43 */
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 Shi7d3c14b2017-08-05 16:34:39 +000060/** @brief TLV-TYPE numbers defined in NDN Packet Format
61 * @sa https://named-data.net/doc/ndn-tlv/types.html
62 */
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080063enum {
Alexander Afanasyev4b456282014-02-13 00:34:34 -080064 Interest = 5,
65 Data = 6,
66 Name = 7,
Alexander Afanasyev6486d522014-10-23 14:14:11 -070067 ImplicitSha256DigestComponent = 1,
Alexander Afanasyev4b456282014-02-13 00:34:34 -080068 NameComponent = 8,
69 Selectors = 9,
70 Nonce = 10,
Alexander Afanasyev4b456282014-02-13 00:34:34 -080071 InterestLifetime = 12,
Junxiao Shi688a6412017-06-22 10:12:07 +000072 ForwardingHint = 30,
Alexander Afanasyev4b456282014-02-13 00:34:34 -080073 MinSuffixComponents = 13,
74 MaxSuffixComponents = 14,
75 PublisherPublicKeyLocator = 15,
Davide Pesavento4ab3be22017-07-18 00:38:52 -040076 Exclude = 16,
77 ChildSelector = 17,
78 MustBeFresh = 18,
79 Any = 19,
80 MetaInfo = 20,
81 Content = 21,
82 SignatureInfo = 22,
Alexander Afanasyev4b456282014-02-13 00:34:34 -080083 SignatureValue = 23,
84 ContentType = 24,
85 FreshnessPeriod = 25,
Davide Pesavento4ab3be22017-07-18 00:38:52 -040086 FinalBlockId = 26,
87 SignatureType = 27,
88 KeyLocator = 28,
89 KeyDigest = 29,
90 LinkPreference = 30,
91 LinkDelegation = 31,
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080092
93 AppPrivateBlock1 = 128,
94 AppPrivateBlock2 = 32767
95};
96
Davide Pesavento7e6f6f82017-10-31 18:05:28 -040097enum SignatureTypeValue : uint16_t {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080098 DigestSha256 = 0,
Yingdi Yuebfa4cb2014-06-17 15:28:53 -070099 SignatureSha256WithRsa = 1,
Alexander Afanasyev117f5ef2015-06-03 15:07:24 -0700100 // <Unassigned> = 2,
Yingdi Yuebfa4cb2014-06-17 15:28:53 -0700101 SignatureSha256WithEcdsa = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800102};
103
Alexander Afanasyev5f1820e2017-01-04 18:12:42 -0800104std::ostream&
Davide Pesavento7e6f6f82017-10-31 18:05:28 -0400105operator<<(std::ostream& os, SignatureTypeValue signatureType);
Alexander Afanasyev5f1820e2017-01-04 18:12:42 -0800106
Junxiao Shi7d3c14b2017-08-05 16:34:39 +0000107/** @brief TLV-TYPE numbers for SignatureInfo features
Yingdi Yu7a813892015-06-09 14:19:54 -0700108 * @sa docs/tutorials/certificate-format.rst
109 */
110enum {
Yingdi Yu7a813892015-06-09 14:19:54 -0700111 ValidityPeriod = 253,
112 NotBefore = 254,
Yingdi Yuea382942015-07-17 23:20:44 -0700113 NotAfter = 255,
114
115 AdditionalDescription = 258,
116 DescriptionEntry = 512,
117 DescriptionKey = 513,
118 DescriptionValue = 514
Yingdi Yu7a813892015-06-09 14:19:54 -0700119};
120
Junxiao Shia464b922014-11-12 21:13:06 -0700121/** @brief indicates a possible value of ContentType field
122 */
Yingdi Yuebfa4cb2014-06-17 15:28:53 -0700123enum ContentTypeValue {
Junxiao Shia464b922014-11-12 21:13:06 -0700124 /** @brief indicates content is the actual data bits
125 */
126 ContentType_Blob = 0,
127
128 /** @brief indicates content is another name which identifies actual data content
129 */
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800130 ContentType_Link = 1,
Junxiao Shia464b922014-11-12 21:13:06 -0700131
132 /** @brief indicates content is a public key
133 */
134 ContentType_Key = 2,
135
136 /** @brief indicates a producer generated NACK
Junxiao Shia464b922014-11-12 21:13:06 -0700137 */
138 ContentType_Nack = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800139};
140
141/**
142 * @brief Read VAR-NUMBER in NDN-TLV encoding
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000143 * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800144 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000145 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
146 * the read VAR-NUMBER
147 * @param [in] end End of the buffer
148 * @param [out] number Read VAR-NUMBER
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700149 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000150 * @return true if number was successfully read from input, false otherwise
151 * @note This call never throws exceptions
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700152 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000153template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000154bool
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000155readVarNumber(Iterator& begin, const Iterator& end, uint64_t& number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700156
157/**
Junxiao Shic18aa192017-07-07 06:06:38 +0000158 * @brief Read TLV-TYPE
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000159 * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700160 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000161 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
162 * the read TLV-TYPE
163 * @param [in] end End of the buffer
164 * @param [out] type Read TLV-TYPE
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700165 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000166 * @return true if TLV-TYPE was successfully read from input, false otherwise
167 * @note This call never throws exceptions
168 * @note This call is largely equivalent to tlv::readVarNumber, but it will return false if type
169 * is larger than 2^32-1 (TLV-TYPE in this library is implemented as uint32_t)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700170 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000171template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000172bool
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000173readType(Iterator& begin, const Iterator& end, uint32_t& type);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700174
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700175/**
176 * @brief Read VAR-NUMBER in NDN-TLV encoding
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000177 * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700178 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000179 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
180 * the read VAR-NUMBER
181 * @param [in] end End of the buffer
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800182 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000183 * @throw tlv::Error VAR-NUMBER cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800184 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000185template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000186uint64_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000187readVarNumber(Iterator& begin, const Iterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800188
189/**
190 * @brief Read TLV Type
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000191 * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800192 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000193 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
194 * the read TLV-TYPE
195 * @param [in] end End of the buffer
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700196 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000197 * @throw tlv::Error VAR-NUMBER cannot be read
198 * @note This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
199 * is larger than 2^32-1 (TLV-TYPE in this library is implemented as uint32_t)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800200 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000201template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000202uint32_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000203readType(Iterator& begin, const Iterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800204
205/**
206 * @brief Get number of bytes necessary to hold value of VAR-NUMBER
207 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000208constexpr size_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000209sizeOfVarNumber(uint64_t number);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800210
211/**
212 * @brief Write VAR-NUMBER to the specified stream
Junxiao Shic18aa192017-07-07 06:06:38 +0000213 * @return length of written VAR-NUMBER
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800214 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000215size_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000216writeVarNumber(std::ostream& os, uint64_t number);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800217
218/**
219 * @brief Read nonNegativeInteger in NDN-TLV encoding
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000220 * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800221 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000222 * @param [in] size size of the nonNegativeInteger
223 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
224 * the read nonNegativeInteger
225 * @param [in] end End of the buffer
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800226 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000227 * @throw tlv::Error number cannot be read
228 * @note How many bytes to read is directly controlled by \p size, which can be either 1, 2, 4, or 8.
229 * If \p size differs from \p std::distance(begin, end), tlv::Error exception will be thrown.
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800230 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000231template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000232uint64_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000233readNonNegativeInteger(size_t size, Iterator& begin, const Iterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800234
235/**
236 * @brief Get number of bytes necessary to hold value of nonNegativeInteger
237 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000238constexpr size_t
239sizeOfNonNegativeInteger(uint64_t integer);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800240
241/**
242 * @brief Write nonNegativeInteger to the specified stream
Junxiao Shic18aa192017-07-07 06:06:38 +0000243 * @return length of written nonNegativeInteger
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800244 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000245size_t
246writeNonNegativeInteger(std::ostream& os, uint64_t integer);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800247
248/////////////////////////////////////////////////////////////////////////////////
249/////////////////////////////////////////////////////////////////////////////////
250/////////////////////////////////////////////////////////////////////////////////
251
Davide Pesavento4ab3be22017-07-18 00:38:52 -0400252// Inline definitions
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800253
254/////////////////////////////////////////////////////////////////////////////////
255/////////////////////////////////////////////////////////////////////////////////
256/////////////////////////////////////////////////////////////////////////////////
257
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000258namespace detail {
259
260/** @brief Function object to read a number from InputIterator
261 */
262template<typename Iterator>
263class ReadNumberSlow
264{
265public:
266 bool
267 operator()(size_t size, Iterator& begin, const Iterator& end, uint64_t& number) const
268 {
269 number = 0;
270 size_t count = 0;
271 for (; begin != end && count < size; ++begin, ++count) {
272 number = (number << 8) | *begin;
273 }
274 return count == size;
275 }
276};
277
278/** @brief Function object to read a number from ContiguousIterator
279 */
280template<typename Iterator>
281class ReadNumberFast
282{
283public:
284 bool
285 operator()(size_t size, Iterator& begin, const Iterator& end, uint64_t& number) const
286 {
287 if (begin + size > end) {
288 return false;
289 }
290
291 switch (size) {
292 case 1: {
293 number = *begin;
294 ++begin;
295 return true;
296 }
297 case 2: {
298 uint16_t value = 0;
299 std::memcpy(&value, &*begin, 2);
300 begin += 2;
301 number = be16toh(value);
302 return true;
303 }
304 case 4: {
305 uint32_t value = 0;
306 std::memcpy(&value, &*begin, 4);
307 begin += 4;
308 number = be32toh(value);
309 return true;
310 }
311 case 8: {
312 uint64_t value = 0;
313 std::memcpy(&value, &*begin, 8);
314 begin += 8;
315 number = be64toh(value);
316 return true;
317 }
318 default: {
319 BOOST_ASSERT(false);
320 return false;
321 }
322 }
323 }
324};
325
326/** @brief Determine whether to select ReadNumber implementation for ContiguousIterator
327 *
328 * This is not a full ContiguousIterator detection implementation. It returns true for the most
329 * common ContiguousIterator types used with TLV decoding function templates.
330 */
331template<typename Iterator,
332 typename DecayedIterator = typename std::decay<Iterator>::type,
333 typename ValueType = typename std::iterator_traits<DecayedIterator>::value_type>
334constexpr bool
335shouldSelectContiguousReadNumber()
336{
337 return (std::is_convertible<DecayedIterator, const ValueType*>::value ||
338 std::is_convertible<DecayedIterator, typename std::basic_string<ValueType>::const_iterator>::value ||
339 std::is_convertible<DecayedIterator, typename std::vector<ValueType>::const_iterator>::value) &&
Davide Pesavento4ab3be22017-07-18 00:38:52 -0400340 sizeof(ValueType) == 1 &&
341 !std::is_same<ValueType, bool>::value;
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000342}
343
344template<typename Iterator>
345class ReadNumber : public std::conditional<shouldSelectContiguousReadNumber<Iterator>(),
346 ReadNumberFast<Iterator>, ReadNumberSlow<Iterator>>::type
347{
348};
349
350} // namespace detail
351
352template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000353bool
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000354readVarNumber(Iterator& begin, const Iterator& end, uint64_t& number)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700355{
356 if (begin == end)
357 return false;
358
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700359 uint8_t firstOctet = *begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700360 ++begin;
Junxiao Shic18aa192017-07-07 06:06:38 +0000361 if (firstOctet < 253) {
362 number = firstOctet;
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000363 return true;
Junxiao Shic18aa192017-07-07 06:06:38 +0000364 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700365
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000366 size_t size = firstOctet == 253 ? 2 :
367 firstOctet == 254 ? 4 : 8;
368 return detail::ReadNumber<Iterator>()(size, begin, end, number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700369}
370
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000371template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000372bool
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000373readType(Iterator& begin, const Iterator& end, uint32_t& type)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700374{
Mickey Sweatt632e0572014-04-20 00:36:32 -0700375 uint64_t number = 0;
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700376 bool isOk = readVarNumber(begin, end, number);
Junxiao Shic18aa192017-07-07 06:06:38 +0000377 if (!isOk || number > std::numeric_limits<uint32_t>::max()) {
378 return false;
379 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700380
Davide Pesavento8f5cbdc2015-09-13 00:59:28 +0200381 type = static_cast<uint32_t>(number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700382 return true;
383}
384
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000385template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000386uint64_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000387readVarNumber(Iterator& begin, const Iterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800388{
389 if (begin == end)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700390 BOOST_THROW_EXCEPTION(Error("Empty buffer during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700391
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000392 uint64_t value = 0;
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700393 bool isOk = readVarNumber(begin, end, value);
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000394 if (!isOk) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700395 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000396 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700397
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700398 return value;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800399}
400
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000401template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000402uint32_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000403readType(Iterator& begin, const Iterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800404{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700405 uint64_t type = readVarNumber(begin, end);
Junxiao Shic18aa192017-07-07 06:06:38 +0000406 if (type > std::numeric_limits<uint32_t>::max()) {
Junxiao Shi7d3c14b2017-08-05 16:34:39 +0000407 BOOST_THROW_EXCEPTION(Error("TLV-TYPE number exceeds allowed maximum"));
Junxiao Shic18aa192017-07-07 06:06:38 +0000408 }
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800409
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700410 return static_cast<uint32_t>(type);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800411}
412
Junxiao Shic18aa192017-07-07 06:06:38 +0000413constexpr size_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000414sizeOfVarNumber(uint64_t number)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800415{
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000416 return number < 253 ? 1 :
417 number <= std::numeric_limits<uint16_t>::max() ? 3 :
418 number <= std::numeric_limits<uint32_t>::max() ? 5 : 9;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800419}
420
421inline size_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000422writeVarNumber(std::ostream& os, uint64_t number)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800423{
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000424 if (number < 253) {
425 os.put(static_cast<char>(number));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800426 return 1;
427 }
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000428 else if (number <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200429 os.put(static_cast<char>(253));
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000430 uint16_t value = htobe16(static_cast<uint16_t>(number));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700431 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800432 return 3;
433 }
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000434 else if (number <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200435 os.put(static_cast<char>(254));
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000436 uint32_t value = htobe32(static_cast<uint32_t>(number));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700437 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800438 return 5;
439 }
440 else {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200441 os.put(static_cast<char>(255));
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000442 uint64_t value = htobe64(number);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700443 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800444 return 9;
445 }
446}
447
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000448template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000449uint64_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000450readNonNegativeInteger(size_t size, Iterator& begin, const Iterator& end)
Yingdi Yu27158392014-01-20 13:04:20 -0800451{
Junxiao Shic18aa192017-07-07 06:06:38 +0000452 if (size != 1 && size != 2 && size != 4 && size != 8) {
453 BOOST_THROW_EXCEPTION(Error("Invalid length for nonNegativeInteger "
454 "(only 1, 2, 4, and 8 are allowed)"));
Yingdi Yu27158392014-01-20 13:04:20 -0800455 }
Junxiao Shic18aa192017-07-07 06:06:38 +0000456
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000457 uint64_t number = 0;
458 bool isOk = detail::ReadNumber<Iterator>()(size, begin, end, number);
459 if (!isOk) {
Junxiao Shic18aa192017-07-07 06:06:38 +0000460 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
461 }
462
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000463 return number;
Junxiao Shic18aa192017-07-07 06:06:38 +0000464}
465
466constexpr size_t
467sizeOfNonNegativeInteger(uint64_t integer)
468{
469 return integer <= std::numeric_limits<uint8_t>::max() ? 1 :
470 integer <= std::numeric_limits<uint16_t>::max() ? 2 :
471 integer <= std::numeric_limits<uint32_t>::max() ? 4 : 8;
Yingdi Yu27158392014-01-20 13:04:20 -0800472}
473
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800474inline size_t
Junxiao Shic18aa192017-07-07 06:06:38 +0000475writeNonNegativeInteger(std::ostream& os, uint64_t integer)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800476{
Junxiao Shic18aa192017-07-07 06:06:38 +0000477 if (integer <= std::numeric_limits<uint8_t>::max()) {
478 os.put(static_cast<char>(integer));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800479 return 1;
480 }
Junxiao Shic18aa192017-07-07 06:06:38 +0000481 else if (integer <= std::numeric_limits<uint16_t>::max()) {
482 uint16_t value = htobe16(static_cast<uint16_t>(integer));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700483 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800484 return 2;
485 }
Junxiao Shic18aa192017-07-07 06:06:38 +0000486 else if (integer <= std::numeric_limits<uint32_t>::max()) {
487 uint32_t value = htobe32(static_cast<uint32_t>(integer));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700488 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800489 return 4;
490 }
491 else {
Junxiao Shic18aa192017-07-07 06:06:38 +0000492 uint64_t value = htobe64(integer);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700493 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800494 return 8;
495 }
496}
497
498
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600499} // namespace tlv
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800500} // namespace ndn
501
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700502#endif // NDN_ENCODING_TLV_HPP