blob: b15ec1485af78e08b7551e4d6c82c865b1b0595a [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,
68 MinSuffixComponents = 13,
69 MaxSuffixComponents = 14,
70 PublisherPublicKeyLocator = 15,
71 Exclude = 16,
72 ChildSelector = 17,
73 MustBeFresh = 18,
74 Any = 19,
75 MetaInfo = 20,
76 Content = 21,
77 SignatureInfo = 22,
78 SignatureValue = 23,
79 ContentType = 24,
80 FreshnessPeriod = 25,
81 FinalBlockId = 26,
82 SignatureType = 27,
83 KeyLocator = 28,
Junxiao Shibc5030d2014-09-01 11:53:12 -070084 KeyDigest = 29,
Spyridon Mastorakis3b54e852015-04-07 08:03:25 -070085 LinkPreference = 30,
86 LinkDelegation = 31,
87 SelectedDelegation = 32,
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080088
89 AppPrivateBlock1 = 128,
90 AppPrivateBlock2 = 32767
91};
92
Yingdi Yuebfa4cb2014-06-17 15:28:53 -070093enum SignatureTypeValue {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080094 DigestSha256 = 0,
Yingdi Yuebfa4cb2014-06-17 15:28:53 -070095 SignatureSha256WithRsa = 1,
Alexander Afanasyev117f5ef2015-06-03 15:07:24 -070096 // <Unassigned> = 2,
Yingdi Yuebfa4cb2014-06-17 15:28:53 -070097 SignatureSha256WithEcdsa = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080098};
99
Alexander Afanasyev5f1820e2017-01-04 18:12:42 -0800100std::ostream&
101operator<<(std::ostream& os, const SignatureTypeValue& signatureType);
102
Yingdi Yu7a813892015-06-09 14:19:54 -0700103/** @brief TLV codes for SignatureInfo features
104 * @sa docs/tutorials/certificate-format.rst
105 */
106enum {
107 // SignatureInfo TLVs
108 ValidityPeriod = 253,
109 NotBefore = 254,
Yingdi Yuea382942015-07-17 23:20:44 -0700110 NotAfter = 255,
111
112 AdditionalDescription = 258,
113 DescriptionEntry = 512,
114 DescriptionKey = 513,
115 DescriptionValue = 514
Yingdi Yu7a813892015-06-09 14:19:54 -0700116};
117
Junxiao Shia464b922014-11-12 21:13:06 -0700118/** @brief indicates a possible value of ContentType field
119 */
Yingdi Yuebfa4cb2014-06-17 15:28:53 -0700120enum ContentTypeValue {
Junxiao Shia464b922014-11-12 21:13:06 -0700121 /** @brief indicates content is the actual data bits
122 */
123 ContentType_Blob = 0,
124
125 /** @brief indicates content is another name which identifies actual data content
126 */
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800127 ContentType_Link = 1,
Junxiao Shia464b922014-11-12 21:13:06 -0700128
129 /** @brief indicates content is a public key
130 */
131 ContentType_Key = 2,
132
133 /** @brief indicates a producer generated NACK
134 * @warning Experimental. Not defined in NDN-TLV spec.
135 */
136 ContentType_Nack = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800137};
138
139/**
140 * @brief Read VAR-NUMBER in NDN-TLV encoding
141 *
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700142 * @param [in] begin Begin (pointer or iterator) of the buffer
143 * @param [in] end End (pointer or iterator) of the buffer
144 * @param [out] number Read number
145 *
146 * @throws This call never throws exception
147 *
148 * @return true if number successfully read from input, false otherwise
149 */
150template<class InputIterator>
151inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700152readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700153
154/**
155 * @brief Read TLV Type
156 *
157 * @param [in] begin Begin (pointer or iterator) of the buffer
158 * @param [in] end End (pointer or iterator) of the buffer
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700159 * @param [out] type Read type number
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700160 *
161 * @throws This call never throws exception
162 *
163 * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
164 * is larger than 2^32-1 (type in this library is implemented as uint32_t)
165 */
166template<class InputIterator>
167inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700168readType(InputIterator& begin, const InputIterator& end, uint32_t& type);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700169
170
171/**
172 * @brief Read VAR-NUMBER in NDN-TLV encoding
173 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600174 * @throws This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800175 *
176 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
177 */
178template<class InputIterator>
179inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700180readVarNumber(InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800181
182/**
183 * @brief Read TLV Type
184 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600185 * @throws This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700186 *
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800187 * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
188 * is larger than 2^32-1 (type in this library is implemented as uint32_t)
189 */
190template<class InputIterator>
191inline uint32_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700192readType(InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800193
194/**
195 * @brief Get number of bytes necessary to hold value of VAR-NUMBER
196 */
197inline size_t
198sizeOfVarNumber(uint64_t varNumber);
199
200/**
201 * @brief Write VAR-NUMBER to the specified stream
202 */
203inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700204writeVarNumber(std::ostream& os, uint64_t varNumber);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800205
206/**
207 * @brief Read nonNegativeInteger in NDN-TLV encoding
208 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600209 * This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800210 *
211 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
212 *
213 * How many bytes will be read is directly controlled by the size parameter, which can be either
214 * 1, 2, 4, or 8. If the value of size is different, then an exception will be thrown.
215 */
216template<class InputIterator>
217inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700218readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800219
220/**
221 * @brief Get number of bytes necessary to hold value of nonNegativeInteger
222 */
223inline size_t
224sizeOfNonNegativeInteger(uint64_t varNumber);
225
226/**
227 * @brief Write nonNegativeInteger to the specified stream
228 */
229inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700230writeNonNegativeInteger(std::ostream& os, uint64_t varNumber);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800231
232/////////////////////////////////////////////////////////////////////////////////
233/////////////////////////////////////////////////////////////////////////////////
234/////////////////////////////////////////////////////////////////////////////////
235
236// Inline implementations
237
238/////////////////////////////////////////////////////////////////////////////////
239/////////////////////////////////////////////////////////////////////////////////
240/////////////////////////////////////////////////////////////////////////////////
241
242template<class InputIterator>
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700243inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700244readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700245{
246 if (begin == end)
247 return false;
248
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700249 uint8_t firstOctet = *begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700250 ++begin;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700251 if (firstOctet < 253)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700252 {
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700253 number = firstOctet;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700254 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700255 else if (firstOctet == 253)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700256 {
257 if (end - begin < 2)
258 return false;
259
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700260 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700261 begin += 2;
262 number = be16toh(value);
263 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700264 else if (firstOctet == 254)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700265 {
266 if (end - begin < 4)
267 return false;
268
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700269 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700270 begin += 4;
271 number = be32toh(value);
272 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700273 else // if (firstOctet == 255)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700274 {
275 if (end - begin < 8)
276 return false;
277
278 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
279 begin += 8;
280
281 number = be64toh(value);
282 }
283
284 return true;
285}
286
287template<class InputIterator>
288inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700289readType(InputIterator& begin, const InputIterator& end, uint32_t& type)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700290{
Mickey Sweatt632e0572014-04-20 00:36:32 -0700291 uint64_t number = 0;
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700292 bool isOk = readVarNumber(begin, end, number);
293 if (!isOk || number > std::numeric_limits<uint32_t>::max())
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700294 {
295 return false;
296 }
297
Davide Pesavento8f5cbdc2015-09-13 00:59:28 +0200298 type = static_cast<uint32_t>(number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700299 return true;
300}
301
302template<class InputIterator>
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800303inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700304readVarNumber(InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800305{
306 if (begin == end)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700307 BOOST_THROW_EXCEPTION(Error("Empty buffer during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700308
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700309 uint64_t value;
310 bool isOk = readVarNumber(begin, end, value);
311 if (!isOk)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700312 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700313
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700314 return value;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800315}
316
Yingdi Yu27158392014-01-20 13:04:20 -0800317template<>
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700318inline bool
Junxiao Shi468abc32014-11-04 09:12:47 -0700319readVarNumber<std::istream_iterator<uint8_t>>(std::istream_iterator<uint8_t>& begin,
320 const std::istream_iterator<uint8_t>& end,
321 uint64_t& value)
Yingdi Yu27158392014-01-20 13:04:20 -0800322{
323 if (begin == end)
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700324 return false;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700325
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700326 uint8_t firstOctet = *begin;
Yingdi Yu27158392014-01-20 13:04:20 -0800327 ++begin;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700328 if (firstOctet < 253)
Yingdi Yu27158392014-01-20 13:04:20 -0800329 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700330 value = firstOctet;
Yingdi Yu27158392014-01-20 13:04:20 -0800331 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700332 else if (firstOctet == 253)
Yingdi Yu27158392014-01-20 13:04:20 -0800333 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700334 value = 0;
335 size_t count = 0;
336 for (; begin != end && count < 2; ++count)
337 {
338 value = ((value << 8) | *begin);
339 begin++;
340 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700341
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700342 if (count != 2)
343 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800344 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700345 else if (firstOctet == 254)
Yingdi Yu27158392014-01-20 13:04:20 -0800346 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700347 value = 0;
348 size_t count = 0;
349 for (; begin != end && count < 4; ++count)
350 {
351 value = ((value << 8) | *begin);
352 begin++;
353 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700354
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700355 if (count != 4)
356 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800357 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700358 else // if (firstOctet == 255)
Yingdi Yu27158392014-01-20 13:04:20 -0800359 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700360 value = 0;
361 size_t count = 0;
362 for (; begin != end && count < 8; ++count)
363 {
364 value = ((value << 8) | *begin);
365 begin++;
366 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700367
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700368 if (count != 8)
369 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800370 }
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700371
372 return true;
Yingdi Yu27158392014-01-20 13:04:20 -0800373}
374
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800375template<class InputIterator>
376inline uint32_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700377readType(InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800378{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700379 uint64_t type = readVarNumber(begin, end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800380 if (type > std::numeric_limits<uint32_t>::max())
381 {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700382 BOOST_THROW_EXCEPTION(Error("TLV type code exceeds allowed maximum"));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800383 }
384
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700385 return static_cast<uint32_t>(type);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800386}
387
388size_t
389sizeOfVarNumber(uint64_t varNumber)
390{
391 if (varNumber < 253) {
392 return 1;
393 }
394 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
395 return 3;
396 }
397 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
398 return 5;
399 }
400 else {
401 return 9;
402 }
403}
404
405inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700406writeVarNumber(std::ostream& os, uint64_t varNumber)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800407{
408 if (varNumber < 253) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200409 os.put(static_cast<char>(varNumber));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800410 return 1;
411 }
412 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200413 os.put(static_cast<char>(253));
414 uint16_t value = htobe16(static_cast<uint16_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700415 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800416 return 3;
417 }
418 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200419 os.put(static_cast<char>(254));
420 uint32_t value = htobe32(static_cast<uint32_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700421 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800422 return 5;
423 }
424 else {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200425 os.put(static_cast<char>(255));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800426 uint64_t value = htobe64(varNumber);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700427 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800428 return 9;
429 }
430}
431
432template<class InputIterator>
433inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700434readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800435{
436 switch (size) {
437 case 1:
438 {
439 if (end - begin < 1)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700440 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700441
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800442 uint8_t value = *begin;
443 begin++;
444 return value;
445 }
446 case 2:
447 {
448 if (end - begin < 2)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700449 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700450
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700451 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800452 begin += 2;
453 return be16toh(value);
454 }
455 case 4:
456 {
457 if (end - begin < 4)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700458 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700459
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700460 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800461 begin += 4;
462 return be32toh(value);
463 }
464 case 8:
465 {
466 if (end - begin < 8)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700467 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700468
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800469 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
470 begin += 8;
471 return be64toh(value);
472 }
473 }
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700474 BOOST_THROW_EXCEPTION(Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)"));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800475}
476
Yingdi Yu27158392014-01-20 13:04:20 -0800477template<>
478inline uint64_t
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700479readNonNegativeInteger<std::istream_iterator<uint8_t> >(size_t size,
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700480 std::istream_iterator<uint8_t>& begin,
481 const std::istream_iterator<uint8_t>& end)
Yingdi Yu27158392014-01-20 13:04:20 -0800482{
483 switch (size) {
484 case 1:
485 {
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700486 if (begin == end)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700487 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700488
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700489 uint64_t value = *begin;
Yingdi Yu27158392014-01-20 13:04:20 -0800490 begin++;
491 return value;
492 }
493 case 2:
494 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700495 uint64_t value = 0;
496 size_t count = 0;
497 for (; begin != end && count < 2; ++count)
498 {
499 value = ((value << 8) | *begin);
500 begin++;
501 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700502
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700503 if (count != 2)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700504 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700505
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700506 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800507 }
508 case 4:
509 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700510 uint64_t value = 0;
511 size_t count = 0;
512 for (; begin != end && count < 4; ++count)
513 {
514 value = ((value << 8) | *begin);
515 begin++;
516 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700517
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700518 if (count != 4)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700519 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700520
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700521 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800522 }
523 case 8:
524 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700525 uint64_t value = 0;
526 size_t count = 0;
527 for (; begin != end && count < 8; ++count)
528 {
529 value = ((value << 8) | *begin);
530 begin++;
531 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700532
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700533 if (count != 8)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700534 BOOST_THROW_EXCEPTION(Error("Insufficient data during TLV processing"));
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700535
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700536 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800537 }
538 }
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700539 BOOST_THROW_EXCEPTION(Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)"));
Yingdi Yu27158392014-01-20 13:04:20 -0800540}
541
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800542inline size_t
543sizeOfNonNegativeInteger(uint64_t varNumber)
544{
545 if (varNumber < 253) {
546 return 1;
547 }
548 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
549 return 2;
550 }
551 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
552 return 4;
553 }
554 else {
555 return 8;
556 }
557}
558
559
560inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700561writeNonNegativeInteger(std::ostream& os, uint64_t varNumber)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800562{
563 if (varNumber < 253) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200564 os.put(static_cast<char>(varNumber));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800565 return 1;
566 }
567 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200568 uint16_t value = htobe16(static_cast<uint16_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700569 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800570 return 2;
571 }
572 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200573 uint32_t value = htobe32(static_cast<uint32_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700574 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800575 return 4;
576 }
577 else {
578 uint64_t value = htobe64(varNumber);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700579 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800580 return 8;
581 }
582}
583
584
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600585} // namespace tlv
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800586} // namespace ndn
587
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700588#endif // NDN_ENCODING_TLV_HPP