blob: bcb562a017ec1b896a581f2f6ab3332a546c0301 [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 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
135 * @warning Experimental. Not defined in NDN-TLV spec.
136 */
137 ContentType_Nack = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800138};
139
140/**
141 * @brief Read VAR-NUMBER in NDN-TLV encoding
142 *
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700143 * @param [in] begin Begin (pointer or iterator) of the buffer
144 * @param [in] end End (pointer or iterator) of the buffer
145 * @param [out] number Read number
146 *
147 * @throws This call never throws exception
148 *
149 * @return true if number successfully read from input, false otherwise
150 */
151template<class InputIterator>
152inline bool
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/**
156 * @brief Read TLV Type
157 *
158 * @param [in] begin Begin (pointer or iterator) of the buffer
159 * @param [in] end End (pointer or iterator) of the buffer
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700160 * @param [out] type Read type number
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700161 *
162 * @throws This call never throws exception
163 *
164 * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
165 * is larger than 2^32-1 (type in this library is implemented as uint32_t)
166 */
167template<class InputIterator>
168inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700169readType(InputIterator& begin, const InputIterator& end, uint32_t& type);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700170
171
172/**
173 * @brief Read VAR-NUMBER in NDN-TLV encoding
174 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600175 * @throws This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800176 *
177 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
178 */
179template<class InputIterator>
180inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700181readVarNumber(InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800182
183/**
184 * @brief Read TLV Type
185 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600186 * @throws This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700187 *
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800188 * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
189 * is larger than 2^32-1 (type in this library is implemented as uint32_t)
190 */
191template<class InputIterator>
192inline uint32_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700193readType(InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800194
195/**
196 * @brief Get number of bytes necessary to hold value of VAR-NUMBER
197 */
198inline size_t
199sizeOfVarNumber(uint64_t varNumber);
200
201/**
202 * @brief Write VAR-NUMBER to the specified stream
203 */
204inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700205writeVarNumber(std::ostream& os, uint64_t varNumber);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800206
207/**
208 * @brief Read nonNegativeInteger in NDN-TLV encoding
209 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600210 * This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800211 *
212 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
213 *
214 * How many bytes will be read is directly controlled by the size parameter, which can be either
215 * 1, 2, 4, or 8. If the value of size is different, then an exception will be thrown.
216 */
217template<class InputIterator>
218inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700219readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800220
221/**
222 * @brief Get number of bytes necessary to hold value of nonNegativeInteger
223 */
224inline size_t
225sizeOfNonNegativeInteger(uint64_t varNumber);
226
227/**
228 * @brief Write nonNegativeInteger to the specified stream
229 */
230inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700231writeNonNegativeInteger(std::ostream& os, uint64_t varNumber);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800232
233/////////////////////////////////////////////////////////////////////////////////
234/////////////////////////////////////////////////////////////////////////////////
235/////////////////////////////////////////////////////////////////////////////////
236
237// Inline implementations
238
239/////////////////////////////////////////////////////////////////////////////////
240/////////////////////////////////////////////////////////////////////////////////
241/////////////////////////////////////////////////////////////////////////////////
242
243template<class InputIterator>
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700244inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700245readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700246{
247 if (begin == end)
248 return false;
249
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700250 uint8_t firstOctet = *begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700251 ++begin;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700252 if (firstOctet < 253)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700253 {
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700254 number = firstOctet;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700255 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700256 else if (firstOctet == 253)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700257 {
258 if (end - begin < 2)
259 return false;
260
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700261 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700262 begin += 2;
263 number = be16toh(value);
264 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700265 else if (firstOctet == 254)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700266 {
267 if (end - begin < 4)
268 return false;
269
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700270 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700271 begin += 4;
272 number = be32toh(value);
273 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700274 else // if (firstOctet == 255)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700275 {
276 if (end - begin < 8)
277 return false;
278
279 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
280 begin += 8;
281
282 number = be64toh(value);
283 }
284
285 return true;
286}
287
288template<class InputIterator>
289inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700290readType(InputIterator& begin, const InputIterator& end, uint32_t& type)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700291{
Mickey Sweatt632e0572014-04-20 00:36:32 -0700292 uint64_t number = 0;
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700293 bool isOk = readVarNumber(begin, end, number);
294 if (!isOk || number > std::numeric_limits<uint32_t>::max())
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700295 {
296 return false;
297 }
298
Davide Pesavento8f5cbdc2015-09-13 00:59:28 +0200299 type = static_cast<uint32_t>(number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700300 return true;
301}
302
303template<class InputIterator>
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800304inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700305readVarNumber(InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800306{
307 if (begin == end)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700308 BOOST_THROW_EXCEPTION(Error("Empty buffer during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700309
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700310 uint64_t value;
311 bool isOk = readVarNumber(begin, end, value);
312 if (!isOk)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700313 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700314
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700315 return value;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800316}
317
Yingdi Yu27158392014-01-20 13:04:20 -0800318template<>
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700319inline bool
Junxiao Shi468abc32014-11-04 09:12:47 -0700320readVarNumber<std::istream_iterator<uint8_t>>(std::istream_iterator<uint8_t>& begin,
321 const std::istream_iterator<uint8_t>& end,
322 uint64_t& value)
Yingdi Yu27158392014-01-20 13:04:20 -0800323{
324 if (begin == end)
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700325 return false;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700326
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700327 uint8_t firstOctet = *begin;
Yingdi Yu27158392014-01-20 13:04:20 -0800328 ++begin;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700329 if (firstOctet < 253)
Yingdi Yu27158392014-01-20 13:04:20 -0800330 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700331 value = firstOctet;
Yingdi Yu27158392014-01-20 13:04:20 -0800332 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700333 else if (firstOctet == 253)
Yingdi Yu27158392014-01-20 13:04:20 -0800334 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700335 value = 0;
336 size_t count = 0;
337 for (; begin != end && count < 2; ++count)
338 {
339 value = ((value << 8) | *begin);
340 begin++;
341 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700342
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700343 if (count != 2)
344 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800345 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700346 else if (firstOctet == 254)
Yingdi Yu27158392014-01-20 13:04:20 -0800347 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700348 value = 0;
349 size_t count = 0;
350 for (; begin != end && count < 4; ++count)
351 {
352 value = ((value << 8) | *begin);
353 begin++;
354 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700355
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700356 if (count != 4)
357 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800358 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700359 else // if (firstOctet == 255)
Yingdi Yu27158392014-01-20 13:04:20 -0800360 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700361 value = 0;
362 size_t count = 0;
363 for (; begin != end && count < 8; ++count)
364 {
365 value = ((value << 8) | *begin);
366 begin++;
367 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700368
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700369 if (count != 8)
370 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800371 }
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700372
373 return true;
Yingdi Yu27158392014-01-20 13:04:20 -0800374}
375
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800376template<class InputIterator>
377inline uint32_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700378readType(InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800379{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700380 uint64_t type = readVarNumber(begin, end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800381 if (type > std::numeric_limits<uint32_t>::max())
382 {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700383 BOOST_THROW_EXCEPTION(Error("TLV type code exceeds allowed maximum"));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800384 }
385
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700386 return static_cast<uint32_t>(type);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800387}
388
389size_t
390sizeOfVarNumber(uint64_t varNumber)
391{
392 if (varNumber < 253) {
393 return 1;
394 }
395 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
396 return 3;
397 }
398 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
399 return 5;
400 }
401 else {
402 return 9;
403 }
404}
405
406inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700407writeVarNumber(std::ostream& os, uint64_t varNumber)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800408{
409 if (varNumber < 253) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200410 os.put(static_cast<char>(varNumber));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800411 return 1;
412 }
413 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200414 os.put(static_cast<char>(253));
415 uint16_t value = htobe16(static_cast<uint16_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700416 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800417 return 3;
418 }
419 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200420 os.put(static_cast<char>(254));
421 uint32_t value = htobe32(static_cast<uint32_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700422 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800423 return 5;
424 }
425 else {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200426 os.put(static_cast<char>(255));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800427 uint64_t value = htobe64(varNumber);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700428 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800429 return 9;
430 }
431}
432
433template<class InputIterator>
434inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700435readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800436{
437 switch (size) {
438 case 1:
439 {
440 if (end - begin < 1)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700441 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700442
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800443 uint8_t value = *begin;
444 begin++;
445 return value;
446 }
447 case 2:
448 {
449 if (end - begin < 2)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700450 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700451
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700452 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800453 begin += 2;
454 return be16toh(value);
455 }
456 case 4:
457 {
458 if (end - begin < 4)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700459 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700460
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700461 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800462 begin += 4;
463 return be32toh(value);
464 }
465 case 8:
466 {
467 if (end - begin < 8)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700468 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700469
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800470 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
471 begin += 8;
472 return be64toh(value);
473 }
474 }
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700475 BOOST_THROW_EXCEPTION(Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)"));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800476}
477
Yingdi Yu27158392014-01-20 13:04:20 -0800478template<>
479inline uint64_t
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700480readNonNegativeInteger<std::istream_iterator<uint8_t> >(size_t size,
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700481 std::istream_iterator<uint8_t>& begin,
482 const std::istream_iterator<uint8_t>& end)
Yingdi Yu27158392014-01-20 13:04:20 -0800483{
484 switch (size) {
485 case 1:
486 {
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700487 if (begin == end)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700488 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700489
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700490 uint64_t value = *begin;
Yingdi Yu27158392014-01-20 13:04:20 -0800491 begin++;
492 return value;
493 }
494 case 2:
495 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700496 uint64_t value = 0;
497 size_t count = 0;
498 for (; begin != end && count < 2; ++count)
499 {
500 value = ((value << 8) | *begin);
501 begin++;
502 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700503
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700504 if (count != 2)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700505 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700506
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700507 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800508 }
509 case 4:
510 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700511 uint64_t value = 0;
512 size_t count = 0;
513 for (; begin != end && count < 4; ++count)
514 {
515 value = ((value << 8) | *begin);
516 begin++;
517 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700518
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700519 if (count != 4)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700520 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700521
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700522 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800523 }
524 case 8:
525 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700526 uint64_t value = 0;
527 size_t count = 0;
528 for (; begin != end && count < 8; ++count)
529 {
530 value = ((value << 8) | *begin);
531 begin++;
532 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700533
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700534 if (count != 8)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700535 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700536
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700537 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800538 }
539 }
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700540 BOOST_THROW_EXCEPTION(Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)"));
Yingdi Yu27158392014-01-20 13:04:20 -0800541}
542
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800543inline size_t
544sizeOfNonNegativeInteger(uint64_t varNumber)
545{
546 if (varNumber < 253) {
547 return 1;
548 }
549 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
550 return 2;
551 }
552 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
553 return 4;
554 }
555 else {
556 return 8;
557 }
558}
559
560
561inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700562writeNonNegativeInteger(std::ostream& os, uint64_t varNumber)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800563{
564 if (varNumber < 253) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200565 os.put(static_cast<char>(varNumber));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800566 return 1;
567 }
568 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200569 uint16_t value = htobe16(static_cast<uint16_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700570 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800571 return 2;
572 }
573 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200574 uint32_t value = htobe32(static_cast<uint32_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700575 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800576 return 4;
577 }
578 else {
579 uint64_t value = htobe64(varNumber);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700580 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800581 return 8;
582 }
583}
584
585
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600586} // namespace tlv
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800587} // namespace ndn
588
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700589#endif // NDN_ENCODING_TLV_HPP