blob: c9a652009d349f5d8e6c2f90ff12b862dd17fccd [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07002/**
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 Afanasyev54467af2014-01-06 15:45:32 -080025#include <stdexcept>
Alexander Afanasyevd1de3972014-08-14 19:47:41 -070026#include <iostream>
Yingdi Yu27158392014-01-20 13:04:20 -080027#include <iterator>
Davide Pesaventodfe9c6b2014-08-25 21:17:10 +020028#include <limits>
Alexander Afanasyevd1de3972014-08-14 19:47:41 -070029
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080030#include "buffer.hpp"
Alexander Afanasyev200dd6f2014-01-28 19:04:25 -080031#include "endian.hpp"
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080032
33namespace 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
60enum {
Alexander Afanasyev4b456282014-02-13 00:34:34 -080061 Interest = 5,
62 Data = 6,
63 Name = 7,
Alexander Afanasyev6486d522014-10-23 14:14:11 -070064 ImplicitSha256DigestComponent = 1,
Alexander Afanasyev4b456282014-02-13 00:34:34 -080065 NameComponent = 8,
66 Selectors = 9,
67 Nonce = 10,
Alexander Afanasyev117f5ef2015-06-03 15:07:24 -070068 // <Unassigned> = 11,
Alexander Afanasyev4b456282014-02-13 00:34:34 -080069 InterestLifetime = 12,
70 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
136 * @warning Experimental. Not defined in NDN-TLV spec.
137 */
138 ContentType_Nack = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800139};
140
141/**
142 * @brief Read VAR-NUMBER in NDN-TLV encoding
143 *
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700144 * @param [in] begin Begin (pointer or iterator) of the buffer
145 * @param [in] end End (pointer or iterator) of the buffer
146 * @param [out] number Read number
147 *
148 * @throws This call never throws exception
149 *
150 * @return true if number successfully read from input, false otherwise
151 */
152template<class InputIterator>
153inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700154readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700155
156/**
157 * @brief Read TLV Type
158 *
159 * @param [in] begin Begin (pointer or iterator) of the buffer
160 * @param [in] end End (pointer or iterator) of the buffer
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700161 * @param [out] type Read type number
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700162 *
163 * @throws This call never throws exception
164 *
165 * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
166 * is larger than 2^32-1 (type in this library is implemented as uint32_t)
167 */
168template<class InputIterator>
169inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700170readType(InputIterator& begin, const InputIterator& end, uint32_t& type);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700171
172
173/**
174 * @brief Read VAR-NUMBER in NDN-TLV encoding
175 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600176 * @throws This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800177 *
178 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
179 */
180template<class InputIterator>
181inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700182readVarNumber(InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800183
184/**
185 * @brief Read TLV Type
186 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600187 * @throws This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700188 *
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800189 * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
190 * is larger than 2^32-1 (type in this library is implemented as uint32_t)
191 */
192template<class InputIterator>
193inline uint32_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700194readType(InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800195
196/**
197 * @brief Get number of bytes necessary to hold value of VAR-NUMBER
198 */
199inline size_t
200sizeOfVarNumber(uint64_t varNumber);
201
202/**
203 * @brief Write VAR-NUMBER to the specified stream
204 */
205inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700206writeVarNumber(std::ostream& os, uint64_t varNumber);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800207
208/**
209 * @brief Read nonNegativeInteger in NDN-TLV encoding
210 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600211 * This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800212 *
213 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
214 *
215 * How many bytes will be read is directly controlled by the size parameter, which can be either
216 * 1, 2, 4, or 8. If the value of size is different, then an exception will be thrown.
217 */
218template<class InputIterator>
219inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700220readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800221
222/**
223 * @brief Get number of bytes necessary to hold value of nonNegativeInteger
224 */
225inline size_t
226sizeOfNonNegativeInteger(uint64_t varNumber);
227
228/**
229 * @brief Write nonNegativeInteger to the specified stream
230 */
231inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700232writeNonNegativeInteger(std::ostream& os, uint64_t varNumber);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800233
234/////////////////////////////////////////////////////////////////////////////////
235/////////////////////////////////////////////////////////////////////////////////
236/////////////////////////////////////////////////////////////////////////////////
237
238// Inline implementations
239
240/////////////////////////////////////////////////////////////////////////////////
241/////////////////////////////////////////////////////////////////////////////////
242/////////////////////////////////////////////////////////////////////////////////
243
244template<class InputIterator>
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700245inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700246readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700247{
248 if (begin == end)
249 return false;
250
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700251 uint8_t firstOctet = *begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700252 ++begin;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700253 if (firstOctet < 253)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700254 {
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700255 number = firstOctet;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700256 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700257 else if (firstOctet == 253)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700258 {
259 if (end - begin < 2)
260 return false;
261
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700262 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700263 begin += 2;
264 number = be16toh(value);
265 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700266 else if (firstOctet == 254)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700267 {
268 if (end - begin < 4)
269 return false;
270
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700271 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700272 begin += 4;
273 number = be32toh(value);
274 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700275 else // if (firstOctet == 255)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700276 {
277 if (end - begin < 8)
278 return false;
279
280 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
281 begin += 8;
282
283 number = be64toh(value);
284 }
285
286 return true;
287}
288
289template<class InputIterator>
290inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700291readType(InputIterator& begin, const InputIterator& end, uint32_t& type)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700292{
Mickey Sweatt632e0572014-04-20 00:36:32 -0700293 uint64_t number = 0;
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700294 bool isOk = readVarNumber(begin, end, number);
295 if (!isOk || number > std::numeric_limits<uint32_t>::max())
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700296 {
297 return false;
298 }
299
Davide Pesavento8f5cbdc2015-09-13 00:59:28 +0200300 type = static_cast<uint32_t>(number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700301 return true;
302}
303
304template<class InputIterator>
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800305inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700306readVarNumber(InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800307{
308 if (begin == end)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700309 BOOST_THROW_EXCEPTION(Error("Empty buffer during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700310
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700311 uint64_t value;
312 bool isOk = readVarNumber(begin, end, value);
313 if (!isOk)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700314 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700315
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700316 return value;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800317}
318
Yingdi Yu27158392014-01-20 13:04:20 -0800319template<>
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700320inline bool
Junxiao Shi468abc32014-11-04 09:12:47 -0700321readVarNumber<std::istream_iterator<uint8_t>>(std::istream_iterator<uint8_t>& begin,
322 const std::istream_iterator<uint8_t>& end,
323 uint64_t& value)
Yingdi Yu27158392014-01-20 13:04:20 -0800324{
325 if (begin == end)
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700326 return false;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700327
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700328 uint8_t firstOctet = *begin;
Yingdi Yu27158392014-01-20 13:04:20 -0800329 ++begin;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700330 if (firstOctet < 253)
Yingdi Yu27158392014-01-20 13:04:20 -0800331 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700332 value = firstOctet;
Yingdi Yu27158392014-01-20 13:04:20 -0800333 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700334 else if (firstOctet == 253)
Yingdi Yu27158392014-01-20 13:04:20 -0800335 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700336 value = 0;
337 size_t count = 0;
338 for (; begin != end && count < 2; ++count)
339 {
340 value = ((value << 8) | *begin);
341 begin++;
342 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700343
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700344 if (count != 2)
345 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800346 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700347 else if (firstOctet == 254)
Yingdi Yu27158392014-01-20 13:04:20 -0800348 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700349 value = 0;
350 size_t count = 0;
351 for (; begin != end && count < 4; ++count)
352 {
353 value = ((value << 8) | *begin);
354 begin++;
355 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700356
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700357 if (count != 4)
358 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800359 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700360 else // if (firstOctet == 255)
Yingdi Yu27158392014-01-20 13:04:20 -0800361 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700362 value = 0;
363 size_t count = 0;
364 for (; begin != end && count < 8; ++count)
365 {
366 value = ((value << 8) | *begin);
367 begin++;
368 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700369
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700370 if (count != 8)
371 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800372 }
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700373
374 return true;
Yingdi Yu27158392014-01-20 13:04:20 -0800375}
376
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800377template<class InputIterator>
378inline uint32_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700379readType(InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800380{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700381 uint64_t type = readVarNumber(begin, end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800382 if (type > std::numeric_limits<uint32_t>::max())
383 {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700384 BOOST_THROW_EXCEPTION(Error("TLV type code exceeds allowed maximum"));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800385 }
386
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700387 return static_cast<uint32_t>(type);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800388}
389
390size_t
391sizeOfVarNumber(uint64_t varNumber)
392{
393 if (varNumber < 253) {
394 return 1;
395 }
396 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
397 return 3;
398 }
399 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
400 return 5;
401 }
402 else {
403 return 9;
404 }
405}
406
407inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700408writeVarNumber(std::ostream& os, uint64_t varNumber)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800409{
410 if (varNumber < 253) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200411 os.put(static_cast<char>(varNumber));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800412 return 1;
413 }
414 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200415 os.put(static_cast<char>(253));
416 uint16_t value = htobe16(static_cast<uint16_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700417 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800418 return 3;
419 }
420 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200421 os.put(static_cast<char>(254));
422 uint32_t value = htobe32(static_cast<uint32_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700423 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800424 return 5;
425 }
426 else {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200427 os.put(static_cast<char>(255));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800428 uint64_t value = htobe64(varNumber);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700429 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800430 return 9;
431 }
432}
433
434template<class InputIterator>
435inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700436readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800437{
438 switch (size) {
439 case 1:
440 {
441 if (end - begin < 1)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700442 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700443
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800444 uint8_t value = *begin;
445 begin++;
446 return value;
447 }
448 case 2:
449 {
450 if (end - begin < 2)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700451 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700452
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700453 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800454 begin += 2;
455 return be16toh(value);
456 }
457 case 4:
458 {
459 if (end - begin < 4)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700460 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700461
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700462 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800463 begin += 4;
464 return be32toh(value);
465 }
466 case 8:
467 {
468 if (end - begin < 8)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700469 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700470
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800471 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
472 begin += 8;
473 return be64toh(value);
474 }
475 }
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700476 BOOST_THROW_EXCEPTION(Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)"));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800477}
478
Yingdi Yu27158392014-01-20 13:04:20 -0800479template<>
480inline uint64_t
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700481readNonNegativeInteger<std::istream_iterator<uint8_t> >(size_t size,
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700482 std::istream_iterator<uint8_t>& begin,
483 const std::istream_iterator<uint8_t>& end)
Yingdi Yu27158392014-01-20 13:04:20 -0800484{
485 switch (size) {
486 case 1:
487 {
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700488 if (begin == end)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700489 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700490
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700491 uint64_t value = *begin;
Yingdi Yu27158392014-01-20 13:04:20 -0800492 begin++;
493 return value;
494 }
495 case 2:
496 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700497 uint64_t value = 0;
498 size_t count = 0;
499 for (; begin != end && count < 2; ++count)
500 {
501 value = ((value << 8) | *begin);
502 begin++;
503 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700504
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700505 if (count != 2)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700506 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700507
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700508 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800509 }
510 case 4:
511 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700512 uint64_t value = 0;
513 size_t count = 0;
514 for (; begin != end && count < 4; ++count)
515 {
516 value = ((value << 8) | *begin);
517 begin++;
518 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700519
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700520 if (count != 4)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700521 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700522
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700523 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800524 }
525 case 8:
526 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700527 uint64_t value = 0;
528 size_t count = 0;
529 for (; begin != end && count < 8; ++count)
530 {
531 value = ((value << 8) | *begin);
532 begin++;
533 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700534
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700535 if (count != 8)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700536 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700537
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700538 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800539 }
540 }
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700541 BOOST_THROW_EXCEPTION(Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)"));
Yingdi Yu27158392014-01-20 13:04:20 -0800542}
543
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800544inline size_t
545sizeOfNonNegativeInteger(uint64_t varNumber)
546{
547 if (varNumber < 253) {
548 return 1;
549 }
550 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
551 return 2;
552 }
553 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
554 return 4;
555 }
556 else {
557 return 8;
558 }
559}
560
561
562inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700563writeNonNegativeInteger(std::ostream& os, uint64_t varNumber)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800564{
565 if (varNumber < 253) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200566 os.put(static_cast<char>(varNumber));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800567 return 1;
568 }
569 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200570 uint16_t value = htobe16(static_cast<uint16_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700571 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800572 return 2;
573 }
574 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200575 uint32_t value = htobe32(static_cast<uint32_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700576 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800577 return 4;
578 }
579 else {
580 uint64_t value = htobe64(varNumber);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700581 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800582 return 8;
583 }
584}
585
586
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600587} // namespace tlv
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800588} // namespace ndn
589
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700590#endif // NDN_ENCODING_TLV_HPP