blob: fac222b991992d35fa4e589bc3b745206373d5fd [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,
Junxiao Shicf4ac5b2018-03-28 22:46:06 +000068 GenericNameComponent = 8,
Alexander Afanasyev4b456282014-02-13 00:34:34 -080069 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
Junxiao Shicf4ac5b2018-03-28 22:46:06 +000093 NameComponentMin = 1,
94 NameComponentMax = 65535,
95
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080096 AppPrivateBlock1 = 128,
97 AppPrivateBlock2 = 32767
98};
99
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000100constexpr int NameComponent NDN_CXX_DEPRECATED = GenericNameComponent;
101
Davide Pesavento7e6f6f82017-10-31 18:05:28 -0400102enum SignatureTypeValue : uint16_t {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800103 DigestSha256 = 0,
Yingdi Yuebfa4cb2014-06-17 15:28:53 -0700104 SignatureSha256WithRsa = 1,
Alexander Afanasyev117f5ef2015-06-03 15:07:24 -0700105 // <Unassigned> = 2,
Yingdi Yuebfa4cb2014-06-17 15:28:53 -0700106 SignatureSha256WithEcdsa = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800107};
108
Alexander Afanasyev5f1820e2017-01-04 18:12:42 -0800109std::ostream&
Davide Pesavento7e6f6f82017-10-31 18:05:28 -0400110operator<<(std::ostream& os, SignatureTypeValue signatureType);
Alexander Afanasyev5f1820e2017-01-04 18:12:42 -0800111
Junxiao Shi7d3c14b2017-08-05 16:34:39 +0000112/** @brief TLV-TYPE numbers for SignatureInfo features
Yingdi Yu7a813892015-06-09 14:19:54 -0700113 * @sa docs/tutorials/certificate-format.rst
114 */
115enum {
Yingdi Yu7a813892015-06-09 14:19:54 -0700116 ValidityPeriod = 253,
117 NotBefore = 254,
Yingdi Yuea382942015-07-17 23:20:44 -0700118 NotAfter = 255,
119
120 AdditionalDescription = 258,
121 DescriptionEntry = 512,
122 DescriptionKey = 513,
123 DescriptionValue = 514
Yingdi Yu7a813892015-06-09 14:19:54 -0700124};
125
Junxiao Shia464b922014-11-12 21:13:06 -0700126/** @brief indicates a possible value of ContentType field
127 */
Yingdi Yuebfa4cb2014-06-17 15:28:53 -0700128enum ContentTypeValue {
Junxiao Shia464b922014-11-12 21:13:06 -0700129 /** @brief indicates content is the actual data bits
130 */
131 ContentType_Blob = 0,
132
133 /** @brief indicates content is another name which identifies actual data content
134 */
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800135 ContentType_Link = 1,
Junxiao Shia464b922014-11-12 21:13:06 -0700136
137 /** @brief indicates content is a public key
138 */
139 ContentType_Key = 2,
140
141 /** @brief indicates a producer generated NACK
Junxiao Shia464b922014-11-12 21:13:06 -0700142 */
143 ContentType_Nack = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800144};
145
146/**
147 * @brief Read VAR-NUMBER in NDN-TLV encoding
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000148 * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800149 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000150 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
151 * the read VAR-NUMBER
152 * @param [in] end End of the buffer
153 * @param [out] number Read VAR-NUMBER
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700154 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000155 * @return true if number was successfully read from input, false otherwise
156 * @note This call never throws exceptions
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700157 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000158template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000159bool
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000160readVarNumber(Iterator& begin, const Iterator& end, uint64_t& number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700161
162/**
Junxiao Shic18aa192017-07-07 06:06:38 +0000163 * @brief Read TLV-TYPE
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000164 * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700165 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000166 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
167 * the read TLV-TYPE
168 * @param [in] end End of the buffer
169 * @param [out] type Read TLV-TYPE
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700170 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000171 * @return true if TLV-TYPE was successfully read from input, false otherwise
172 * @note This call never throws exceptions
173 * @note This call is largely equivalent to tlv::readVarNumber, but it will return false if type
174 * is larger than 2^32-1 (TLV-TYPE in this library is implemented as uint32_t)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700175 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000176template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000177bool
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000178readType(Iterator& begin, const Iterator& end, uint32_t& type);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700179
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700180/**
181 * @brief Read VAR-NUMBER in NDN-TLV encoding
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000182 * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700183 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000184 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
185 * the read VAR-NUMBER
186 * @param [in] end End of the buffer
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800187 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000188 * @throw tlv::Error VAR-NUMBER cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800189 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000190template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000191uint64_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000192readVarNumber(Iterator& begin, const Iterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800193
194/**
195 * @brief Read TLV Type
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000196 * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800197 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000198 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
199 * the read TLV-TYPE
200 * @param [in] end End of the buffer
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700201 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000202 * @throw tlv::Error VAR-NUMBER cannot be read
203 * @note This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
204 * is larger than 2^32-1 (TLV-TYPE in this library is implemented as uint32_t)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800205 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000206template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000207uint32_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000208readType(Iterator& begin, const Iterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800209
210/**
211 * @brief Get number of bytes necessary to hold value of VAR-NUMBER
212 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000213constexpr size_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000214sizeOfVarNumber(uint64_t number);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800215
216/**
217 * @brief Write VAR-NUMBER to the specified stream
Junxiao Shic18aa192017-07-07 06:06:38 +0000218 * @return length of written VAR-NUMBER
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800219 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000220size_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000221writeVarNumber(std::ostream& os, uint64_t number);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800222
223/**
224 * @brief Read nonNegativeInteger in NDN-TLV encoding
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000225 * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800226 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000227 * @param [in] size size of the nonNegativeInteger
228 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
229 * the read nonNegativeInteger
230 * @param [in] end End of the buffer
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800231 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000232 * @throw tlv::Error number cannot be read
233 * @note How many bytes to read is directly controlled by \p size, which can be either 1, 2, 4, or 8.
234 * If \p size differs from \p std::distance(begin, end), tlv::Error exception will be thrown.
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800235 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000236template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000237uint64_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000238readNonNegativeInteger(size_t size, Iterator& begin, const Iterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800239
240/**
241 * @brief Get number of bytes necessary to hold value of nonNegativeInteger
242 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000243constexpr size_t
244sizeOfNonNegativeInteger(uint64_t integer);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800245
246/**
247 * @brief Write nonNegativeInteger to the specified stream
Junxiao Shic18aa192017-07-07 06:06:38 +0000248 * @return length of written nonNegativeInteger
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800249 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000250size_t
251writeNonNegativeInteger(std::ostream& os, uint64_t integer);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800252
253/////////////////////////////////////////////////////////////////////////////////
254/////////////////////////////////////////////////////////////////////////////////
255/////////////////////////////////////////////////////////////////////////////////
256
Davide Pesavento4ab3be22017-07-18 00:38:52 -0400257// Inline definitions
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800258
259/////////////////////////////////////////////////////////////////////////////////
260/////////////////////////////////////////////////////////////////////////////////
261/////////////////////////////////////////////////////////////////////////////////
262
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000263namespace detail {
264
265/** @brief Function object to read a number from InputIterator
266 */
267template<typename Iterator>
268class ReadNumberSlow
269{
270public:
271 bool
272 operator()(size_t size, Iterator& begin, const Iterator& end, uint64_t& number) const
273 {
274 number = 0;
275 size_t count = 0;
276 for (; begin != end && count < size; ++begin, ++count) {
277 number = (number << 8) | *begin;
278 }
279 return count == size;
280 }
281};
282
283/** @brief Function object to read a number from ContiguousIterator
284 */
285template<typename Iterator>
286class ReadNumberFast
287{
288public:
289 bool
290 operator()(size_t size, Iterator& begin, const Iterator& end, uint64_t& number) const
291 {
292 if (begin + size > end) {
293 return false;
294 }
295
296 switch (size) {
297 case 1: {
298 number = *begin;
299 ++begin;
300 return true;
301 }
302 case 2: {
303 uint16_t value = 0;
304 std::memcpy(&value, &*begin, 2);
305 begin += 2;
306 number = be16toh(value);
307 return true;
308 }
309 case 4: {
310 uint32_t value = 0;
311 std::memcpy(&value, &*begin, 4);
312 begin += 4;
313 number = be32toh(value);
314 return true;
315 }
316 case 8: {
317 uint64_t value = 0;
318 std::memcpy(&value, &*begin, 8);
319 begin += 8;
320 number = be64toh(value);
321 return true;
322 }
323 default: {
324 BOOST_ASSERT(false);
325 return false;
326 }
327 }
328 }
329};
330
331/** @brief Determine whether to select ReadNumber implementation for ContiguousIterator
332 *
333 * This is not a full ContiguousIterator detection implementation. It returns true for the most
334 * common ContiguousIterator types used with TLV decoding function templates.
335 */
336template<typename Iterator,
337 typename DecayedIterator = typename std::decay<Iterator>::type,
338 typename ValueType = typename std::iterator_traits<DecayedIterator>::value_type>
339constexpr bool
340shouldSelectContiguousReadNumber()
341{
342 return (std::is_convertible<DecayedIterator, const ValueType*>::value ||
343 std::is_convertible<DecayedIterator, typename std::basic_string<ValueType>::const_iterator>::value ||
344 std::is_convertible<DecayedIterator, typename std::vector<ValueType>::const_iterator>::value) &&
Davide Pesavento4ab3be22017-07-18 00:38:52 -0400345 sizeof(ValueType) == 1 &&
346 !std::is_same<ValueType, bool>::value;
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000347}
348
349template<typename Iterator>
350class ReadNumber : public std::conditional<shouldSelectContiguousReadNumber<Iterator>(),
351 ReadNumberFast<Iterator>, ReadNumberSlow<Iterator>>::type
352{
353};
354
355} // namespace detail
356
357template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000358bool
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000359readVarNumber(Iterator& begin, const Iterator& end, uint64_t& number)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700360{
361 if (begin == end)
362 return false;
363
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700364 uint8_t firstOctet = *begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700365 ++begin;
Junxiao Shic18aa192017-07-07 06:06:38 +0000366 if (firstOctet < 253) {
367 number = firstOctet;
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000368 return true;
Junxiao Shic18aa192017-07-07 06:06:38 +0000369 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700370
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000371 size_t size = firstOctet == 253 ? 2 :
372 firstOctet == 254 ? 4 : 8;
373 return detail::ReadNumber<Iterator>()(size, begin, end, number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700374}
375
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000376template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000377bool
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000378readType(Iterator& begin, const Iterator& end, uint32_t& type)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700379{
Mickey Sweatt632e0572014-04-20 00:36:32 -0700380 uint64_t number = 0;
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700381 bool isOk = readVarNumber(begin, end, number);
Junxiao Shic18aa192017-07-07 06:06:38 +0000382 if (!isOk || number > std::numeric_limits<uint32_t>::max()) {
383 return false;
384 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700385
Davide Pesavento8f5cbdc2015-09-13 00:59:28 +0200386 type = static_cast<uint32_t>(number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700387 return true;
388}
389
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000390template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000391uint64_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000392readVarNumber(Iterator& begin, const Iterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800393{
394 if (begin == end)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700395 BOOST_THROW_EXCEPTION(Error("Empty buffer during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700396
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000397 uint64_t value = 0;
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700398 bool isOk = readVarNumber(begin, end, value);
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000399 if (!isOk) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700400 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000401 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700402
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700403 return value;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800404}
405
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000406template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000407uint32_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000408readType(Iterator& begin, const Iterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800409{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700410 uint64_t type = readVarNumber(begin, end);
Junxiao Shic18aa192017-07-07 06:06:38 +0000411 if (type > std::numeric_limits<uint32_t>::max()) {
Junxiao Shi7d3c14b2017-08-05 16:34:39 +0000412 BOOST_THROW_EXCEPTION(Error("TLV-TYPE number exceeds allowed maximum"));
Junxiao Shic18aa192017-07-07 06:06:38 +0000413 }
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800414
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700415 return static_cast<uint32_t>(type);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800416}
417
Junxiao Shic18aa192017-07-07 06:06:38 +0000418constexpr size_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000419sizeOfVarNumber(uint64_t number)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800420{
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000421 return number < 253 ? 1 :
422 number <= std::numeric_limits<uint16_t>::max() ? 3 :
423 number <= std::numeric_limits<uint32_t>::max() ? 5 : 9;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800424}
425
426inline size_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000427writeVarNumber(std::ostream& os, uint64_t number)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800428{
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000429 if (number < 253) {
430 os.put(static_cast<char>(number));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800431 return 1;
432 }
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000433 else if (number <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200434 os.put(static_cast<char>(253));
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000435 uint16_t value = htobe16(static_cast<uint16_t>(number));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700436 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800437 return 3;
438 }
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000439 else if (number <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200440 os.put(static_cast<char>(254));
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000441 uint32_t value = htobe32(static_cast<uint32_t>(number));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700442 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800443 return 5;
444 }
445 else {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200446 os.put(static_cast<char>(255));
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000447 uint64_t value = htobe64(number);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700448 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800449 return 9;
450 }
451}
452
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000453template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000454uint64_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000455readNonNegativeInteger(size_t size, Iterator& begin, const Iterator& end)
Yingdi Yu27158392014-01-20 13:04:20 -0800456{
Junxiao Shic18aa192017-07-07 06:06:38 +0000457 if (size != 1 && size != 2 && size != 4 && size != 8) {
458 BOOST_THROW_EXCEPTION(Error("Invalid length for nonNegativeInteger "
459 "(only 1, 2, 4, and 8 are allowed)"));
Yingdi Yu27158392014-01-20 13:04:20 -0800460 }
Junxiao Shic18aa192017-07-07 06:06:38 +0000461
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000462 uint64_t number = 0;
463 bool isOk = detail::ReadNumber<Iterator>()(size, begin, end, number);
464 if (!isOk) {
Junxiao Shic18aa192017-07-07 06:06:38 +0000465 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
466 }
467
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000468 return number;
Junxiao Shic18aa192017-07-07 06:06:38 +0000469}
470
471constexpr size_t
472sizeOfNonNegativeInteger(uint64_t integer)
473{
474 return integer <= std::numeric_limits<uint8_t>::max() ? 1 :
475 integer <= std::numeric_limits<uint16_t>::max() ? 2 :
476 integer <= std::numeric_limits<uint32_t>::max() ? 4 : 8;
Yingdi Yu27158392014-01-20 13:04:20 -0800477}
478
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800479inline size_t
Junxiao Shic18aa192017-07-07 06:06:38 +0000480writeNonNegativeInteger(std::ostream& os, uint64_t integer)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800481{
Junxiao Shic18aa192017-07-07 06:06:38 +0000482 if (integer <= std::numeric_limits<uint8_t>::max()) {
483 os.put(static_cast<char>(integer));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800484 return 1;
485 }
Junxiao Shic18aa192017-07-07 06:06:38 +0000486 else if (integer <= std::numeric_limits<uint16_t>::max()) {
487 uint16_t value = htobe16(static_cast<uint16_t>(integer));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700488 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800489 return 2;
490 }
Junxiao Shic18aa192017-07-07 06:06:38 +0000491 else if (integer <= std::numeric_limits<uint32_t>::max()) {
492 uint32_t value = htobe32(static_cast<uint32_t>(integer));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700493 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800494 return 4;
495 }
496 else {
Junxiao Shic18aa192017-07-07 06:06:38 +0000497 uint64_t value = htobe64(integer);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700498 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800499 return 8;
500 }
501}
502
503
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600504} // namespace tlv
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800505} // namespace ndn
506
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700507#endif // NDN_ENCODING_TLV_HPP