blob: 7d7461f2127d9d30716e81a8b3ea92ff7ed42912 [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 Afanasyevc169a812014-05-20 20:37:29 -04003 * Copyright (c) 2013-2014 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
Yingdi Yu7a813892015-06-09 14:19:54 -0700102/** @brief TLV codes for SignatureInfo features
103 * @sa docs/tutorials/certificate-format.rst
104 */
105enum {
106 // SignatureInfo TLVs
107 ValidityPeriod = 253,
108 NotBefore = 254,
Yingdi Yuea382942015-07-17 23:20:44 -0700109 NotAfter = 255,
110
111 AdditionalDescription = 258,
112 DescriptionEntry = 512,
113 DescriptionKey = 513,
114 DescriptionValue = 514
Yingdi Yu7a813892015-06-09 14:19:54 -0700115};
116
Junxiao Shia464b922014-11-12 21:13:06 -0700117/** @brief indicates a possible value of ContentType field
118 */
Yingdi Yuebfa4cb2014-06-17 15:28:53 -0700119enum ContentTypeValue {
Junxiao Shia464b922014-11-12 21:13:06 -0700120 /** @brief indicates content is the actual data bits
121 */
122 ContentType_Blob = 0,
123
124 /** @brief indicates content is another name which identifies actual data content
125 */
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800126 ContentType_Link = 1,
Junxiao Shia464b922014-11-12 21:13:06 -0700127
128 /** @brief indicates content is a public key
129 */
130 ContentType_Key = 2,
131
132 /** @brief indicates a producer generated NACK
133 * @warning Experimental. Not defined in NDN-TLV spec.
134 */
135 ContentType_Nack = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800136};
137
138/**
139 * @brief Read VAR-NUMBER in NDN-TLV encoding
140 *
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700141 * @param [in] begin Begin (pointer or iterator) of the buffer
142 * @param [in] end End (pointer or iterator) of the buffer
143 * @param [out] number Read number
144 *
145 * @throws This call never throws exception
146 *
147 * @return true if number successfully read from input, false otherwise
148 */
149template<class InputIterator>
150inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700151readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700152
153/**
154 * @brief Read TLV Type
155 *
156 * @param [in] begin Begin (pointer or iterator) of the buffer
157 * @param [in] end End (pointer or iterator) of the buffer
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700158 * @param [out] type Read type number
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700159 *
160 * @throws This call never throws exception
161 *
162 * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
163 * is larger than 2^32-1 (type in this library is implemented as uint32_t)
164 */
165template<class InputIterator>
166inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700167readType(InputIterator& begin, const InputIterator& end, uint32_t& type);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700168
169
170/**
171 * @brief Read VAR-NUMBER in NDN-TLV encoding
172 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600173 * @throws This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800174 *
175 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
176 */
177template<class InputIterator>
178inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700179readVarNumber(InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800180
181/**
182 * @brief Read TLV Type
183 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600184 * @throws This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700185 *
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800186 * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
187 * is larger than 2^32-1 (type in this library is implemented as uint32_t)
188 */
189template<class InputIterator>
190inline uint32_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700191readType(InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800192
193/**
194 * @brief Get number of bytes necessary to hold value of VAR-NUMBER
195 */
196inline size_t
197sizeOfVarNumber(uint64_t varNumber);
198
199/**
200 * @brief Write VAR-NUMBER to the specified stream
201 */
202inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700203writeVarNumber(std::ostream& os, uint64_t varNumber);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800204
205/**
206 * @brief Read nonNegativeInteger in NDN-TLV encoding
207 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600208 * This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800209 *
210 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
211 *
212 * How many bytes will be read is directly controlled by the size parameter, which can be either
213 * 1, 2, 4, or 8. If the value of size is different, then an exception will be thrown.
214 */
215template<class InputIterator>
216inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700217readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800218
219/**
220 * @brief Get number of bytes necessary to hold value of nonNegativeInteger
221 */
222inline size_t
223sizeOfNonNegativeInteger(uint64_t varNumber);
224
225/**
226 * @brief Write nonNegativeInteger to the specified stream
227 */
228inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700229writeNonNegativeInteger(std::ostream& os, uint64_t varNumber);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800230
231/////////////////////////////////////////////////////////////////////////////////
232/////////////////////////////////////////////////////////////////////////////////
233/////////////////////////////////////////////////////////////////////////////////
234
235// Inline implementations
236
237/////////////////////////////////////////////////////////////////////////////////
238/////////////////////////////////////////////////////////////////////////////////
239/////////////////////////////////////////////////////////////////////////////////
240
241template<class InputIterator>
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700242inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700243readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700244{
245 if (begin == end)
246 return false;
247
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700248 uint8_t firstOctet = *begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700249 ++begin;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700250 if (firstOctet < 253)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700251 {
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700252 number = firstOctet;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700253 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700254 else if (firstOctet == 253)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700255 {
256 if (end - begin < 2)
257 return false;
258
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700259 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700260 begin += 2;
261 number = be16toh(value);
262 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700263 else if (firstOctet == 254)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700264 {
265 if (end - begin < 4)
266 return false;
267
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700268 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700269 begin += 4;
270 number = be32toh(value);
271 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700272 else // if (firstOctet == 255)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700273 {
274 if (end - begin < 8)
275 return false;
276
277 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
278 begin += 8;
279
280 number = be64toh(value);
281 }
282
283 return true;
284}
285
286template<class InputIterator>
287inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700288readType(InputIterator& begin, const InputIterator& end, uint32_t& type)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700289{
Mickey Sweatt632e0572014-04-20 00:36:32 -0700290 uint64_t number = 0;
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700291 bool isOk = readVarNumber(begin, end, number);
292 if (!isOk || number > std::numeric_limits<uint32_t>::max())
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700293 {
294 return false;
295 }
296
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700297 type = static_cast<uint64_t>(number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700298 return true;
299}
300
301template<class InputIterator>
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800302inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700303readVarNumber(InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800304{
305 if (begin == end)
306 throw Error("Empty buffer during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700307
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700308 uint64_t value;
309 bool isOk = readVarNumber(begin, end, value);
310 if (!isOk)
311 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700312
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700313 return value;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800314}
315
Yingdi Yu27158392014-01-20 13:04:20 -0800316template<>
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700317inline bool
Junxiao Shi468abc32014-11-04 09:12:47 -0700318readVarNumber<std::istream_iterator<uint8_t>>(std::istream_iterator<uint8_t>& begin,
319 const std::istream_iterator<uint8_t>& end,
320 uint64_t& value)
Yingdi Yu27158392014-01-20 13:04:20 -0800321{
322 if (begin == end)
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700323 return false;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700324
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700325 uint8_t firstOctet = *begin;
Yingdi Yu27158392014-01-20 13:04:20 -0800326 ++begin;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700327 if (firstOctet < 253)
Yingdi Yu27158392014-01-20 13:04:20 -0800328 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700329 value = firstOctet;
Yingdi Yu27158392014-01-20 13:04:20 -0800330 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700331 else if (firstOctet == 253)
Yingdi Yu27158392014-01-20 13:04:20 -0800332 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700333 value = 0;
334 size_t count = 0;
335 for (; begin != end && count < 2; ++count)
336 {
337 value = ((value << 8) | *begin);
338 begin++;
339 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700340
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700341 if (count != 2)
342 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800343 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700344 else if (firstOctet == 254)
Yingdi Yu27158392014-01-20 13:04:20 -0800345 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700346 value = 0;
347 size_t count = 0;
348 for (; begin != end && count < 4; ++count)
349 {
350 value = ((value << 8) | *begin);
351 begin++;
352 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700353
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700354 if (count != 4)
355 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800356 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700357 else // if (firstOctet == 255)
Yingdi Yu27158392014-01-20 13:04:20 -0800358 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700359 value = 0;
360 size_t count = 0;
361 for (; begin != end && count < 8; ++count)
362 {
363 value = ((value << 8) | *begin);
364 begin++;
365 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700366
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700367 if (count != 8)
368 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800369 }
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700370
371 return true;
Yingdi Yu27158392014-01-20 13:04:20 -0800372}
373
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800374template<class InputIterator>
375inline uint32_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700376readType(InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800377{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700378 uint64_t type = readVarNumber(begin, end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800379 if (type > std::numeric_limits<uint32_t>::max())
380 {
381 throw Error("TLV type code exceeds allowed maximum");
382 }
383
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700384 return static_cast<uint32_t>(type);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800385}
386
387size_t
388sizeOfVarNumber(uint64_t varNumber)
389{
390 if (varNumber < 253) {
391 return 1;
392 }
393 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
394 return 3;
395 }
396 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
397 return 5;
398 }
399 else {
400 return 9;
401 }
402}
403
404inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700405writeVarNumber(std::ostream& os, uint64_t varNumber)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800406{
407 if (varNumber < 253) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200408 os.put(static_cast<char>(varNumber));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800409 return 1;
410 }
411 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200412 os.put(static_cast<char>(253));
413 uint16_t value = htobe16(static_cast<uint16_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700414 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800415 return 3;
416 }
417 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200418 os.put(static_cast<char>(254));
419 uint32_t value = htobe32(static_cast<uint32_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700420 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800421 return 5;
422 }
423 else {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200424 os.put(static_cast<char>(255));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800425 uint64_t value = htobe64(varNumber);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700426 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800427 return 9;
428 }
429}
430
431template<class InputIterator>
432inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700433readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800434{
435 switch (size) {
436 case 1:
437 {
438 if (end - begin < 1)
439 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700440
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800441 uint8_t value = *begin;
442 begin++;
443 return value;
444 }
445 case 2:
446 {
447 if (end - begin < 2)
448 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700449
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700450 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800451 begin += 2;
452 return be16toh(value);
453 }
454 case 4:
455 {
456 if (end - begin < 4)
457 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700458
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700459 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800460 begin += 4;
461 return be32toh(value);
462 }
463 case 8:
464 {
465 if (end - begin < 8)
466 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700467
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800468 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
469 begin += 8;
470 return be64toh(value);
471 }
472 }
473 throw Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)");
474}
475
Yingdi Yu27158392014-01-20 13:04:20 -0800476template<>
477inline uint64_t
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700478readNonNegativeInteger<std::istream_iterator<uint8_t> >(size_t size,
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700479 std::istream_iterator<uint8_t>& begin,
480 const std::istream_iterator<uint8_t>& end)
Yingdi Yu27158392014-01-20 13:04:20 -0800481{
482 switch (size) {
483 case 1:
484 {
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700485 if (begin == end)
Yingdi Yu27158392014-01-20 13:04:20 -0800486 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700487
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700488 uint64_t value = *begin;
Yingdi Yu27158392014-01-20 13:04:20 -0800489 begin++;
490 return value;
491 }
492 case 2:
493 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700494 uint64_t value = 0;
495 size_t count = 0;
496 for (; begin != end && count < 2; ++count)
497 {
498 value = ((value << 8) | *begin);
499 begin++;
500 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700501
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700502 if (count != 2)
Yingdi Yu27158392014-01-20 13:04:20 -0800503 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700504
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700505 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800506 }
507 case 4:
508 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700509 uint64_t value = 0;
510 size_t count = 0;
511 for (; begin != end && count < 4; ++count)
512 {
513 value = ((value << 8) | *begin);
514 begin++;
515 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700516
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700517 if (count != 4)
Yingdi Yu27158392014-01-20 13:04:20 -0800518 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700519
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700520 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800521 }
522 case 8:
523 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700524 uint64_t value = 0;
525 size_t count = 0;
526 for (; begin != end && count < 8; ++count)
527 {
528 value = ((value << 8) | *begin);
529 begin++;
530 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700531
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700532 if (count != 8)
Yingdi Yu27158392014-01-20 13:04:20 -0800533 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700534
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700535 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800536 }
537 }
538 throw Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)");
539}
540
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800541inline size_t
542sizeOfNonNegativeInteger(uint64_t varNumber)
543{
544 if (varNumber < 253) {
545 return 1;
546 }
547 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
548 return 2;
549 }
550 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
551 return 4;
552 }
553 else {
554 return 8;
555 }
556}
557
558
559inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700560writeNonNegativeInteger(std::ostream& os, uint64_t varNumber)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800561{
562 if (varNumber < 253) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200563 os.put(static_cast<char>(varNumber));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800564 return 1;
565 }
566 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200567 uint16_t value = htobe16(static_cast<uint16_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700568 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800569 return 2;
570 }
571 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200572 uint32_t value = htobe32(static_cast<uint32_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700573 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800574 return 4;
575 }
576 else {
577 uint64_t value = htobe64(varNumber);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700578 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800579 return 8;
580 }
581}
582
583
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600584} // namespace tlv
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800585} // namespace ndn
586
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700587#endif // NDN_ENCODING_TLV_HPP