blob: 4e9c0090a0382a9e9f2c2ac676a267ba19825e6c [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
Junxiao Shi46a9bd32017-07-14 19:12:11 +000028#include <cstring>
Davide Pesaventoe1789892017-02-26 15:50:52 -050029#include <iostream>
30#include <iterator>
31
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080032namespace ndn {
33
Junxiao Shi468abc32014-11-04 09:12:47 -070034/** @brief practical limit of network layer packet size
35 *
36 * If a packet is longer than this size, library and application MAY drop it.
37 */
38const size_t MAX_NDN_PACKET_SIZE = 8800;
39
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080040/**
41 * @brief Namespace defining NDN-TLV related constants and procedures
42 */
Steve DiBenedetto54ce6682014-07-22 13:22:57 -060043namespace tlv {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080044
Junxiao Shi468abc32014-11-04 09:12:47 -070045/** @brief represents an error in TLV encoding or decoding
46 *
47 * Element::Error SHOULD inherit from this Error class.
48 */
Alexander Afanasyeva465e972014-03-22 17:21:49 -070049class Error : public std::runtime_error
50{
51public:
52 explicit
53 Error(const std::string& what)
54 : std::runtime_error(what)
55 {
56 }
57};
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080058
59enum {
Alexander Afanasyev4b456282014-02-13 00:34:34 -080060 Interest = 5,
61 Data = 6,
62 Name = 7,
Alexander Afanasyev6486d522014-10-23 14:14:11 -070063 ImplicitSha256DigestComponent = 1,
Alexander Afanasyev4b456282014-02-13 00:34:34 -080064 NameComponent = 8,
65 Selectors = 9,
66 Nonce = 10,
Alexander Afanasyev117f5ef2015-06-03 15:07:24 -070067 // <Unassigned> = 11,
Alexander Afanasyev4b456282014-02-13 00:34:34 -080068 InterestLifetime = 12,
Junxiao Shi688a6412017-06-22 10:12:07 +000069 ForwardingHint = 30,
Alexander Afanasyev4b456282014-02-13 00:34:34 -080070 MinSuffixComponents = 13,
71 MaxSuffixComponents = 14,
72 PublisherPublicKeyLocator = 15,
73 Exclude = 16,
74 ChildSelector = 17,
75 MustBeFresh = 18,
76 Any = 19,
77 MetaInfo = 20,
78 Content = 21,
79 SignatureInfo = 22,
80 SignatureValue = 23,
81 ContentType = 24,
82 FreshnessPeriod = 25,
83 FinalBlockId = 26,
84 SignatureType = 27,
85 KeyLocator = 28,
Junxiao Shibc5030d2014-09-01 11:53:12 -070086 KeyDigest = 29,
Spyridon Mastorakis3b54e852015-04-07 08:03:25 -070087 LinkPreference = 30,
88 LinkDelegation = 31,
89 SelectedDelegation = 32,
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080090
91 AppPrivateBlock1 = 128,
92 AppPrivateBlock2 = 32767
93};
94
Yingdi Yuebfa4cb2014-06-17 15:28:53 -070095enum SignatureTypeValue {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080096 DigestSha256 = 0,
Yingdi Yuebfa4cb2014-06-17 15:28:53 -070097 SignatureSha256WithRsa = 1,
Alexander Afanasyev117f5ef2015-06-03 15:07:24 -070098 // <Unassigned> = 2,
Yingdi Yuebfa4cb2014-06-17 15:28:53 -070099 SignatureSha256WithEcdsa = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800100};
101
Alexander Afanasyev5f1820e2017-01-04 18:12:42 -0800102std::ostream&
103operator<<(std::ostream& os, const SignatureTypeValue& signatureType);
104
Yingdi Yu7a813892015-06-09 14:19:54 -0700105/** @brief TLV codes for SignatureInfo features
106 * @sa docs/tutorials/certificate-format.rst
107 */
108enum {
109 // SignatureInfo TLVs
110 ValidityPeriod = 253,
111 NotBefore = 254,
Yingdi Yuea382942015-07-17 23:20:44 -0700112 NotAfter = 255,
113
114 AdditionalDescription = 258,
115 DescriptionEntry = 512,
116 DescriptionKey = 513,
117 DescriptionValue = 514
Yingdi Yu7a813892015-06-09 14:19:54 -0700118};
119
Junxiao Shia464b922014-11-12 21:13:06 -0700120/** @brief indicates a possible value of ContentType field
121 */
Yingdi Yuebfa4cb2014-06-17 15:28:53 -0700122enum ContentTypeValue {
Junxiao Shia464b922014-11-12 21:13:06 -0700123 /** @brief indicates content is the actual data bits
124 */
125 ContentType_Blob = 0,
126
127 /** @brief indicates content is another name which identifies actual data content
128 */
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800129 ContentType_Link = 1,
Junxiao Shia464b922014-11-12 21:13:06 -0700130
131 /** @brief indicates content is a public key
132 */
133 ContentType_Key = 2,
134
135 /** @brief indicates a producer generated NACK
Junxiao Shia464b922014-11-12 21:13:06 -0700136 */
137 ContentType_Nack = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800138};
139
140/**
141 * @brief Read VAR-NUMBER in NDN-TLV encoding
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000142 * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800143 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000144 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
145 * the read VAR-NUMBER
146 * @param [in] end End of the buffer
147 * @param [out] number Read VAR-NUMBER
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700148 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000149 * @return true if number was successfully read from input, false otherwise
150 * @note This call never throws exceptions
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700151 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000152template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000153bool
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000154readVarNumber(Iterator& begin, const Iterator& end, uint64_t& number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700155
156/**
Junxiao Shic18aa192017-07-07 06:06:38 +0000157 * @brief Read TLV-TYPE
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000158 * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700159 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000160 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
161 * the read TLV-TYPE
162 * @param [in] end End of the buffer
163 * @param [out] type Read TLV-TYPE
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700164 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000165 * @return true if TLV-TYPE was successfully read from input, false otherwise
166 * @note This call never throws exceptions
167 * @note This call is largely equivalent to tlv::readVarNumber, but it will return false if type
168 * is larger than 2^32-1 (TLV-TYPE in this library is implemented as uint32_t)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700169 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000170template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000171bool
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000172readType(Iterator& begin, const Iterator& end, uint32_t& type);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700173
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700174/**
175 * @brief Read VAR-NUMBER in NDN-TLV encoding
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000176 * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700177 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000178 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
179 * the read VAR-NUMBER
180 * @param [in] end End of the buffer
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800181 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000182 * @throw tlv::Error VAR-NUMBER cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800183 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000184template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000185uint64_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000186readVarNumber(Iterator& begin, const Iterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800187
188/**
189 * @brief Read TLV Type
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000190 * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800191 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000192 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
193 * the read TLV-TYPE
194 * @param [in] end End of the buffer
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700195 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000196 * @throw tlv::Error VAR-NUMBER cannot be read
197 * @note This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
198 * is larger than 2^32-1 (TLV-TYPE in this library is implemented as uint32_t)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800199 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000200template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000201uint32_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000202readType(Iterator& begin, const Iterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800203
204/**
205 * @brief Get number of bytes necessary to hold value of VAR-NUMBER
206 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000207constexpr size_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000208sizeOfVarNumber(uint64_t number);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800209
210/**
211 * @brief Write VAR-NUMBER to the specified stream
Junxiao Shic18aa192017-07-07 06:06:38 +0000212 * @return length of written VAR-NUMBER
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800213 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000214size_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000215writeVarNumber(std::ostream& os, uint64_t number);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800216
217/**
218 * @brief Read nonNegativeInteger in NDN-TLV encoding
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000219 * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800220 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000221 * @param [in] size size of the nonNegativeInteger
222 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
223 * the read nonNegativeInteger
224 * @param [in] end End of the buffer
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800225 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000226 * @throw tlv::Error number cannot be read
227 * @note How many bytes to read is directly controlled by \p size, which can be either 1, 2, 4, or 8.
228 * If \p size differs from \p std::distance(begin, end), tlv::Error exception will be thrown.
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800229 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000230template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000231uint64_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000232readNonNegativeInteger(size_t size, Iterator& begin, const Iterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800233
234/**
235 * @brief Get number of bytes necessary to hold value of nonNegativeInteger
236 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000237constexpr size_t
238sizeOfNonNegativeInteger(uint64_t integer);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800239
240/**
241 * @brief Write nonNegativeInteger to the specified stream
Junxiao Shic18aa192017-07-07 06:06:38 +0000242 * @return length of written nonNegativeInteger
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800243 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000244size_t
245writeNonNegativeInteger(std::ostream& os, uint64_t integer);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800246
247/////////////////////////////////////////////////////////////////////////////////
248/////////////////////////////////////////////////////////////////////////////////
249/////////////////////////////////////////////////////////////////////////////////
250
251// Inline implementations
252
253/////////////////////////////////////////////////////////////////////////////////
254/////////////////////////////////////////////////////////////////////////////////
255/////////////////////////////////////////////////////////////////////////////////
256
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000257namespace detail {
258
259/** @brief Function object to read a number from InputIterator
260 */
261template<typename Iterator>
262class ReadNumberSlow
263{
264public:
265 bool
266 operator()(size_t size, Iterator& begin, const Iterator& end, uint64_t& number) const
267 {
268 number = 0;
269 size_t count = 0;
270 for (; begin != end && count < size; ++begin, ++count) {
271 number = (number << 8) | *begin;
272 }
273 return count == size;
274 }
275};
276
277/** @brief Function object to read a number from ContiguousIterator
278 */
279template<typename Iterator>
280class ReadNumberFast
281{
282public:
283 bool
284 operator()(size_t size, Iterator& begin, const Iterator& end, uint64_t& number) const
285 {
286 if (begin + size > end) {
287 return false;
288 }
289
290 switch (size) {
291 case 1: {
292 number = *begin;
293 ++begin;
294 return true;
295 }
296 case 2: {
297 uint16_t value = 0;
298 std::memcpy(&value, &*begin, 2);
299 begin += 2;
300 number = be16toh(value);
301 return true;
302 }
303 case 4: {
304 uint32_t value = 0;
305 std::memcpy(&value, &*begin, 4);
306 begin += 4;
307 number = be32toh(value);
308 return true;
309 }
310 case 8: {
311 uint64_t value = 0;
312 std::memcpy(&value, &*begin, 8);
313 begin += 8;
314 number = be64toh(value);
315 return true;
316 }
317 default: {
318 BOOST_ASSERT(false);
319 return false;
320 }
321 }
322 }
323};
324
325/** @brief Determine whether to select ReadNumber implementation for ContiguousIterator
326 *
327 * This is not a full ContiguousIterator detection implementation. It returns true for the most
328 * common ContiguousIterator types used with TLV decoding function templates.
329 */
330template<typename Iterator,
331 typename DecayedIterator = typename std::decay<Iterator>::type,
332 typename ValueType = typename std::iterator_traits<DecayedIterator>::value_type>
333constexpr bool
334shouldSelectContiguousReadNumber()
335{
336 return (std::is_convertible<DecayedIterator, const ValueType*>::value ||
337 std::is_convertible<DecayedIterator, typename std::basic_string<ValueType>::const_iterator>::value ||
338 std::is_convertible<DecayedIterator, typename std::vector<ValueType>::const_iterator>::value) &&
339 (std::is_same<ValueType, uint8_t>::value ||
340 std::is_same<ValueType, int8_t>::value ||
341 std::is_same<ValueType, char>::value ||
342 std::is_same<ValueType, unsigned char>::value ||
343 std::is_same<ValueType, signed char>::value);
344}
345
346template<typename Iterator>
347class ReadNumber : public std::conditional<shouldSelectContiguousReadNumber<Iterator>(),
348 ReadNumberFast<Iterator>, ReadNumberSlow<Iterator>>::type
349{
350};
351
352} // namespace detail
353
354template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000355bool
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000356readVarNumber(Iterator& begin, const Iterator& end, uint64_t& number)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700357{
358 if (begin == end)
359 return false;
360
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700361 uint8_t firstOctet = *begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700362 ++begin;
Junxiao Shic18aa192017-07-07 06:06:38 +0000363 if (firstOctet < 253) {
364 number = firstOctet;
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000365 return true;
Junxiao Shic18aa192017-07-07 06:06:38 +0000366 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700367
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000368 size_t size = firstOctet == 253 ? 2 :
369 firstOctet == 254 ? 4 : 8;
370 return detail::ReadNumber<Iterator>()(size, begin, end, number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700371}
372
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000373template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000374bool
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000375readType(Iterator& begin, const Iterator& end, uint32_t& type)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700376{
Mickey Sweatt632e0572014-04-20 00:36:32 -0700377 uint64_t number = 0;
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700378 bool isOk = readVarNumber(begin, end, number);
Junxiao Shic18aa192017-07-07 06:06:38 +0000379 if (!isOk || number > std::numeric_limits<uint32_t>::max()) {
380 return false;
381 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700382
Davide Pesavento8f5cbdc2015-09-13 00:59:28 +0200383 type = static_cast<uint32_t>(number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700384 return true;
385}
386
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000387template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000388uint64_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000389readVarNumber(Iterator& begin, const Iterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800390{
391 if (begin == end)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700392 BOOST_THROW_EXCEPTION(Error("Empty buffer during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700393
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000394 uint64_t value = 0;
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700395 bool isOk = readVarNumber(begin, end, value);
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000396 if (!isOk) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700397 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000398 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700399
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700400 return value;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800401}
402
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000403template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000404uint32_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000405readType(Iterator& begin, const Iterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800406{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700407 uint64_t type = readVarNumber(begin, end);
Junxiao Shic18aa192017-07-07 06:06:38 +0000408 if (type > std::numeric_limits<uint32_t>::max()) {
409 BOOST_THROW_EXCEPTION(Error("TLV-TYPE code exceeds allowed maximum"));
410 }
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800411
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700412 return static_cast<uint32_t>(type);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800413}
414
Junxiao Shic18aa192017-07-07 06:06:38 +0000415constexpr size_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000416sizeOfVarNumber(uint64_t number)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800417{
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000418 return number < 253 ? 1 :
419 number <= std::numeric_limits<uint16_t>::max() ? 3 :
420 number <= std::numeric_limits<uint32_t>::max() ? 5 : 9;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800421}
422
423inline size_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000424writeVarNumber(std::ostream& os, uint64_t number)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800425{
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000426 if (number < 253) {
427 os.put(static_cast<char>(number));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800428 return 1;
429 }
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000430 else if (number <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200431 os.put(static_cast<char>(253));
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000432 uint16_t value = htobe16(static_cast<uint16_t>(number));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700433 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800434 return 3;
435 }
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000436 else if (number <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200437 os.put(static_cast<char>(254));
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000438 uint32_t value = htobe32(static_cast<uint32_t>(number));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700439 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800440 return 5;
441 }
442 else {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200443 os.put(static_cast<char>(255));
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000444 uint64_t value = htobe64(number);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700445 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800446 return 9;
447 }
448}
449
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000450template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000451uint64_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000452readNonNegativeInteger(size_t size, Iterator& begin, const Iterator& end)
Yingdi Yu27158392014-01-20 13:04:20 -0800453{
Junxiao Shic18aa192017-07-07 06:06:38 +0000454 if (size != 1 && size != 2 && size != 4 && size != 8) {
455 BOOST_THROW_EXCEPTION(Error("Invalid length for nonNegativeInteger "
456 "(only 1, 2, 4, and 8 are allowed)"));
Yingdi Yu27158392014-01-20 13:04:20 -0800457 }
Junxiao Shic18aa192017-07-07 06:06:38 +0000458
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000459 uint64_t number = 0;
460 bool isOk = detail::ReadNumber<Iterator>()(size, begin, end, number);
461 if (!isOk) {
Junxiao Shic18aa192017-07-07 06:06:38 +0000462 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
463 }
464
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000465 return number;
Junxiao Shic18aa192017-07-07 06:06:38 +0000466}
467
468constexpr size_t
469sizeOfNonNegativeInteger(uint64_t integer)
470{
471 return integer <= std::numeric_limits<uint8_t>::max() ? 1 :
472 integer <= std::numeric_limits<uint16_t>::max() ? 2 :
473 integer <= std::numeric_limits<uint32_t>::max() ? 4 : 8;
Yingdi Yu27158392014-01-20 13:04:20 -0800474}
475
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800476inline size_t
Junxiao Shic18aa192017-07-07 06:06:38 +0000477writeNonNegativeInteger(std::ostream& os, uint64_t integer)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800478{
Junxiao Shic18aa192017-07-07 06:06:38 +0000479 if (integer <= std::numeric_limits<uint8_t>::max()) {
480 os.put(static_cast<char>(integer));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800481 return 1;
482 }
Junxiao Shic18aa192017-07-07 06:06:38 +0000483 else if (integer <= std::numeric_limits<uint16_t>::max()) {
484 uint16_t value = htobe16(static_cast<uint16_t>(integer));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700485 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800486 return 2;
487 }
Junxiao Shic18aa192017-07-07 06:06:38 +0000488 else if (integer <= std::numeric_limits<uint32_t>::max()) {
489 uint32_t value = htobe32(static_cast<uint32_t>(integer));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700490 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800491 return 4;
492 }
493 else {
Junxiao Shic18aa192017-07-07 06:06:38 +0000494 uint64_t value = htobe64(integer);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700495 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800496 return 8;
497 }
498}
499
500
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600501} // namespace tlv
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800502} // namespace ndn
503
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700504#endif // NDN_ENCODING_TLV_HPP