blob: 876fcb57da9c89ad598aa41de9e7d6f9013cd1d5 [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/*
Alexander Afanasyev5f1820e2017-01-04 18:12:42 -08003 * Copyright (c) 2013-2017 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
Davide Pesaventoe1789892017-02-26 15:50:52 -050028#include <iostream>
29#include <iterator>
30
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080031namespace ndn {
32
Junxiao Shi468abc32014-11-04 09:12:47 -070033/** @brief practical limit of network layer packet size
34 *
35 * If a packet is longer than this size, library and application MAY drop it.
36 */
37const size_t MAX_NDN_PACKET_SIZE = 8800;
38
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080039/**
40 * @brief Namespace defining NDN-TLV related constants and procedures
41 */
Steve DiBenedetto54ce6682014-07-22 13:22:57 -060042namespace tlv {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080043
Junxiao Shi468abc32014-11-04 09:12:47 -070044/** @brief represents an error in TLV encoding or decoding
45 *
46 * Element::Error SHOULD inherit from this Error class.
47 */
Alexander Afanasyeva465e972014-03-22 17:21:49 -070048class Error : public std::runtime_error
49{
50public:
51 explicit
52 Error(const std::string& what)
53 : std::runtime_error(what)
54 {
55 }
56};
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080057
58enum {
Alexander Afanasyev4b456282014-02-13 00:34:34 -080059 Interest = 5,
60 Data = 6,
61 Name = 7,
Alexander Afanasyev6486d522014-10-23 14:14:11 -070062 ImplicitSha256DigestComponent = 1,
Alexander Afanasyev4b456282014-02-13 00:34:34 -080063 NameComponent = 8,
64 Selectors = 9,
65 Nonce = 10,
Alexander Afanasyev117f5ef2015-06-03 15:07:24 -070066 // <Unassigned> = 11,
Alexander Afanasyev4b456282014-02-13 00:34:34 -080067 InterestLifetime = 12,
Junxiao Shi688a6412017-06-22 10:12:07 +000068 ForwardingHint = 30,
Alexander Afanasyev4b456282014-02-13 00:34:34 -080069 MinSuffixComponents = 13,
70 MaxSuffixComponents = 14,
71 PublisherPublicKeyLocator = 15,
72 Exclude = 16,
73 ChildSelector = 17,
74 MustBeFresh = 18,
75 Any = 19,
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,
Junxiao Shibc5030d2014-09-01 11:53:12 -070085 KeyDigest = 29,
Spyridon Mastorakis3b54e852015-04-07 08:03:25 -070086 LinkPreference = 30,
87 LinkDelegation = 31,
88 SelectedDelegation = 32,
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080089
90 AppPrivateBlock1 = 128,
91 AppPrivateBlock2 = 32767
92};
93
Yingdi Yuebfa4cb2014-06-17 15:28:53 -070094enum SignatureTypeValue {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080095 DigestSha256 = 0,
Yingdi Yuebfa4cb2014-06-17 15:28:53 -070096 SignatureSha256WithRsa = 1,
Alexander Afanasyev117f5ef2015-06-03 15:07:24 -070097 // <Unassigned> = 2,
Yingdi Yuebfa4cb2014-06-17 15:28:53 -070098 SignatureSha256WithEcdsa = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080099};
100
Alexander Afanasyev5f1820e2017-01-04 18:12:42 -0800101std::ostream&
102operator<<(std::ostream& os, const SignatureTypeValue& signatureType);
103
Yingdi Yu7a813892015-06-09 14:19:54 -0700104/** @brief TLV codes for SignatureInfo features
105 * @sa docs/tutorials/certificate-format.rst
106 */
107enum {
108 // SignatureInfo TLVs
109 ValidityPeriod = 253,
110 NotBefore = 254,
Yingdi Yuea382942015-07-17 23:20:44 -0700111 NotAfter = 255,
112
113 AdditionalDescription = 258,
114 DescriptionEntry = 512,
115 DescriptionKey = 513,
116 DescriptionValue = 514
Yingdi Yu7a813892015-06-09 14:19:54 -0700117};
118
Junxiao Shia464b922014-11-12 21:13:06 -0700119/** @brief indicates a possible value of ContentType field
120 */
Yingdi Yuebfa4cb2014-06-17 15:28:53 -0700121enum ContentTypeValue {
Junxiao Shia464b922014-11-12 21:13:06 -0700122 /** @brief indicates content is the actual data bits
123 */
124 ContentType_Blob = 0,
125
126 /** @brief indicates content is another name which identifies actual data content
127 */
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800128 ContentType_Link = 1,
Junxiao Shia464b922014-11-12 21:13:06 -0700129
130 /** @brief indicates content is a public key
131 */
132 ContentType_Key = 2,
133
134 /** @brief indicates a producer generated NACK
Junxiao Shia464b922014-11-12 21:13:06 -0700135 */
136 ContentType_Nack = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800137};
138
139/**
140 * @brief Read VAR-NUMBER in NDN-TLV encoding
Junxiao Shic18aa192017-07-07 06:06:38 +0000141 * @tparam InputIterator an iterator or pointer dereferencable to uint8_t
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800142 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000143 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
144 * the read VAR-NUMBER
145 * @param [in] end End of the buffer
146 * @param [out] number Read VAR-NUMBER
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700147 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000148 * @return true if number was successfully read from input, false otherwise
149 * @note This call never throws exceptions
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700150 */
151template<class InputIterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000152bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700153readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700154
155/**
Junxiao Shic18aa192017-07-07 06:06:38 +0000156 * @brief Read TLV-TYPE
157 * @tparam InputIterator an iterator or pointer dereferencable to uint8_t
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700158 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000159 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
160 * the read TLV-TYPE
161 * @param [in] end End of the buffer
162 * @param [out] type Read TLV-TYPE
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700163 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000164 * @return true if TLV-TYPE was successfully read from input, false otherwise
165 * @note This call never throws exceptions
166 * @note This call is largely equivalent to tlv::readVarNumber, but it will return false if type
167 * is larger than 2^32-1 (TLV-TYPE in this library is implemented as uint32_t)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700168 */
169template<class InputIterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000170bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700171readType(InputIterator& begin, const InputIterator& end, uint32_t& type);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700172
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700173/**
174 * @brief Read VAR-NUMBER in NDN-TLV encoding
Junxiao Shic18aa192017-07-07 06:06:38 +0000175 * @tparam InputIterator an iterator or pointer dereferencable to uint8_t
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700176 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000177 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
178 * the read VAR-NUMBER
179 * @param [in] end End of the buffer
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800180 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000181 * @throw tlv::Error VAR-NUMBER cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800182 */
183template<class InputIterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000184uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700185readVarNumber(InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800186
187/**
188 * @brief Read TLV Type
Junxiao Shic18aa192017-07-07 06:06:38 +0000189 * @tparam InputIterator an iterator or pointer dereferencable to uint8_t
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800190 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000191 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
192 * the read TLV-TYPE
193 * @param [in] end End of the buffer
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700194 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000195 * @throw tlv::Error VAR-NUMBER cannot be read
196 * @note This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
197 * is larger than 2^32-1 (TLV-TYPE in this library is implemented as uint32_t)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800198 */
199template<class InputIterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000200uint32_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700201readType(InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800202
203/**
204 * @brief Get number of bytes necessary to hold value of VAR-NUMBER
205 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000206constexpr size_t
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800207sizeOfVarNumber(uint64_t varNumber);
208
209/**
210 * @brief Write VAR-NUMBER to the specified stream
Junxiao Shic18aa192017-07-07 06:06:38 +0000211 * @return length of written VAR-NUMBER
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800212 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000213size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700214writeVarNumber(std::ostream& os, uint64_t varNumber);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800215
216/**
217 * @brief Read nonNegativeInteger in NDN-TLV encoding
Junxiao Shic18aa192017-07-07 06:06:38 +0000218 * @tparam InputIterator an iterator or pointer dereferencable to uint8_t
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800219 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000220 * @param [in] size size of the nonNegativeInteger
221 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
222 * the read nonNegativeInteger
223 * @param [in] end End of the buffer
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800224 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000225 * @throw tlv::Error number cannot be read
226 * @note How many bytes to read is directly controlled by \p size, which can be either 1, 2, 4, or 8.
227 * If \p size differs from \p std::distance(begin, end), tlv::Error exception will be thrown.
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800228 */
229template<class InputIterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000230uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700231readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800232
233/**
234 * @brief Get number of bytes necessary to hold value of nonNegativeInteger
235 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000236constexpr size_t
237sizeOfNonNegativeInteger(uint64_t integer);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800238
239/**
240 * @brief Write nonNegativeInteger to the specified stream
Junxiao Shic18aa192017-07-07 06:06:38 +0000241 * @return length of written nonNegativeInteger
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800242 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000243size_t
244writeNonNegativeInteger(std::ostream& os, uint64_t integer);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800245
246/////////////////////////////////////////////////////////////////////////////////
247/////////////////////////////////////////////////////////////////////////////////
248/////////////////////////////////////////////////////////////////////////////////
249
250// Inline implementations
251
252/////////////////////////////////////////////////////////////////////////////////
253/////////////////////////////////////////////////////////////////////////////////
254/////////////////////////////////////////////////////////////////////////////////
255
256template<class InputIterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000257bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700258readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700259{
260 if (begin == end)
261 return false;
262
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700263 uint8_t firstOctet = *begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700264 ++begin;
Junxiao Shic18aa192017-07-07 06:06:38 +0000265 if (firstOctet < 253) {
266 number = firstOctet;
267 }
268 else if (firstOctet == 253) {
269 if (end - begin < 2)
270 return false;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700271
Junxiao Shic18aa192017-07-07 06:06:38 +0000272 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin);
273 begin += 2;
274 number = be16toh(value);
275 }
276 else if (firstOctet == 254) {
277 if (end - begin < 4)
278 return false;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700279
Junxiao Shic18aa192017-07-07 06:06:38 +0000280 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin);
281 begin += 4;
282 number = be32toh(value);
283 }
284 else { // if (firstOctet == 255)
285 if (end - begin < 8)
286 return false;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700287
Junxiao Shic18aa192017-07-07 06:06:38 +0000288 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
289 begin += 8;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700290
Junxiao Shic18aa192017-07-07 06:06:38 +0000291 number = be64toh(value);
292 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700293
294 return true;
295}
296
297template<class InputIterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000298bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700299readType(InputIterator& begin, const InputIterator& end, uint32_t& type)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700300{
Mickey Sweatt632e0572014-04-20 00:36:32 -0700301 uint64_t number = 0;
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700302 bool isOk = readVarNumber(begin, end, number);
Junxiao Shic18aa192017-07-07 06:06:38 +0000303 if (!isOk || number > std::numeric_limits<uint32_t>::max()) {
304 return false;
305 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700306
Davide Pesavento8f5cbdc2015-09-13 00:59:28 +0200307 type = static_cast<uint32_t>(number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700308 return true;
309}
310
311template<class InputIterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000312uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700313readVarNumber(InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800314{
315 if (begin == end)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700316 BOOST_THROW_EXCEPTION(Error("Empty buffer during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700317
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700318 uint64_t value;
319 bool isOk = readVarNumber(begin, end, value);
320 if (!isOk)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700321 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700322
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700323 return value;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800324}
325
Yingdi Yu27158392014-01-20 13:04:20 -0800326template<>
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700327inline bool
Junxiao Shi468abc32014-11-04 09:12:47 -0700328readVarNumber<std::istream_iterator<uint8_t>>(std::istream_iterator<uint8_t>& begin,
329 const std::istream_iterator<uint8_t>& end,
330 uint64_t& value)
Yingdi Yu27158392014-01-20 13:04:20 -0800331{
332 if (begin == end)
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700333 return false;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700334
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700335 uint8_t firstOctet = *begin;
Yingdi Yu27158392014-01-20 13:04:20 -0800336 ++begin;
Junxiao Shic18aa192017-07-07 06:06:38 +0000337 if (firstOctet < 253) {
338 value = firstOctet;
339 return true;
340 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700341
Junxiao Shic18aa192017-07-07 06:06:38 +0000342 size_t expectedSize = firstOctet == 253 ? 2 :
343 firstOctet == 254 ? 4 : 8;
344 value = 0;
345 size_t count = 0;
346 for (; begin != end && count < expectedSize; ++count) {
347 value = (value << 8) | *begin;
348 ++begin;
349 }
350 return count == expectedSize;
Yingdi Yu27158392014-01-20 13:04:20 -0800351}
352
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800353template<class InputIterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000354uint32_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700355readType(InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800356{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700357 uint64_t type = readVarNumber(begin, end);
Junxiao Shic18aa192017-07-07 06:06:38 +0000358 if (type > std::numeric_limits<uint32_t>::max()) {
359 BOOST_THROW_EXCEPTION(Error("TLV-TYPE code exceeds allowed maximum"));
360 }
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800361
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700362 return static_cast<uint32_t>(type);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800363}
364
Junxiao Shic18aa192017-07-07 06:06:38 +0000365constexpr size_t
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800366sizeOfVarNumber(uint64_t varNumber)
367{
Junxiao Shic18aa192017-07-07 06:06:38 +0000368 return varNumber < 253 ? 1 :
369 varNumber <= std::numeric_limits<uint16_t>::max() ? 3 :
370 varNumber <= std::numeric_limits<uint32_t>::max() ? 5 : 9;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800371}
372
373inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700374writeVarNumber(std::ostream& os, uint64_t varNumber)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800375{
376 if (varNumber < 253) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200377 os.put(static_cast<char>(varNumber));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800378 return 1;
379 }
380 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200381 os.put(static_cast<char>(253));
382 uint16_t value = htobe16(static_cast<uint16_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700383 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800384 return 3;
385 }
386 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200387 os.put(static_cast<char>(254));
388 uint32_t value = htobe32(static_cast<uint32_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700389 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800390 return 5;
391 }
392 else {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200393 os.put(static_cast<char>(255));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800394 uint64_t value = htobe64(varNumber);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700395 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800396 return 9;
397 }
398}
399
400template<class InputIterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000401uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700402readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800403{
404 switch (size) {
Junxiao Shic18aa192017-07-07 06:06:38 +0000405 case 1: {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800406 if (end - begin < 1)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700407 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700408
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800409 uint8_t value = *begin;
410 begin++;
411 return value;
412 }
Junxiao Shic18aa192017-07-07 06:06:38 +0000413 case 2: {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800414 if (end - begin < 2)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700415 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700416
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700417 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800418 begin += 2;
419 return be16toh(value);
420 }
Junxiao Shic18aa192017-07-07 06:06:38 +0000421 case 4: {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800422 if (end - begin < 4)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700423 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700424
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700425 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800426 begin += 4;
427 return be32toh(value);
428 }
Junxiao Shic18aa192017-07-07 06:06:38 +0000429 case 8: {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800430 if (end - begin < 8)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700431 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700432
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800433 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
434 begin += 8;
435 return be64toh(value);
436 }
437 }
Junxiao Shic18aa192017-07-07 06:06:38 +0000438 BOOST_THROW_EXCEPTION(Error("Invalid length for nonNegativeInteger "
439 "(only 1, 2, 4, and 8 are allowed)"));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800440}
441
Yingdi Yu27158392014-01-20 13:04:20 -0800442template<>
443inline uint64_t
Junxiao Shic18aa192017-07-07 06:06:38 +0000444readNonNegativeInteger<std::istream_iterator<uint8_t>>(size_t size,
445 std::istream_iterator<uint8_t>& begin,
446 const std::istream_iterator<uint8_t>& end)
Yingdi Yu27158392014-01-20 13:04:20 -0800447{
Junxiao Shic18aa192017-07-07 06:06:38 +0000448 if (size != 1 && size != 2 && size != 4 && size != 8) {
449 BOOST_THROW_EXCEPTION(Error("Invalid length for nonNegativeInteger "
450 "(only 1, 2, 4, and 8 are allowed)"));
Yingdi Yu27158392014-01-20 13:04:20 -0800451 }
Junxiao Shic18aa192017-07-07 06:06:38 +0000452
453 uint64_t value = 0;
454 size_t count = 0;
455 for (; begin != end && count < size; ++count) {
456 value = (value << 8) | *begin;
457 begin++;
458 }
459
460 if (count != size) {
461 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
462 }
463
464 return value;
465}
466
467constexpr size_t
468sizeOfNonNegativeInteger(uint64_t integer)
469{
470 return integer <= std::numeric_limits<uint8_t>::max() ? 1 :
471 integer <= std::numeric_limits<uint16_t>::max() ? 2 :
472 integer <= std::numeric_limits<uint32_t>::max() ? 4 : 8;
Yingdi Yu27158392014-01-20 13:04:20 -0800473}
474
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800475inline size_t
Junxiao Shic18aa192017-07-07 06:06:38 +0000476writeNonNegativeInteger(std::ostream& os, uint64_t integer)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800477{
Junxiao Shic18aa192017-07-07 06:06:38 +0000478 if (integer <= std::numeric_limits<uint8_t>::max()) {
479 os.put(static_cast<char>(integer));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800480 return 1;
481 }
Junxiao Shic18aa192017-07-07 06:06:38 +0000482 else if (integer <= std::numeric_limits<uint16_t>::max()) {
483 uint16_t value = htobe16(static_cast<uint16_t>(integer));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700484 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800485 return 2;
486 }
Junxiao Shic18aa192017-07-07 06:06:38 +0000487 else if (integer <= std::numeric_limits<uint32_t>::max()) {
488 uint32_t value = htobe32(static_cast<uint32_t>(integer));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700489 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800490 return 4;
491 }
492 else {
Junxiao Shic18aa192017-07-07 06:06:38 +0000493 uint64_t value = htobe64(integer);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700494 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800495 return 8;
496 }
497}
498
499
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600500} // namespace tlv
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800501} // namespace ndn
502
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700503#endif // NDN_ENCODING_TLV_HPP