blob: 1c4851afb766796f814b4861c84a00d9c8d88bae [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,
109 NotAfter = 255
110};
111
Junxiao Shia464b922014-11-12 21:13:06 -0700112/** @brief indicates a possible value of ContentType field
113 */
Yingdi Yuebfa4cb2014-06-17 15:28:53 -0700114enum ContentTypeValue {
Junxiao Shia464b922014-11-12 21:13:06 -0700115 /** @brief indicates content is the actual data bits
116 */
117 ContentType_Blob = 0,
118
119 /** @brief indicates content is another name which identifies actual data content
120 */
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800121 ContentType_Link = 1,
Junxiao Shia464b922014-11-12 21:13:06 -0700122
123 /** @brief indicates content is a public key
124 */
125 ContentType_Key = 2,
126
127 /** @brief indicates a producer generated NACK
128 * @warning Experimental. Not defined in NDN-TLV spec.
129 */
130 ContentType_Nack = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800131};
132
133/**
134 * @brief Read VAR-NUMBER in NDN-TLV encoding
135 *
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700136 * @param [in] begin Begin (pointer or iterator) of the buffer
137 * @param [in] end End (pointer or iterator) of the buffer
138 * @param [out] number Read number
139 *
140 * @throws This call never throws exception
141 *
142 * @return true if number successfully read from input, false otherwise
143 */
144template<class InputIterator>
145inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700146readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700147
148/**
149 * @brief Read TLV Type
150 *
151 * @param [in] begin Begin (pointer or iterator) of the buffer
152 * @param [in] end End (pointer or iterator) of the buffer
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700153 * @param [out] type Read type number
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700154 *
155 * @throws This call never throws exception
156 *
157 * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
158 * is larger than 2^32-1 (type in this library is implemented as uint32_t)
159 */
160template<class InputIterator>
161inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700162readType(InputIterator& begin, const InputIterator& end, uint32_t& type);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700163
164
165/**
166 * @brief Read VAR-NUMBER in NDN-TLV encoding
167 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600168 * @throws This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800169 *
170 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
171 */
172template<class InputIterator>
173inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700174readVarNumber(InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800175
176/**
177 * @brief Read TLV Type
178 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600179 * @throws This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700180 *
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800181 * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
182 * is larger than 2^32-1 (type in this library is implemented as uint32_t)
183 */
184template<class InputIterator>
185inline uint32_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700186readType(InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800187
188/**
189 * @brief Get number of bytes necessary to hold value of VAR-NUMBER
190 */
191inline size_t
192sizeOfVarNumber(uint64_t varNumber);
193
194/**
195 * @brief Write VAR-NUMBER to the specified stream
196 */
197inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700198writeVarNumber(std::ostream& os, uint64_t varNumber);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800199
200/**
201 * @brief Read nonNegativeInteger in NDN-TLV encoding
202 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600203 * This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800204 *
205 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
206 *
207 * How many bytes will be read is directly controlled by the size parameter, which can be either
208 * 1, 2, 4, or 8. If the value of size is different, then an exception will be thrown.
209 */
210template<class InputIterator>
211inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700212readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800213
214/**
215 * @brief Get number of bytes necessary to hold value of nonNegativeInteger
216 */
217inline size_t
218sizeOfNonNegativeInteger(uint64_t varNumber);
219
220/**
221 * @brief Write nonNegativeInteger to the specified stream
222 */
223inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700224writeNonNegativeInteger(std::ostream& os, uint64_t varNumber);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800225
226/////////////////////////////////////////////////////////////////////////////////
227/////////////////////////////////////////////////////////////////////////////////
228/////////////////////////////////////////////////////////////////////////////////
229
230// Inline implementations
231
232/////////////////////////////////////////////////////////////////////////////////
233/////////////////////////////////////////////////////////////////////////////////
234/////////////////////////////////////////////////////////////////////////////////
235
236template<class InputIterator>
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700237inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700238readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700239{
240 if (begin == end)
241 return false;
242
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700243 uint8_t firstOctet = *begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700244 ++begin;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700245 if (firstOctet < 253)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700246 {
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700247 number = firstOctet;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700248 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700249 else if (firstOctet == 253)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700250 {
251 if (end - begin < 2)
252 return false;
253
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700254 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700255 begin += 2;
256 number = be16toh(value);
257 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700258 else if (firstOctet == 254)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700259 {
260 if (end - begin < 4)
261 return false;
262
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700263 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700264 begin += 4;
265 number = be32toh(value);
266 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700267 else // if (firstOctet == 255)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700268 {
269 if (end - begin < 8)
270 return false;
271
272 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
273 begin += 8;
274
275 number = be64toh(value);
276 }
277
278 return true;
279}
280
281template<class InputIterator>
282inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700283readType(InputIterator& begin, const InputIterator& end, uint32_t& type)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700284{
Mickey Sweatt632e0572014-04-20 00:36:32 -0700285 uint64_t number = 0;
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700286 bool isOk = readVarNumber(begin, end, number);
287 if (!isOk || number > std::numeric_limits<uint32_t>::max())
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700288 {
289 return false;
290 }
291
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700292 type = static_cast<uint64_t>(number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700293 return true;
294}
295
296template<class InputIterator>
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800297inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700298readVarNumber(InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800299{
300 if (begin == end)
301 throw Error("Empty buffer during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700302
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700303 uint64_t value;
304 bool isOk = readVarNumber(begin, end, value);
305 if (!isOk)
306 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700307
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700308 return value;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800309}
310
Yingdi Yu27158392014-01-20 13:04:20 -0800311template<>
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700312inline bool
Junxiao Shi468abc32014-11-04 09:12:47 -0700313readVarNumber<std::istream_iterator<uint8_t>>(std::istream_iterator<uint8_t>& begin,
314 const std::istream_iterator<uint8_t>& end,
315 uint64_t& value)
Yingdi Yu27158392014-01-20 13:04:20 -0800316{
317 if (begin == end)
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700318 return false;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700319
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700320 uint8_t firstOctet = *begin;
Yingdi Yu27158392014-01-20 13:04:20 -0800321 ++begin;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700322 if (firstOctet < 253)
Yingdi Yu27158392014-01-20 13:04:20 -0800323 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700324 value = firstOctet;
Yingdi Yu27158392014-01-20 13:04:20 -0800325 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700326 else if (firstOctet == 253)
Yingdi Yu27158392014-01-20 13:04:20 -0800327 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700328 value = 0;
329 size_t count = 0;
330 for (; begin != end && count < 2; ++count)
331 {
332 value = ((value << 8) | *begin);
333 begin++;
334 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700335
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700336 if (count != 2)
337 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800338 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700339 else if (firstOctet == 254)
Yingdi Yu27158392014-01-20 13:04:20 -0800340 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700341 value = 0;
342 size_t count = 0;
343 for (; begin != end && count < 4; ++count)
344 {
345 value = ((value << 8) | *begin);
346 begin++;
347 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700348
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700349 if (count != 4)
350 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800351 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700352 else // if (firstOctet == 255)
Yingdi Yu27158392014-01-20 13:04:20 -0800353 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700354 value = 0;
355 size_t count = 0;
356 for (; begin != end && count < 8; ++count)
357 {
358 value = ((value << 8) | *begin);
359 begin++;
360 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700361
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700362 if (count != 8)
363 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800364 }
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700365
366 return true;
Yingdi Yu27158392014-01-20 13:04:20 -0800367}
368
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800369template<class InputIterator>
370inline uint32_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700371readType(InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800372{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700373 uint64_t type = readVarNumber(begin, end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800374 if (type > std::numeric_limits<uint32_t>::max())
375 {
376 throw Error("TLV type code exceeds allowed maximum");
377 }
378
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700379 return static_cast<uint32_t>(type);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800380}
381
382size_t
383sizeOfVarNumber(uint64_t varNumber)
384{
385 if (varNumber < 253) {
386 return 1;
387 }
388 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
389 return 3;
390 }
391 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
392 return 5;
393 }
394 else {
395 return 9;
396 }
397}
398
399inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700400writeVarNumber(std::ostream& os, uint64_t varNumber)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800401{
402 if (varNumber < 253) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200403 os.put(static_cast<char>(varNumber));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800404 return 1;
405 }
406 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200407 os.put(static_cast<char>(253));
408 uint16_t value = htobe16(static_cast<uint16_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700409 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800410 return 3;
411 }
412 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200413 os.put(static_cast<char>(254));
414 uint32_t value = htobe32(static_cast<uint32_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700415 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800416 return 5;
417 }
418 else {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200419 os.put(static_cast<char>(255));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800420 uint64_t value = htobe64(varNumber);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700421 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800422 return 9;
423 }
424}
425
426template<class InputIterator>
427inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700428readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800429{
430 switch (size) {
431 case 1:
432 {
433 if (end - begin < 1)
434 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700435
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800436 uint8_t value = *begin;
437 begin++;
438 return value;
439 }
440 case 2:
441 {
442 if (end - begin < 2)
443 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700444
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700445 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800446 begin += 2;
447 return be16toh(value);
448 }
449 case 4:
450 {
451 if (end - begin < 4)
452 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700453
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700454 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800455 begin += 4;
456 return be32toh(value);
457 }
458 case 8:
459 {
460 if (end - begin < 8)
461 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700462
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800463 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
464 begin += 8;
465 return be64toh(value);
466 }
467 }
468 throw Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)");
469}
470
Yingdi Yu27158392014-01-20 13:04:20 -0800471template<>
472inline uint64_t
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700473readNonNegativeInteger<std::istream_iterator<uint8_t> >(size_t size,
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700474 std::istream_iterator<uint8_t>& begin,
475 const std::istream_iterator<uint8_t>& end)
Yingdi Yu27158392014-01-20 13:04:20 -0800476{
477 switch (size) {
478 case 1:
479 {
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700480 if (begin == end)
Yingdi Yu27158392014-01-20 13:04:20 -0800481 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700482
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700483 uint64_t value = *begin;
Yingdi Yu27158392014-01-20 13:04:20 -0800484 begin++;
485 return value;
486 }
487 case 2:
488 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700489 uint64_t value = 0;
490 size_t count = 0;
491 for (; begin != end && count < 2; ++count)
492 {
493 value = ((value << 8) | *begin);
494 begin++;
495 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700496
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700497 if (count != 2)
Yingdi Yu27158392014-01-20 13:04:20 -0800498 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700499
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700500 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800501 }
502 case 4:
503 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700504 uint64_t value = 0;
505 size_t count = 0;
506 for (; begin != end && count < 4; ++count)
507 {
508 value = ((value << 8) | *begin);
509 begin++;
510 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700511
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700512 if (count != 4)
Yingdi Yu27158392014-01-20 13:04:20 -0800513 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700514
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700515 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800516 }
517 case 8:
518 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700519 uint64_t value = 0;
520 size_t count = 0;
521 for (; begin != end && count < 8; ++count)
522 {
523 value = ((value << 8) | *begin);
524 begin++;
525 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700526
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700527 if (count != 8)
Yingdi Yu27158392014-01-20 13:04:20 -0800528 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700529
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700530 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800531 }
532 }
533 throw Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)");
534}
535
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800536inline size_t
537sizeOfNonNegativeInteger(uint64_t varNumber)
538{
539 if (varNumber < 253) {
540 return 1;
541 }
542 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
543 return 2;
544 }
545 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
546 return 4;
547 }
548 else {
549 return 8;
550 }
551}
552
553
554inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700555writeNonNegativeInteger(std::ostream& os, uint64_t varNumber)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800556{
557 if (varNumber < 253) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200558 os.put(static_cast<char>(varNumber));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800559 return 1;
560 }
561 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200562 uint16_t value = htobe16(static_cast<uint16_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700563 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800564 return 2;
565 }
566 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200567 uint32_t value = htobe32(static_cast<uint32_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700568 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800569 return 4;
570 }
571 else {
572 uint64_t value = htobe64(varNumber);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700573 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800574 return 8;
575 }
576}
577
578
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600579} // namespace tlv
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800580} // namespace ndn
581
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700582#endif // NDN_ENCODING_TLV_HPP