blob: 52115f95b48861272bf8ba6edfd06527e8771858 [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 <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 Afanasyev117f5ef2015-06-03 15:07:24 -070071 // <Unassigned> = 11,
Alexander Afanasyev4b456282014-02-13 00:34:34 -080072 InterestLifetime = 12,
Junxiao Shi688a6412017-06-22 10:12:07 +000073 ForwardingHint = 30,
Alexander Afanasyev4b456282014-02-13 00:34:34 -080074 MinSuffixComponents = 13,
75 MaxSuffixComponents = 14,
76 PublisherPublicKeyLocator = 15,
Davide Pesavento4ab3be22017-07-18 00:38:52 -040077 Exclude = 16,
78 ChildSelector = 17,
79 MustBeFresh = 18,
80 Any = 19,
81 MetaInfo = 20,
82 Content = 21,
83 SignatureInfo = 22,
Alexander Afanasyev4b456282014-02-13 00:34:34 -080084 SignatureValue = 23,
85 ContentType = 24,
86 FreshnessPeriod = 25,
Davide Pesavento4ab3be22017-07-18 00:38:52 -040087 FinalBlockId = 26,
88 SignatureType = 27,
89 KeyLocator = 28,
90 KeyDigest = 29,
91 LinkPreference = 30,
92 LinkDelegation = 31,
Spyridon Mastorakis3b54e852015-04-07 08:03:25 -070093 SelectedDelegation = 32,
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080094
95 AppPrivateBlock1 = 128,
96 AppPrivateBlock2 = 32767
97};
98
Davide Pesavento7e6f6f82017-10-31 18:05:28 -040099enum SignatureTypeValue : uint16_t {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800100 DigestSha256 = 0,
Yingdi Yuebfa4cb2014-06-17 15:28:53 -0700101 SignatureSha256WithRsa = 1,
Alexander Afanasyev117f5ef2015-06-03 15:07:24 -0700102 // <Unassigned> = 2,
Yingdi Yuebfa4cb2014-06-17 15:28:53 -0700103 SignatureSha256WithEcdsa = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800104};
105
Alexander Afanasyev5f1820e2017-01-04 18:12:42 -0800106std::ostream&
Davide Pesavento7e6f6f82017-10-31 18:05:28 -0400107operator<<(std::ostream& os, SignatureTypeValue signatureType);
Alexander Afanasyev5f1820e2017-01-04 18:12:42 -0800108
Junxiao Shi7d3c14b2017-08-05 16:34:39 +0000109/** @brief TLV-TYPE numbers for SignatureInfo features
Yingdi Yu7a813892015-06-09 14:19:54 -0700110 * @sa docs/tutorials/certificate-format.rst
111 */
112enum {
Yingdi Yu7a813892015-06-09 14:19:54 -0700113 ValidityPeriod = 253,
114 NotBefore = 254,
Yingdi Yuea382942015-07-17 23:20:44 -0700115 NotAfter = 255,
116
117 AdditionalDescription = 258,
118 DescriptionEntry = 512,
119 DescriptionKey = 513,
120 DescriptionValue = 514
Yingdi Yu7a813892015-06-09 14:19:54 -0700121};
122
Junxiao Shia464b922014-11-12 21:13:06 -0700123/** @brief indicates a possible value of ContentType field
124 */
Yingdi Yuebfa4cb2014-06-17 15:28:53 -0700125enum ContentTypeValue {
Junxiao Shia464b922014-11-12 21:13:06 -0700126 /** @brief indicates content is the actual data bits
127 */
128 ContentType_Blob = 0,
129
130 /** @brief indicates content is another name which identifies actual data content
131 */
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800132 ContentType_Link = 1,
Junxiao Shia464b922014-11-12 21:13:06 -0700133
134 /** @brief indicates content is a public key
135 */
136 ContentType_Key = 2,
137
138 /** @brief indicates a producer generated NACK
Junxiao Shia464b922014-11-12 21:13:06 -0700139 */
140 ContentType_Nack = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800141};
142
143/**
144 * @brief Read VAR-NUMBER in NDN-TLV encoding
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000145 * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800146 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000147 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
148 * the read VAR-NUMBER
149 * @param [in] end End of the buffer
150 * @param [out] number Read VAR-NUMBER
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700151 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000152 * @return true if number was successfully read from input, false otherwise
153 * @note This call never throws exceptions
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700154 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000155template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000156bool
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000157readVarNumber(Iterator& begin, const Iterator& end, uint64_t& number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700158
159/**
Junxiao Shic18aa192017-07-07 06:06:38 +0000160 * @brief Read TLV-TYPE
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000161 * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700162 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000163 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
164 * the read TLV-TYPE
165 * @param [in] end End of the buffer
166 * @param [out] type Read TLV-TYPE
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700167 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000168 * @return true if TLV-TYPE was successfully read from input, false otherwise
169 * @note This call never throws exceptions
170 * @note This call is largely equivalent to tlv::readVarNumber, but it will return false if type
171 * is larger than 2^32-1 (TLV-TYPE in this library is implemented as uint32_t)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700172 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000173template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000174bool
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000175readType(Iterator& begin, const Iterator& end, uint32_t& type);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700176
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700177/**
178 * @brief Read VAR-NUMBER in NDN-TLV encoding
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000179 * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700180 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000181 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
182 * the read VAR-NUMBER
183 * @param [in] end End of the buffer
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800184 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000185 * @throw tlv::Error VAR-NUMBER cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800186 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000187template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000188uint64_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000189readVarNumber(Iterator& begin, const Iterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800190
191/**
192 * @brief Read TLV Type
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000193 * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800194 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000195 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
196 * the read TLV-TYPE
197 * @param [in] end End of the buffer
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700198 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000199 * @throw tlv::Error VAR-NUMBER cannot be read
200 * @note This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
201 * is larger than 2^32-1 (TLV-TYPE in this library is implemented as uint32_t)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800202 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000203template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000204uint32_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000205readType(Iterator& begin, const Iterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800206
207/**
208 * @brief Get number of bytes necessary to hold value of VAR-NUMBER
209 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000210constexpr size_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000211sizeOfVarNumber(uint64_t number);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800212
213/**
214 * @brief Write VAR-NUMBER to the specified stream
Junxiao Shic18aa192017-07-07 06:06:38 +0000215 * @return length of written VAR-NUMBER
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800216 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000217size_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000218writeVarNumber(std::ostream& os, uint64_t number);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800219
220/**
221 * @brief Read nonNegativeInteger in NDN-TLV encoding
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000222 * @tparam Iterator an iterator or pointer whose value is assignable to uint8_t
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800223 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000224 * @param [in] size size of the nonNegativeInteger
225 * @param [inout] begin Begin of the buffer, will be incremented to point to the first byte after
226 * the read nonNegativeInteger
227 * @param [in] end End of the buffer
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800228 *
Junxiao Shic18aa192017-07-07 06:06:38 +0000229 * @throw tlv::Error number cannot be read
230 * @note How many bytes to read is directly controlled by \p size, which can be either 1, 2, 4, or 8.
231 * If \p size differs from \p std::distance(begin, end), tlv::Error exception will be thrown.
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800232 */
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000233template<typename Iterator>
Junxiao Shic18aa192017-07-07 06:06:38 +0000234uint64_t
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000235readNonNegativeInteger(size_t size, Iterator& begin, const Iterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800236
237/**
238 * @brief Get number of bytes necessary to hold value of nonNegativeInteger
239 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000240constexpr size_t
241sizeOfNonNegativeInteger(uint64_t integer);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800242
243/**
244 * @brief Write nonNegativeInteger to the specified stream
Junxiao Shic18aa192017-07-07 06:06:38 +0000245 * @return length of written nonNegativeInteger
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800246 */
Junxiao Shic18aa192017-07-07 06:06:38 +0000247size_t
248writeNonNegativeInteger(std::ostream& os, uint64_t integer);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800249
250/////////////////////////////////////////////////////////////////////////////////
251/////////////////////////////////////////////////////////////////////////////////
252/////////////////////////////////////////////////////////////////////////////////
253
Davide Pesavento4ab3be22017-07-18 00:38:52 -0400254// Inline definitions
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800255
256/////////////////////////////////////////////////////////////////////////////////
257/////////////////////////////////////////////////////////////////////////////////
258/////////////////////////////////////////////////////////////////////////////////
259
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000260namespace detail {
261
262/** @brief Function object to read a number from InputIterator
263 */
264template<typename Iterator>
265class ReadNumberSlow
266{
267public:
268 bool
269 operator()(size_t size, Iterator& begin, const Iterator& end, uint64_t& number) const
270 {
271 number = 0;
272 size_t count = 0;
273 for (; begin != end && count < size; ++begin, ++count) {
274 number = (number << 8) | *begin;
275 }
276 return count == size;
277 }
278};
279
280/** @brief Function object to read a number from ContiguousIterator
281 */
282template<typename Iterator>
283class ReadNumberFast
284{
285public:
286 bool
287 operator()(size_t size, Iterator& begin, const Iterator& end, uint64_t& number) const
288 {
289 if (begin + size > end) {
290 return false;
291 }
292
293 switch (size) {
294 case 1: {
295 number = *begin;
296 ++begin;
297 return true;
298 }
299 case 2: {
300 uint16_t value = 0;
301 std::memcpy(&value, &*begin, 2);
302 begin += 2;
303 number = be16toh(value);
304 return true;
305 }
306 case 4: {
307 uint32_t value = 0;
308 std::memcpy(&value, &*begin, 4);
309 begin += 4;
310 number = be32toh(value);
311 return true;
312 }
313 case 8: {
314 uint64_t value = 0;
315 std::memcpy(&value, &*begin, 8);
316 begin += 8;
317 number = be64toh(value);
318 return true;
319 }
320 default: {
321 BOOST_ASSERT(false);
322 return false;
323 }
324 }
325 }
326};
327
328/** @brief Determine whether to select ReadNumber implementation for ContiguousIterator
329 *
330 * This is not a full ContiguousIterator detection implementation. It returns true for the most
331 * common ContiguousIterator types used with TLV decoding function templates.
332 */
333template<typename Iterator,
334 typename DecayedIterator = typename std::decay<Iterator>::type,
335 typename ValueType = typename std::iterator_traits<DecayedIterator>::value_type>
336constexpr bool
337shouldSelectContiguousReadNumber()
338{
339 return (std::is_convertible<DecayedIterator, const ValueType*>::value ||
340 std::is_convertible<DecayedIterator, typename std::basic_string<ValueType>::const_iterator>::value ||
341 std::is_convertible<DecayedIterator, typename std::vector<ValueType>::const_iterator>::value) &&
Davide Pesavento4ab3be22017-07-18 00:38:52 -0400342 sizeof(ValueType) == 1 &&
343 !std::is_same<ValueType, bool>::value;
Junxiao Shi46a9bd32017-07-14 19:12:11 +0000344}
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()) {
Junxiao Shi7d3c14b2017-08-05 16:34:39 +0000409 BOOST_THROW_EXCEPTION(Error("TLV-TYPE number exceeds allowed maximum"));
Junxiao Shic18aa192017-07-07 06:06:38 +0000410 }
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