blob: c1c9b99f61a49375794bd74df7a8f6cc1bd850c5 [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,
64 NameComponent = 8,
65 Selectors = 9,
66 Nonce = 10,
Alexander Afanasyeva465e972014-03-22 17:21:49 -070067 Scope = 11, // deprecated
Alexander Afanasyev4b456282014-02-13 00:34:34 -080068 InterestLifetime = 12,
69 MinSuffixComponents = 13,
70 MaxSuffixComponents = 14,
71 PublisherPublicKeyLocator = 15,
72 Exclude = 16,
73 ChildSelector = 17,
74 MustBeFresh = 18,
75 Any = 19,
76 MetaInfo = 20,
77 Content = 21,
78 SignatureInfo = 22,
79 SignatureValue = 23,
80 ContentType = 24,
81 FreshnessPeriod = 25,
82 FinalBlockId = 26,
83 SignatureType = 27,
84 KeyLocator = 28,
Junxiao Shibc5030d2014-09-01 11:53:12 -070085 KeyDigest = 29,
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080086
87 AppPrivateBlock1 = 128,
88 AppPrivateBlock2 = 32767
89};
90
Yingdi Yuebfa4cb2014-06-17 15:28:53 -070091enum SignatureTypeValue {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080092 DigestSha256 = 0,
Yingdi Yuebfa4cb2014-06-17 15:28:53 -070093 SignatureSha256WithRsa = 1,
94 SignatureSha256WithEcdsa = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080095};
96
Yingdi Yuebfa4cb2014-06-17 15:28:53 -070097enum ContentTypeValue {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080098 ContentType_Default = 0,
99 ContentType_Link = 1,
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -0700100 ContentType_Key = 2
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800101};
102
Yingdi Yuebfa4cb2014-06-17 15:28:53 -0700103/// @deprecated use ContentType instead
104typedef ContentTypeValue ConentType;
105
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800106/**
107 * @brief Read VAR-NUMBER in NDN-TLV encoding
108 *
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700109 * @param [in] begin Begin (pointer or iterator) of the buffer
110 * @param [in] end End (pointer or iterator) of the buffer
111 * @param [out] number Read number
112 *
113 * @throws This call never throws exception
114 *
115 * @return true if number successfully read from input, false otherwise
116 */
117template<class InputIterator>
118inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700119readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700120
121/**
122 * @brief Read TLV Type
123 *
124 * @param [in] begin Begin (pointer or iterator) of the buffer
125 * @param [in] end End (pointer or iterator) of the buffer
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700126 * @param [out] type Read type number
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700127 *
128 * @throws This call never throws exception
129 *
130 * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
131 * is larger than 2^32-1 (type in this library is implemented as uint32_t)
132 */
133template<class InputIterator>
134inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700135readType(InputIterator& begin, const InputIterator& end, uint32_t& type);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700136
137
138/**
139 * @brief Read VAR-NUMBER in NDN-TLV encoding
140 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600141 * @throws This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800142 *
143 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
144 */
145template<class InputIterator>
146inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700147readVarNumber(InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800148
149/**
150 * @brief Read TLV Type
151 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600152 * @throws This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700153 *
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800154 * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
155 * is larger than 2^32-1 (type in this library is implemented as uint32_t)
156 */
157template<class InputIterator>
158inline uint32_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700159readType(InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800160
161/**
162 * @brief Get number of bytes necessary to hold value of VAR-NUMBER
163 */
164inline size_t
165sizeOfVarNumber(uint64_t varNumber);
166
167/**
168 * @brief Write VAR-NUMBER to the specified stream
169 */
170inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700171writeVarNumber(std::ostream& os, uint64_t varNumber);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800172
173/**
174 * @brief Read nonNegativeInteger in NDN-TLV encoding
175 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600176 * This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800177 *
178 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
179 *
180 * How many bytes will be read is directly controlled by the size parameter, which can be either
181 * 1, 2, 4, or 8. If the value of size is different, then an exception will be thrown.
182 */
183template<class InputIterator>
184inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700185readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800186
187/**
188 * @brief Get number of bytes necessary to hold value of nonNegativeInteger
189 */
190inline size_t
191sizeOfNonNegativeInteger(uint64_t varNumber);
192
193/**
194 * @brief Write nonNegativeInteger to the specified stream
195 */
196inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700197writeNonNegativeInteger(std::ostream& os, uint64_t varNumber);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800198
199/////////////////////////////////////////////////////////////////////////////////
200/////////////////////////////////////////////////////////////////////////////////
201/////////////////////////////////////////////////////////////////////////////////
202
203// Inline implementations
204
205/////////////////////////////////////////////////////////////////////////////////
206/////////////////////////////////////////////////////////////////////////////////
207/////////////////////////////////////////////////////////////////////////////////
208
209template<class InputIterator>
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700210inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700211readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700212{
213 if (begin == end)
214 return false;
215
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700216 uint8_t firstOctet = *begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700217 ++begin;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700218 if (firstOctet < 253)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700219 {
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700220 number = firstOctet;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700221 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700222 else if (firstOctet == 253)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700223 {
224 if (end - begin < 2)
225 return false;
226
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700227 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700228 begin += 2;
229 number = be16toh(value);
230 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700231 else if (firstOctet == 254)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700232 {
233 if (end - begin < 4)
234 return false;
235
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700236 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700237 begin += 4;
238 number = be32toh(value);
239 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700240 else // if (firstOctet == 255)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700241 {
242 if (end - begin < 8)
243 return false;
244
245 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
246 begin += 8;
247
248 number = be64toh(value);
249 }
250
251 return true;
252}
253
254template<class InputIterator>
255inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700256readType(InputIterator& begin, const InputIterator& end, uint32_t& type)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700257{
Mickey Sweatt632e0572014-04-20 00:36:32 -0700258 uint64_t number = 0;
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700259 bool isOk = readVarNumber(begin, end, number);
260 if (!isOk || number > std::numeric_limits<uint32_t>::max())
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700261 {
262 return false;
263 }
264
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700265 type = static_cast<uint64_t>(number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700266 return true;
267}
268
269template<class InputIterator>
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800270inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700271readVarNumber(InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800272{
273 if (begin == end)
274 throw Error("Empty buffer during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700275
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700276 uint64_t value;
277 bool isOk = readVarNumber(begin, end, value);
278 if (!isOk)
279 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700280
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700281 return value;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800282}
283
Yingdi Yu27158392014-01-20 13:04:20 -0800284template<>
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700285inline bool
Junxiao Shi468abc32014-11-04 09:12:47 -0700286readVarNumber<std::istream_iterator<uint8_t>>(std::istream_iterator<uint8_t>& begin,
287 const std::istream_iterator<uint8_t>& end,
288 uint64_t& value)
Yingdi Yu27158392014-01-20 13:04:20 -0800289{
290 if (begin == end)
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700291 return false;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700292
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700293 uint8_t firstOctet = *begin;
Yingdi Yu27158392014-01-20 13:04:20 -0800294 ++begin;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700295 if (firstOctet < 253)
Yingdi Yu27158392014-01-20 13:04:20 -0800296 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700297 value = firstOctet;
Yingdi Yu27158392014-01-20 13:04:20 -0800298 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700299 else if (firstOctet == 253)
Yingdi Yu27158392014-01-20 13:04:20 -0800300 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700301 value = 0;
302 size_t count = 0;
303 for (; begin != end && count < 2; ++count)
304 {
305 value = ((value << 8) | *begin);
306 begin++;
307 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700308
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700309 if (count != 2)
310 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800311 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700312 else if (firstOctet == 254)
Yingdi Yu27158392014-01-20 13:04:20 -0800313 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700314 value = 0;
315 size_t count = 0;
316 for (; begin != end && count < 4; ++count)
317 {
318 value = ((value << 8) | *begin);
319 begin++;
320 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700321
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700322 if (count != 4)
323 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800324 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700325 else // if (firstOctet == 255)
Yingdi Yu27158392014-01-20 13:04:20 -0800326 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700327 value = 0;
328 size_t count = 0;
329 for (; begin != end && count < 8; ++count)
330 {
331 value = ((value << 8) | *begin);
332 begin++;
333 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700334
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700335 if (count != 8)
336 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800337 }
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700338
339 return true;
Yingdi Yu27158392014-01-20 13:04:20 -0800340}
341
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800342template<class InputIterator>
343inline uint32_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700344readType(InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800345{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700346 uint64_t type = readVarNumber(begin, end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800347 if (type > std::numeric_limits<uint32_t>::max())
348 {
349 throw Error("TLV type code exceeds allowed maximum");
350 }
351
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700352 return static_cast<uint32_t>(type);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800353}
354
355size_t
356sizeOfVarNumber(uint64_t varNumber)
357{
358 if (varNumber < 253) {
359 return 1;
360 }
361 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
362 return 3;
363 }
364 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
365 return 5;
366 }
367 else {
368 return 9;
369 }
370}
371
372inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700373writeVarNumber(std::ostream& os, uint64_t varNumber)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800374{
375 if (varNumber < 253) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200376 os.put(static_cast<char>(varNumber));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800377 return 1;
378 }
379 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200380 os.put(static_cast<char>(253));
381 uint16_t value = htobe16(static_cast<uint16_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700382 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800383 return 3;
384 }
385 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200386 os.put(static_cast<char>(254));
387 uint32_t value = htobe32(static_cast<uint32_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700388 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800389 return 5;
390 }
391 else {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200392 os.put(static_cast<char>(255));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800393 uint64_t value = htobe64(varNumber);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700394 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800395 return 9;
396 }
397}
398
399template<class InputIterator>
400inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700401readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800402{
403 switch (size) {
404 case 1:
405 {
406 if (end - begin < 1)
407 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700408
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800409 uint8_t value = *begin;
410 begin++;
411 return value;
412 }
413 case 2:
414 {
415 if (end - begin < 2)
416 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700417
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700418 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800419 begin += 2;
420 return be16toh(value);
421 }
422 case 4:
423 {
424 if (end - begin < 4)
425 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700426
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700427 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800428 begin += 4;
429 return be32toh(value);
430 }
431 case 8:
432 {
433 if (end - begin < 8)
434 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700435
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800436 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
437 begin += 8;
438 return be64toh(value);
439 }
440 }
441 throw Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)");
442}
443
Yingdi Yu27158392014-01-20 13:04:20 -0800444template<>
445inline uint64_t
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700446readNonNegativeInteger<std::istream_iterator<uint8_t> >(size_t size,
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700447 std::istream_iterator<uint8_t>& begin,
448 const std::istream_iterator<uint8_t>& end)
Yingdi Yu27158392014-01-20 13:04:20 -0800449{
450 switch (size) {
451 case 1:
452 {
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700453 if (begin == end)
Yingdi Yu27158392014-01-20 13:04:20 -0800454 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700455
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700456 uint64_t value = *begin;
Yingdi Yu27158392014-01-20 13:04:20 -0800457 begin++;
458 return value;
459 }
460 case 2:
461 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700462 uint64_t value = 0;
463 size_t count = 0;
464 for (; begin != end && count < 2; ++count)
465 {
466 value = ((value << 8) | *begin);
467 begin++;
468 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700469
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700470 if (count != 2)
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 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800474 }
475 case 4:
476 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700477 uint64_t value = 0;
478 size_t count = 0;
479 for (; begin != end && count < 4; ++count)
480 {
481 value = ((value << 8) | *begin);
482 begin++;
483 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700484
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700485 if (count != 4)
Yingdi Yu27158392014-01-20 13:04:20 -0800486 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700487
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700488 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800489 }
490 case 8:
491 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700492 uint64_t value = 0;
493 size_t count = 0;
494 for (; begin != end && count < 8; ++count)
495 {
496 value = ((value << 8) | *begin);
497 begin++;
498 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700499
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700500 if (count != 8)
Yingdi Yu27158392014-01-20 13:04:20 -0800501 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700502
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700503 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800504 }
505 }
506 throw Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)");
507}
508
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800509inline size_t
510sizeOfNonNegativeInteger(uint64_t varNumber)
511{
512 if (varNumber < 253) {
513 return 1;
514 }
515 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
516 return 2;
517 }
518 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
519 return 4;
520 }
521 else {
522 return 8;
523 }
524}
525
526
527inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700528writeNonNegativeInteger(std::ostream& os, uint64_t varNumber)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800529{
530 if (varNumber < 253) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200531 os.put(static_cast<char>(varNumber));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800532 return 1;
533 }
534 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200535 uint16_t value = htobe16(static_cast<uint16_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700536 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800537 return 2;
538 }
539 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200540 uint32_t value = htobe32(static_cast<uint32_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700541 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800542 return 4;
543 }
544 else {
545 uint64_t value = htobe64(varNumber);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700546 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800547 return 8;
548 }
549}
550
551
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600552} // namespace tlv
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800553} // namespace ndn
554
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700555#endif // NDN_ENCODING_TLV_HPP