blob: 78564d84ed8c6867ed6a55a04052713d717a9ec1 [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
Junxiao Shia464b922014-11-12 21:13:06 -0700102/** @brief indicates a possible value of ContentType field
103 */
Yingdi Yuebfa4cb2014-06-17 15:28:53 -0700104enum ContentTypeValue {
Junxiao Shia464b922014-11-12 21:13:06 -0700105 /** @brief indicates content is the actual data bits
106 */
107 ContentType_Blob = 0,
108
109 /** @brief indicates content is another name which identifies actual data content
110 */
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800111 ContentType_Link = 1,
Junxiao Shia464b922014-11-12 21:13:06 -0700112
113 /** @brief indicates content is a public key
114 */
115 ContentType_Key = 2,
116
117 /** @brief indicates a producer generated NACK
118 * @warning Experimental. Not defined in NDN-TLV spec.
119 */
120 ContentType_Nack = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800121};
122
123/**
124 * @brief Read VAR-NUMBER in NDN-TLV encoding
125 *
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700126 * @param [in] begin Begin (pointer or iterator) of the buffer
127 * @param [in] end End (pointer or iterator) of the buffer
128 * @param [out] number Read number
129 *
130 * @throws This call never throws exception
131 *
132 * @return true if number successfully read from input, false otherwise
133 */
134template<class InputIterator>
135inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700136readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700137
138/**
139 * @brief Read TLV Type
140 *
141 * @param [in] begin Begin (pointer or iterator) of the buffer
142 * @param [in] end End (pointer or iterator) of the buffer
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700143 * @param [out] type Read type number
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700144 *
145 * @throws This call never throws exception
146 *
147 * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
148 * is larger than 2^32-1 (type in this library is implemented as uint32_t)
149 */
150template<class InputIterator>
151inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700152readType(InputIterator& begin, const InputIterator& end, uint32_t& type);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700153
154
155/**
156 * @brief Read VAR-NUMBER in NDN-TLV encoding
157 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600158 * @throws This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800159 *
160 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
161 */
162template<class InputIterator>
163inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700164readVarNumber(InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800165
166/**
167 * @brief Read TLV Type
168 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600169 * @throws This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700170 *
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800171 * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
172 * is larger than 2^32-1 (type in this library is implemented as uint32_t)
173 */
174template<class InputIterator>
175inline uint32_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700176readType(InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800177
178/**
179 * @brief Get number of bytes necessary to hold value of VAR-NUMBER
180 */
181inline size_t
182sizeOfVarNumber(uint64_t varNumber);
183
184/**
185 * @brief Write VAR-NUMBER to the specified stream
186 */
187inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700188writeVarNumber(std::ostream& os, uint64_t varNumber);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800189
190/**
191 * @brief Read nonNegativeInteger in NDN-TLV encoding
192 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600193 * This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800194 *
195 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
196 *
197 * How many bytes will be read is directly controlled by the size parameter, which can be either
198 * 1, 2, 4, or 8. If the value of size is different, then an exception will be thrown.
199 */
200template<class InputIterator>
201inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700202readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800203
204/**
205 * @brief Get number of bytes necessary to hold value of nonNegativeInteger
206 */
207inline size_t
208sizeOfNonNegativeInteger(uint64_t varNumber);
209
210/**
211 * @brief Write nonNegativeInteger to the specified stream
212 */
213inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700214writeNonNegativeInteger(std::ostream& os, uint64_t varNumber);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800215
216/////////////////////////////////////////////////////////////////////////////////
217/////////////////////////////////////////////////////////////////////////////////
218/////////////////////////////////////////////////////////////////////////////////
219
220// Inline implementations
221
222/////////////////////////////////////////////////////////////////////////////////
223/////////////////////////////////////////////////////////////////////////////////
224/////////////////////////////////////////////////////////////////////////////////
225
226template<class InputIterator>
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700227inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700228readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700229{
230 if (begin == end)
231 return false;
232
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700233 uint8_t firstOctet = *begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700234 ++begin;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700235 if (firstOctet < 253)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700236 {
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700237 number = firstOctet;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700238 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700239 else if (firstOctet == 253)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700240 {
241 if (end - begin < 2)
242 return false;
243
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700244 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700245 begin += 2;
246 number = be16toh(value);
247 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700248 else if (firstOctet == 254)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700249 {
250 if (end - begin < 4)
251 return false;
252
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700253 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700254 begin += 4;
255 number = be32toh(value);
256 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700257 else // if (firstOctet == 255)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700258 {
259 if (end - begin < 8)
260 return false;
261
262 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
263 begin += 8;
264
265 number = be64toh(value);
266 }
267
268 return true;
269}
270
271template<class InputIterator>
272inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700273readType(InputIterator& begin, const InputIterator& end, uint32_t& type)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700274{
Mickey Sweatt632e0572014-04-20 00:36:32 -0700275 uint64_t number = 0;
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700276 bool isOk = readVarNumber(begin, end, number);
277 if (!isOk || number > std::numeric_limits<uint32_t>::max())
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700278 {
279 return false;
280 }
281
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700282 type = static_cast<uint64_t>(number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700283 return true;
284}
285
286template<class InputIterator>
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800287inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700288readVarNumber(InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800289{
290 if (begin == end)
291 throw Error("Empty buffer during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700292
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700293 uint64_t value;
294 bool isOk = readVarNumber(begin, end, value);
295 if (!isOk)
296 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700297
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700298 return value;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800299}
300
Yingdi Yu27158392014-01-20 13:04:20 -0800301template<>
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700302inline bool
Junxiao Shi468abc32014-11-04 09:12:47 -0700303readVarNumber<std::istream_iterator<uint8_t>>(std::istream_iterator<uint8_t>& begin,
304 const std::istream_iterator<uint8_t>& end,
305 uint64_t& value)
Yingdi Yu27158392014-01-20 13:04:20 -0800306{
307 if (begin == end)
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700308 return false;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700309
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700310 uint8_t firstOctet = *begin;
Yingdi Yu27158392014-01-20 13:04:20 -0800311 ++begin;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700312 if (firstOctet < 253)
Yingdi Yu27158392014-01-20 13:04:20 -0800313 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700314 value = firstOctet;
Yingdi Yu27158392014-01-20 13:04:20 -0800315 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700316 else if (firstOctet == 253)
Yingdi Yu27158392014-01-20 13:04:20 -0800317 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700318 value = 0;
319 size_t count = 0;
320 for (; begin != end && count < 2; ++count)
321 {
322 value = ((value << 8) | *begin);
323 begin++;
324 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700325
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700326 if (count != 2)
327 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800328 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700329 else if (firstOctet == 254)
Yingdi Yu27158392014-01-20 13:04:20 -0800330 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700331 value = 0;
332 size_t count = 0;
333 for (; begin != end && count < 4; ++count)
334 {
335 value = ((value << 8) | *begin);
336 begin++;
337 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700338
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700339 if (count != 4)
340 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800341 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700342 else // if (firstOctet == 255)
Yingdi Yu27158392014-01-20 13:04:20 -0800343 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700344 value = 0;
345 size_t count = 0;
346 for (; begin != end && count < 8; ++count)
347 {
348 value = ((value << 8) | *begin);
349 begin++;
350 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700351
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700352 if (count != 8)
353 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800354 }
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700355
356 return true;
Yingdi Yu27158392014-01-20 13:04:20 -0800357}
358
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800359template<class InputIterator>
360inline uint32_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700361readType(InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800362{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700363 uint64_t type = readVarNumber(begin, end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800364 if (type > std::numeric_limits<uint32_t>::max())
365 {
366 throw Error("TLV type code exceeds allowed maximum");
367 }
368
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700369 return static_cast<uint32_t>(type);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800370}
371
372size_t
373sizeOfVarNumber(uint64_t varNumber)
374{
375 if (varNumber < 253) {
376 return 1;
377 }
378 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
379 return 3;
380 }
381 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
382 return 5;
383 }
384 else {
385 return 9;
386 }
387}
388
389inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700390writeVarNumber(std::ostream& os, uint64_t varNumber)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800391{
392 if (varNumber < 253) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200393 os.put(static_cast<char>(varNumber));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800394 return 1;
395 }
396 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200397 os.put(static_cast<char>(253));
398 uint16_t value = htobe16(static_cast<uint16_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700399 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800400 return 3;
401 }
402 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200403 os.put(static_cast<char>(254));
404 uint32_t value = htobe32(static_cast<uint32_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700405 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800406 return 5;
407 }
408 else {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200409 os.put(static_cast<char>(255));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800410 uint64_t value = htobe64(varNumber);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700411 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800412 return 9;
413 }
414}
415
416template<class InputIterator>
417inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700418readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800419{
420 switch (size) {
421 case 1:
422 {
423 if (end - begin < 1)
424 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700425
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800426 uint8_t value = *begin;
427 begin++;
428 return value;
429 }
430 case 2:
431 {
432 if (end - begin < 2)
433 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700434
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700435 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800436 begin += 2;
437 return be16toh(value);
438 }
439 case 4:
440 {
441 if (end - begin < 4)
442 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700443
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700444 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800445 begin += 4;
446 return be32toh(value);
447 }
448 case 8:
449 {
450 if (end - begin < 8)
451 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700452
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800453 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
454 begin += 8;
455 return be64toh(value);
456 }
457 }
458 throw Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)");
459}
460
Yingdi Yu27158392014-01-20 13:04:20 -0800461template<>
462inline uint64_t
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700463readNonNegativeInteger<std::istream_iterator<uint8_t> >(size_t size,
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700464 std::istream_iterator<uint8_t>& begin,
465 const std::istream_iterator<uint8_t>& end)
Yingdi Yu27158392014-01-20 13:04:20 -0800466{
467 switch (size) {
468 case 1:
469 {
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700470 if (begin == end)
Yingdi Yu27158392014-01-20 13:04:20 -0800471 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700472
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700473 uint64_t value = *begin;
Yingdi Yu27158392014-01-20 13:04:20 -0800474 begin++;
475 return value;
476 }
477 case 2:
478 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700479 uint64_t value = 0;
480 size_t count = 0;
481 for (; begin != end && count < 2; ++count)
482 {
483 value = ((value << 8) | *begin);
484 begin++;
485 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700486
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700487 if (count != 2)
Yingdi Yu27158392014-01-20 13:04:20 -0800488 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700489
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700490 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800491 }
492 case 4:
493 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700494 uint64_t value = 0;
495 size_t count = 0;
496 for (; begin != end && count < 4; ++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 != 4)
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 8:
508 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700509 uint64_t value = 0;
510 size_t count = 0;
511 for (; begin != end && count < 8; ++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 != 8)
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 }
523 throw Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)");
524}
525
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800526inline size_t
527sizeOfNonNegativeInteger(uint64_t varNumber)
528{
529 if (varNumber < 253) {
530 return 1;
531 }
532 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
533 return 2;
534 }
535 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
536 return 4;
537 }
538 else {
539 return 8;
540 }
541}
542
543
544inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700545writeNonNegativeInteger(std::ostream& os, uint64_t varNumber)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800546{
547 if (varNumber < 253) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200548 os.put(static_cast<char>(varNumber));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800549 return 1;
550 }
551 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200552 uint16_t value = htobe16(static_cast<uint16_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700553 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800554 return 2;
555 }
556 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200557 uint32_t value = htobe32(static_cast<uint32_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700558 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800559 return 4;
560 }
561 else {
562 uint64_t value = htobe64(varNumber);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700563 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800564 return 8;
565 }
566}
567
568
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600569} // namespace tlv
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800570} // namespace ndn
571
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700572#endif // NDN_ENCODING_TLV_HPP