blob: 284ca26988dc799f54366e975acd84729c18f02b [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
Yingdi Yuebfa4cb2014-06-17 15:28:53 -070098enum ContentTypeValue {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080099 ContentType_Default = 0,
100 ContentType_Link = 1,
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700101 ContentType_Key = 2
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800102};
103
104/**
105 * @brief Read VAR-NUMBER in NDN-TLV encoding
106 *
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700107 * @param [in] begin Begin (pointer or iterator) of the buffer
108 * @param [in] end End (pointer or iterator) of the buffer
109 * @param [out] number Read number
110 *
111 * @throws This call never throws exception
112 *
113 * @return true if number successfully read from input, false otherwise
114 */
115template<class InputIterator>
116inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700117readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700118
119/**
120 * @brief Read TLV Type
121 *
122 * @param [in] begin Begin (pointer or iterator) of the buffer
123 * @param [in] end End (pointer or iterator) of the buffer
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700124 * @param [out] type Read type number
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700125 *
126 * @throws This call never throws exception
127 *
128 * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
129 * is larger than 2^32-1 (type in this library is implemented as uint32_t)
130 */
131template<class InputIterator>
132inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700133readType(InputIterator& begin, const InputIterator& end, uint32_t& type);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700134
135
136/**
137 * @brief Read VAR-NUMBER in NDN-TLV encoding
138 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600139 * @throws This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800140 *
141 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
142 */
143template<class InputIterator>
144inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700145readVarNumber(InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800146
147/**
148 * @brief Read TLV Type
149 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600150 * @throws This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700151 *
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800152 * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
153 * is larger than 2^32-1 (type in this library is implemented as uint32_t)
154 */
155template<class InputIterator>
156inline uint32_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700157readType(InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800158
159/**
160 * @brief Get number of bytes necessary to hold value of VAR-NUMBER
161 */
162inline size_t
163sizeOfVarNumber(uint64_t varNumber);
164
165/**
166 * @brief Write VAR-NUMBER to the specified stream
167 */
168inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700169writeVarNumber(std::ostream& os, uint64_t varNumber);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800170
171/**
172 * @brief Read nonNegativeInteger in NDN-TLV encoding
173 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600174 * This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800175 *
176 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
177 *
178 * How many bytes will be read is directly controlled by the size parameter, which can be either
179 * 1, 2, 4, or 8. If the value of size is different, then an exception will be thrown.
180 */
181template<class InputIterator>
182inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700183readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800184
185/**
186 * @brief Get number of bytes necessary to hold value of nonNegativeInteger
187 */
188inline size_t
189sizeOfNonNegativeInteger(uint64_t varNumber);
190
191/**
192 * @brief Write nonNegativeInteger to the specified stream
193 */
194inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700195writeNonNegativeInteger(std::ostream& os, uint64_t varNumber);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800196
197/////////////////////////////////////////////////////////////////////////////////
198/////////////////////////////////////////////////////////////////////////////////
199/////////////////////////////////////////////////////////////////////////////////
200
201// Inline implementations
202
203/////////////////////////////////////////////////////////////////////////////////
204/////////////////////////////////////////////////////////////////////////////////
205/////////////////////////////////////////////////////////////////////////////////
206
207template<class InputIterator>
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700208inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700209readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700210{
211 if (begin == end)
212 return false;
213
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700214 uint8_t firstOctet = *begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700215 ++begin;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700216 if (firstOctet < 253)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700217 {
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700218 number = firstOctet;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700219 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700220 else if (firstOctet == 253)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700221 {
222 if (end - begin < 2)
223 return false;
224
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700225 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700226 begin += 2;
227 number = be16toh(value);
228 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700229 else if (firstOctet == 254)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700230 {
231 if (end - begin < 4)
232 return false;
233
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700234 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700235 begin += 4;
236 number = be32toh(value);
237 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700238 else // if (firstOctet == 255)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700239 {
240 if (end - begin < 8)
241 return false;
242
243 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
244 begin += 8;
245
246 number = be64toh(value);
247 }
248
249 return true;
250}
251
252template<class InputIterator>
253inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700254readType(InputIterator& begin, const InputIterator& end, uint32_t& type)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700255{
Mickey Sweatt632e0572014-04-20 00:36:32 -0700256 uint64_t number = 0;
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700257 bool isOk = readVarNumber(begin, end, number);
258 if (!isOk || number > std::numeric_limits<uint32_t>::max())
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700259 {
260 return false;
261 }
262
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700263 type = static_cast<uint64_t>(number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700264 return true;
265}
266
267template<class InputIterator>
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800268inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700269readVarNumber(InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800270{
271 if (begin == end)
272 throw Error("Empty buffer during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700273
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700274 uint64_t value;
275 bool isOk = readVarNumber(begin, end, value);
276 if (!isOk)
277 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700278
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700279 return value;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800280}
281
Yingdi Yu27158392014-01-20 13:04:20 -0800282template<>
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700283inline bool
Junxiao Shi468abc32014-11-04 09:12:47 -0700284readVarNumber<std::istream_iterator<uint8_t>>(std::istream_iterator<uint8_t>& begin,
285 const std::istream_iterator<uint8_t>& end,
286 uint64_t& value)
Yingdi Yu27158392014-01-20 13:04:20 -0800287{
288 if (begin == end)
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700289 return false;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700290
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700291 uint8_t firstOctet = *begin;
Yingdi Yu27158392014-01-20 13:04:20 -0800292 ++begin;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700293 if (firstOctet < 253)
Yingdi Yu27158392014-01-20 13:04:20 -0800294 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700295 value = firstOctet;
Yingdi Yu27158392014-01-20 13:04:20 -0800296 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700297 else if (firstOctet == 253)
Yingdi Yu27158392014-01-20 13:04:20 -0800298 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700299 value = 0;
300 size_t count = 0;
301 for (; begin != end && count < 2; ++count)
302 {
303 value = ((value << 8) | *begin);
304 begin++;
305 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700306
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700307 if (count != 2)
308 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800309 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700310 else if (firstOctet == 254)
Yingdi Yu27158392014-01-20 13:04:20 -0800311 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700312 value = 0;
313 size_t count = 0;
314 for (; begin != end && count < 4; ++count)
315 {
316 value = ((value << 8) | *begin);
317 begin++;
318 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700319
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700320 if (count != 4)
321 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800322 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700323 else // if (firstOctet == 255)
Yingdi Yu27158392014-01-20 13:04:20 -0800324 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700325 value = 0;
326 size_t count = 0;
327 for (; begin != end && count < 8; ++count)
328 {
329 value = ((value << 8) | *begin);
330 begin++;
331 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700332
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700333 if (count != 8)
334 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800335 }
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700336
337 return true;
Yingdi Yu27158392014-01-20 13:04:20 -0800338}
339
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800340template<class InputIterator>
341inline uint32_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700342readType(InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800343{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700344 uint64_t type = readVarNumber(begin, end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800345 if (type > std::numeric_limits<uint32_t>::max())
346 {
347 throw Error("TLV type code exceeds allowed maximum");
348 }
349
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700350 return static_cast<uint32_t>(type);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800351}
352
353size_t
354sizeOfVarNumber(uint64_t varNumber)
355{
356 if (varNumber < 253) {
357 return 1;
358 }
359 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
360 return 3;
361 }
362 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
363 return 5;
364 }
365 else {
366 return 9;
367 }
368}
369
370inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700371writeVarNumber(std::ostream& os, uint64_t varNumber)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800372{
373 if (varNumber < 253) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200374 os.put(static_cast<char>(varNumber));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800375 return 1;
376 }
377 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200378 os.put(static_cast<char>(253));
379 uint16_t value = htobe16(static_cast<uint16_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700380 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800381 return 3;
382 }
383 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200384 os.put(static_cast<char>(254));
385 uint32_t value = htobe32(static_cast<uint32_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700386 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800387 return 5;
388 }
389 else {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200390 os.put(static_cast<char>(255));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800391 uint64_t value = htobe64(varNumber);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700392 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800393 return 9;
394 }
395}
396
397template<class InputIterator>
398inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700399readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800400{
401 switch (size) {
402 case 1:
403 {
404 if (end - begin < 1)
405 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700406
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800407 uint8_t value = *begin;
408 begin++;
409 return value;
410 }
411 case 2:
412 {
413 if (end - begin < 2)
414 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700415
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700416 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800417 begin += 2;
418 return be16toh(value);
419 }
420 case 4:
421 {
422 if (end - begin < 4)
423 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700424
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700425 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800426 begin += 4;
427 return be32toh(value);
428 }
429 case 8:
430 {
431 if (end - begin < 8)
432 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700433
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800434 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
435 begin += 8;
436 return be64toh(value);
437 }
438 }
439 throw Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)");
440}
441
Yingdi Yu27158392014-01-20 13:04:20 -0800442template<>
443inline uint64_t
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700444readNonNegativeInteger<std::istream_iterator<uint8_t> >(size_t size,
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700445 std::istream_iterator<uint8_t>& begin,
446 const std::istream_iterator<uint8_t>& end)
Yingdi Yu27158392014-01-20 13:04:20 -0800447{
448 switch (size) {
449 case 1:
450 {
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700451 if (begin == end)
Yingdi Yu27158392014-01-20 13:04:20 -0800452 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700453
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700454 uint64_t value = *begin;
Yingdi Yu27158392014-01-20 13:04:20 -0800455 begin++;
456 return value;
457 }
458 case 2:
459 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700460 uint64_t value = 0;
461 size_t count = 0;
462 for (; begin != end && count < 2; ++count)
463 {
464 value = ((value << 8) | *begin);
465 begin++;
466 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700467
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700468 if (count != 2)
Yingdi Yu27158392014-01-20 13:04:20 -0800469 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700470
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700471 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800472 }
473 case 4:
474 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700475 uint64_t value = 0;
476 size_t count = 0;
477 for (; begin != end && count < 4; ++count)
478 {
479 value = ((value << 8) | *begin);
480 begin++;
481 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700482
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700483 if (count != 4)
Yingdi Yu27158392014-01-20 13:04:20 -0800484 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700485
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700486 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800487 }
488 case 8:
489 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700490 uint64_t value = 0;
491 size_t count = 0;
492 for (; begin != end && count < 8; ++count)
493 {
494 value = ((value << 8) | *begin);
495 begin++;
496 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700497
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700498 if (count != 8)
Yingdi Yu27158392014-01-20 13:04:20 -0800499 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700500
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700501 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800502 }
503 }
504 throw Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)");
505}
506
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800507inline size_t
508sizeOfNonNegativeInteger(uint64_t varNumber)
509{
510 if (varNumber < 253) {
511 return 1;
512 }
513 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
514 return 2;
515 }
516 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
517 return 4;
518 }
519 else {
520 return 8;
521 }
522}
523
524
525inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700526writeNonNegativeInteger(std::ostream& os, uint64_t varNumber)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800527{
528 if (varNumber < 253) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200529 os.put(static_cast<char>(varNumber));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800530 return 1;
531 }
532 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200533 uint16_t value = htobe16(static_cast<uint16_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700534 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800535 return 2;
536 }
537 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200538 uint32_t value = htobe32(static_cast<uint32_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700539 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800540 return 4;
541 }
542 else {
543 uint64_t value = htobe64(varNumber);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700544 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800545 return 8;
546 }
547}
548
549
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600550} // namespace tlv
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800551} // namespace ndn
552
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700553#endif // NDN_ENCODING_TLV_HPP