blob: 6a7589ea8f960e1c6173f41b329e3e5afd710507 [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 Afanasyeva465e972014-03-22 17:21:49 -070068 Scope = 11, // deprecated
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,
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080087
88 AppPrivateBlock1 = 128,
89 AppPrivateBlock2 = 32767
90};
91
Yingdi Yuebfa4cb2014-06-17 15:28:53 -070092enum SignatureTypeValue {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080093 DigestSha256 = 0,
Yingdi Yuebfa4cb2014-06-17 15:28:53 -070094 SignatureSha256WithRsa = 1,
95 SignatureSha256WithEcdsa = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080096};
97
Junxiao Shia464b922014-11-12 21:13:06 -070098/** @brief indicates a possible value of ContentType field
99 */
Yingdi Yuebfa4cb2014-06-17 15:28:53 -0700100enum ContentTypeValue {
Junxiao Shia464b922014-11-12 21:13:06 -0700101 /** @brief indicates content is the actual data bits
102 */
103 ContentType_Blob = 0,
104
105 /** @brief indicates content is another name which identifies actual data content
106 */
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800107 ContentType_Link = 1,
Junxiao Shia464b922014-11-12 21:13:06 -0700108
109 /** @brief indicates content is a public key
110 */
111 ContentType_Key = 2,
112
113 /** @brief indicates a producer generated NACK
114 * @warning Experimental. Not defined in NDN-TLV spec.
115 */
116 ContentType_Nack = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800117};
118
Junxiao Shia464b922014-11-12 21:13:06 -0700119/** @deprecated use ContentType_Blob
120 */
121static const uint32_t DEPRECATED(ContentType_Default) = ContentType_Blob;
122
123
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800124/**
125 * @brief Read VAR-NUMBER in NDN-TLV encoding
126 *
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700127 * @param [in] begin Begin (pointer or iterator) of the buffer
128 * @param [in] end End (pointer or iterator) of the buffer
129 * @param [out] number Read number
130 *
131 * @throws This call never throws exception
132 *
133 * @return true if number successfully read from input, false otherwise
134 */
135template<class InputIterator>
136inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700137readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700138
139/**
140 * @brief Read TLV Type
141 *
142 * @param [in] begin Begin (pointer or iterator) of the buffer
143 * @param [in] end End (pointer or iterator) of the buffer
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700144 * @param [out] type Read type number
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700145 *
146 * @throws This call never throws exception
147 *
148 * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
149 * is larger than 2^32-1 (type in this library is implemented as uint32_t)
150 */
151template<class InputIterator>
152inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700153readType(InputIterator& begin, const InputIterator& end, uint32_t& type);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700154
155
156/**
157 * @brief Read VAR-NUMBER in NDN-TLV encoding
158 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600159 * @throws This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800160 *
161 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
162 */
163template<class InputIterator>
164inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700165readVarNumber(InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800166
167/**
168 * @brief Read TLV Type
169 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600170 * @throws This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700171 *
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800172 * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
173 * is larger than 2^32-1 (type in this library is implemented as uint32_t)
174 */
175template<class InputIterator>
176inline uint32_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700177readType(InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800178
179/**
180 * @brief Get number of bytes necessary to hold value of VAR-NUMBER
181 */
182inline size_t
183sizeOfVarNumber(uint64_t varNumber);
184
185/**
186 * @brief Write VAR-NUMBER to the specified stream
187 */
188inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700189writeVarNumber(std::ostream& os, uint64_t varNumber);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800190
191/**
192 * @brief Read nonNegativeInteger in NDN-TLV encoding
193 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600194 * This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800195 *
196 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
197 *
198 * How many bytes will be read is directly controlled by the size parameter, which can be either
199 * 1, 2, 4, or 8. If the value of size is different, then an exception will be thrown.
200 */
201template<class InputIterator>
202inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700203readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800204
205/**
206 * @brief Get number of bytes necessary to hold value of nonNegativeInteger
207 */
208inline size_t
209sizeOfNonNegativeInteger(uint64_t varNumber);
210
211/**
212 * @brief Write nonNegativeInteger to the specified stream
213 */
214inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700215writeNonNegativeInteger(std::ostream& os, uint64_t varNumber);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800216
217/////////////////////////////////////////////////////////////////////////////////
218/////////////////////////////////////////////////////////////////////////////////
219/////////////////////////////////////////////////////////////////////////////////
220
221// Inline implementations
222
223/////////////////////////////////////////////////////////////////////////////////
224/////////////////////////////////////////////////////////////////////////////////
225/////////////////////////////////////////////////////////////////////////////////
226
227template<class InputIterator>
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700228inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700229readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700230{
231 if (begin == end)
232 return false;
233
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700234 uint8_t firstOctet = *begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700235 ++begin;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700236 if (firstOctet < 253)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700237 {
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700238 number = firstOctet;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700239 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700240 else if (firstOctet == 253)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700241 {
242 if (end - begin < 2)
243 return false;
244
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700245 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700246 begin += 2;
247 number = be16toh(value);
248 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700249 else if (firstOctet == 254)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700250 {
251 if (end - begin < 4)
252 return false;
253
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700254 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700255 begin += 4;
256 number = be32toh(value);
257 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700258 else // if (firstOctet == 255)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700259 {
260 if (end - begin < 8)
261 return false;
262
263 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
264 begin += 8;
265
266 number = be64toh(value);
267 }
268
269 return true;
270}
271
272template<class InputIterator>
273inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700274readType(InputIterator& begin, const InputIterator& end, uint32_t& type)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700275{
Mickey Sweatt632e0572014-04-20 00:36:32 -0700276 uint64_t number = 0;
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700277 bool isOk = readVarNumber(begin, end, number);
278 if (!isOk || number > std::numeric_limits<uint32_t>::max())
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700279 {
280 return false;
281 }
282
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700283 type = static_cast<uint64_t>(number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700284 return true;
285}
286
287template<class InputIterator>
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800288inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700289readVarNumber(InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800290{
291 if (begin == end)
292 throw Error("Empty buffer during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700293
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700294 uint64_t value;
295 bool isOk = readVarNumber(begin, end, value);
296 if (!isOk)
297 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700298
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700299 return value;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800300}
301
Yingdi Yu27158392014-01-20 13:04:20 -0800302template<>
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700303inline bool
Junxiao Shi468abc32014-11-04 09:12:47 -0700304readVarNumber<std::istream_iterator<uint8_t>>(std::istream_iterator<uint8_t>& begin,
305 const std::istream_iterator<uint8_t>& end,
306 uint64_t& value)
Yingdi Yu27158392014-01-20 13:04:20 -0800307{
308 if (begin == end)
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700309 return false;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700310
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700311 uint8_t firstOctet = *begin;
Yingdi Yu27158392014-01-20 13:04:20 -0800312 ++begin;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700313 if (firstOctet < 253)
Yingdi Yu27158392014-01-20 13:04:20 -0800314 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700315 value = firstOctet;
Yingdi Yu27158392014-01-20 13:04:20 -0800316 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700317 else if (firstOctet == 253)
Yingdi Yu27158392014-01-20 13:04:20 -0800318 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700319 value = 0;
320 size_t count = 0;
321 for (; begin != end && count < 2; ++count)
322 {
323 value = ((value << 8) | *begin);
324 begin++;
325 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700326
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700327 if (count != 2)
328 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800329 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700330 else if (firstOctet == 254)
Yingdi Yu27158392014-01-20 13:04:20 -0800331 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700332 value = 0;
333 size_t count = 0;
334 for (; begin != end && count < 4; ++count)
335 {
336 value = ((value << 8) | *begin);
337 begin++;
338 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700339
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700340 if (count != 4)
341 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800342 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700343 else // if (firstOctet == 255)
Yingdi Yu27158392014-01-20 13:04:20 -0800344 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700345 value = 0;
346 size_t count = 0;
347 for (; begin != end && count < 8; ++count)
348 {
349 value = ((value << 8) | *begin);
350 begin++;
351 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700352
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700353 if (count != 8)
354 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800355 }
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700356
357 return true;
Yingdi Yu27158392014-01-20 13:04:20 -0800358}
359
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800360template<class InputIterator>
361inline uint32_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700362readType(InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800363{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700364 uint64_t type = readVarNumber(begin, end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800365 if (type > std::numeric_limits<uint32_t>::max())
366 {
367 throw Error("TLV type code exceeds allowed maximum");
368 }
369
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700370 return static_cast<uint32_t>(type);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800371}
372
373size_t
374sizeOfVarNumber(uint64_t varNumber)
375{
376 if (varNumber < 253) {
377 return 1;
378 }
379 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
380 return 3;
381 }
382 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
383 return 5;
384 }
385 else {
386 return 9;
387 }
388}
389
390inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700391writeVarNumber(std::ostream& os, uint64_t varNumber)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800392{
393 if (varNumber < 253) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200394 os.put(static_cast<char>(varNumber));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800395 return 1;
396 }
397 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200398 os.put(static_cast<char>(253));
399 uint16_t value = htobe16(static_cast<uint16_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700400 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800401 return 3;
402 }
403 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200404 os.put(static_cast<char>(254));
405 uint32_t value = htobe32(static_cast<uint32_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700406 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800407 return 5;
408 }
409 else {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200410 os.put(static_cast<char>(255));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800411 uint64_t value = htobe64(varNumber);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700412 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800413 return 9;
414 }
415}
416
417template<class InputIterator>
418inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700419readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800420{
421 switch (size) {
422 case 1:
423 {
424 if (end - begin < 1)
425 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700426
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800427 uint8_t value = *begin;
428 begin++;
429 return value;
430 }
431 case 2:
432 {
433 if (end - begin < 2)
434 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700435
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700436 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800437 begin += 2;
438 return be16toh(value);
439 }
440 case 4:
441 {
442 if (end - begin < 4)
443 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700444
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700445 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800446 begin += 4;
447 return be32toh(value);
448 }
449 case 8:
450 {
451 if (end - begin < 8)
452 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700453
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800454 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
455 begin += 8;
456 return be64toh(value);
457 }
458 }
459 throw Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)");
460}
461
Yingdi Yu27158392014-01-20 13:04:20 -0800462template<>
463inline uint64_t
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700464readNonNegativeInteger<std::istream_iterator<uint8_t> >(size_t size,
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700465 std::istream_iterator<uint8_t>& begin,
466 const std::istream_iterator<uint8_t>& end)
Yingdi Yu27158392014-01-20 13:04:20 -0800467{
468 switch (size) {
469 case 1:
470 {
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700471 if (begin == end)
Yingdi Yu27158392014-01-20 13:04:20 -0800472 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700473
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700474 uint64_t value = *begin;
Yingdi Yu27158392014-01-20 13:04:20 -0800475 begin++;
476 return value;
477 }
478 case 2:
479 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700480 uint64_t value = 0;
481 size_t count = 0;
482 for (; begin != end && count < 2; ++count)
483 {
484 value = ((value << 8) | *begin);
485 begin++;
486 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700487
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700488 if (count != 2)
Yingdi Yu27158392014-01-20 13:04:20 -0800489 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700490
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700491 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800492 }
493 case 4:
494 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700495 uint64_t value = 0;
496 size_t count = 0;
497 for (; begin != end && count < 4; ++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 != 4)
Yingdi Yu27158392014-01-20 13:04:20 -0800504 throw 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 8:
509 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700510 uint64_t value = 0;
511 size_t count = 0;
512 for (; begin != end && count < 8; ++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 != 8)
Yingdi Yu27158392014-01-20 13:04:20 -0800519 throw 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 }
524 throw Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)");
525}
526
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800527inline size_t
528sizeOfNonNegativeInteger(uint64_t varNumber)
529{
530 if (varNumber < 253) {
531 return 1;
532 }
533 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
534 return 2;
535 }
536 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
537 return 4;
538 }
539 else {
540 return 8;
541 }
542}
543
544
545inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700546writeNonNegativeInteger(std::ostream& os, uint64_t varNumber)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800547{
548 if (varNumber < 253) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200549 os.put(static_cast<char>(varNumber));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800550 return 1;
551 }
552 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200553 uint16_t value = htobe16(static_cast<uint16_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700554 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800555 return 2;
556 }
557 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200558 uint32_t value = htobe32(static_cast<uint32_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700559 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800560 return 4;
561 }
562 else {
563 uint64_t value = htobe64(varNumber);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700564 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800565 return 8;
566 }
567}
568
569
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600570} // namespace tlv
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800571} // namespace ndn
572
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700573#endif // NDN_ENCODING_TLV_HPP