blob: bb0f1c5459ad92d2339b5211a8f52a0ed5a84772 [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
103/**
104 * @brief Read VAR-NUMBER in NDN-TLV encoding
105 *
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700106 * @param [in] begin Begin (pointer or iterator) of the buffer
107 * @param [in] end End (pointer or iterator) of the buffer
108 * @param [out] number Read number
109 *
110 * @throws This call never throws exception
111 *
112 * @return true if number successfully read from input, false otherwise
113 */
114template<class InputIterator>
115inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700116readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700117
118/**
119 * @brief Read TLV Type
120 *
121 * @param [in] begin Begin (pointer or iterator) of the buffer
122 * @param [in] end End (pointer or iterator) of the buffer
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700123 * @param [out] type Read type number
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700124 *
125 * @throws This call never throws exception
126 *
127 * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
128 * is larger than 2^32-1 (type in this library is implemented as uint32_t)
129 */
130template<class InputIterator>
131inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700132readType(InputIterator& begin, const InputIterator& end, uint32_t& type);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700133
134
135/**
136 * @brief Read VAR-NUMBER in NDN-TLV encoding
137 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600138 * @throws This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800139 *
140 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
141 */
142template<class InputIterator>
143inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700144readVarNumber(InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800145
146/**
147 * @brief Read TLV Type
148 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600149 * @throws This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700150 *
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800151 * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
152 * is larger than 2^32-1 (type in this library is implemented as uint32_t)
153 */
154template<class InputIterator>
155inline uint32_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700156readType(InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800157
158/**
159 * @brief Get number of bytes necessary to hold value of VAR-NUMBER
160 */
161inline size_t
162sizeOfVarNumber(uint64_t varNumber);
163
164/**
165 * @brief Write VAR-NUMBER to the specified stream
166 */
167inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700168writeVarNumber(std::ostream& os, uint64_t varNumber);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800169
170/**
171 * @brief Read nonNegativeInteger in NDN-TLV encoding
172 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600173 * This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800174 *
175 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
176 *
177 * How many bytes will be read is directly controlled by the size parameter, which can be either
178 * 1, 2, 4, or 8. If the value of size is different, then an exception will be thrown.
179 */
180template<class InputIterator>
181inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700182readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800183
184/**
185 * @brief Get number of bytes necessary to hold value of nonNegativeInteger
186 */
187inline size_t
188sizeOfNonNegativeInteger(uint64_t varNumber);
189
190/**
191 * @brief Write nonNegativeInteger to the specified stream
192 */
193inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700194writeNonNegativeInteger(std::ostream& os, uint64_t varNumber);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800195
196/////////////////////////////////////////////////////////////////////////////////
197/////////////////////////////////////////////////////////////////////////////////
198/////////////////////////////////////////////////////////////////////////////////
199
200// Inline implementations
201
202/////////////////////////////////////////////////////////////////////////////////
203/////////////////////////////////////////////////////////////////////////////////
204/////////////////////////////////////////////////////////////////////////////////
205
206template<class InputIterator>
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700207inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700208readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700209{
210 if (begin == end)
211 return false;
212
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700213 uint8_t firstOctet = *begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700214 ++begin;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700215 if (firstOctet < 253)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700216 {
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700217 number = firstOctet;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700218 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700219 else if (firstOctet == 253)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700220 {
221 if (end - begin < 2)
222 return false;
223
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700224 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700225 begin += 2;
226 number = be16toh(value);
227 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700228 else if (firstOctet == 254)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700229 {
230 if (end - begin < 4)
231 return false;
232
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700233 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700234 begin += 4;
235 number = be32toh(value);
236 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700237 else // if (firstOctet == 255)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700238 {
239 if (end - begin < 8)
240 return false;
241
242 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
243 begin += 8;
244
245 number = be64toh(value);
246 }
247
248 return true;
249}
250
251template<class InputIterator>
252inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700253readType(InputIterator& begin, const InputIterator& end, uint32_t& type)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700254{
Mickey Sweatt632e0572014-04-20 00:36:32 -0700255 uint64_t number = 0;
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700256 bool isOk = readVarNumber(begin, end, number);
257 if (!isOk || number > std::numeric_limits<uint32_t>::max())
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700258 {
259 return false;
260 }
261
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700262 type = static_cast<uint64_t>(number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700263 return true;
264}
265
266template<class InputIterator>
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800267inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700268readVarNumber(InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800269{
270 if (begin == end)
271 throw Error("Empty buffer during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700272
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700273 uint64_t value;
274 bool isOk = readVarNumber(begin, end, value);
275 if (!isOk)
276 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700277
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700278 return value;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800279}
280
Yingdi Yu27158392014-01-20 13:04:20 -0800281template<>
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700282inline bool
Junxiao Shi468abc32014-11-04 09:12:47 -0700283readVarNumber<std::istream_iterator<uint8_t>>(std::istream_iterator<uint8_t>& begin,
284 const std::istream_iterator<uint8_t>& end,
285 uint64_t& value)
Yingdi Yu27158392014-01-20 13:04:20 -0800286{
287 if (begin == end)
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700288 return false;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700289
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700290 uint8_t firstOctet = *begin;
Yingdi Yu27158392014-01-20 13:04:20 -0800291 ++begin;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700292 if (firstOctet < 253)
Yingdi Yu27158392014-01-20 13:04:20 -0800293 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700294 value = firstOctet;
Yingdi Yu27158392014-01-20 13:04:20 -0800295 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700296 else if (firstOctet == 253)
Yingdi Yu27158392014-01-20 13:04:20 -0800297 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700298 value = 0;
299 size_t count = 0;
300 for (; begin != end && count < 2; ++count)
301 {
302 value = ((value << 8) | *begin);
303 begin++;
304 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700305
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700306 if (count != 2)
307 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800308 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700309 else if (firstOctet == 254)
Yingdi Yu27158392014-01-20 13:04:20 -0800310 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700311 value = 0;
312 size_t count = 0;
313 for (; begin != end && count < 4; ++count)
314 {
315 value = ((value << 8) | *begin);
316 begin++;
317 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700318
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700319 if (count != 4)
320 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800321 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700322 else // if (firstOctet == 255)
Yingdi Yu27158392014-01-20 13:04:20 -0800323 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700324 value = 0;
325 size_t count = 0;
326 for (; begin != end && count < 8; ++count)
327 {
328 value = ((value << 8) | *begin);
329 begin++;
330 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700331
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700332 if (count != 8)
333 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800334 }
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700335
336 return true;
Yingdi Yu27158392014-01-20 13:04:20 -0800337}
338
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800339template<class InputIterator>
340inline uint32_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700341readType(InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800342{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700343 uint64_t type = readVarNumber(begin, end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800344 if (type > std::numeric_limits<uint32_t>::max())
345 {
346 throw Error("TLV type code exceeds allowed maximum");
347 }
348
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700349 return static_cast<uint32_t>(type);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800350}
351
352size_t
353sizeOfVarNumber(uint64_t varNumber)
354{
355 if (varNumber < 253) {
356 return 1;
357 }
358 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
359 return 3;
360 }
361 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
362 return 5;
363 }
364 else {
365 return 9;
366 }
367}
368
369inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700370writeVarNumber(std::ostream& os, uint64_t varNumber)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800371{
372 if (varNumber < 253) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200373 os.put(static_cast<char>(varNumber));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800374 return 1;
375 }
376 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200377 os.put(static_cast<char>(253));
378 uint16_t value = htobe16(static_cast<uint16_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700379 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800380 return 3;
381 }
382 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200383 os.put(static_cast<char>(254));
384 uint32_t value = htobe32(static_cast<uint32_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700385 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800386 return 5;
387 }
388 else {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200389 os.put(static_cast<char>(255));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800390 uint64_t value = htobe64(varNumber);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700391 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800392 return 9;
393 }
394}
395
396template<class InputIterator>
397inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700398readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800399{
400 switch (size) {
401 case 1:
402 {
403 if (end - begin < 1)
404 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700405
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800406 uint8_t value = *begin;
407 begin++;
408 return value;
409 }
410 case 2:
411 {
412 if (end - begin < 2)
413 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700414
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700415 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800416 begin += 2;
417 return be16toh(value);
418 }
419 case 4:
420 {
421 if (end - begin < 4)
422 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700423
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700424 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800425 begin += 4;
426 return be32toh(value);
427 }
428 case 8:
429 {
430 if (end - begin < 8)
431 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700432
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800433 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
434 begin += 8;
435 return be64toh(value);
436 }
437 }
438 throw Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)");
439}
440
Yingdi Yu27158392014-01-20 13:04:20 -0800441template<>
442inline uint64_t
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700443readNonNegativeInteger<std::istream_iterator<uint8_t> >(size_t size,
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700444 std::istream_iterator<uint8_t>& begin,
445 const std::istream_iterator<uint8_t>& end)
Yingdi Yu27158392014-01-20 13:04:20 -0800446{
447 switch (size) {
448 case 1:
449 {
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700450 if (begin == end)
Yingdi Yu27158392014-01-20 13:04:20 -0800451 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700452
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700453 uint64_t value = *begin;
Yingdi Yu27158392014-01-20 13:04:20 -0800454 begin++;
455 return value;
456 }
457 case 2:
458 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700459 uint64_t value = 0;
460 size_t count = 0;
461 for (; begin != end && count < 2; ++count)
462 {
463 value = ((value << 8) | *begin);
464 begin++;
465 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700466
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700467 if (count != 2)
Yingdi Yu27158392014-01-20 13:04:20 -0800468 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700469
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700470 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800471 }
472 case 4:
473 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700474 uint64_t value = 0;
475 size_t count = 0;
476 for (; begin != end && count < 4; ++count)
477 {
478 value = ((value << 8) | *begin);
479 begin++;
480 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700481
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700482 if (count != 4)
Yingdi Yu27158392014-01-20 13:04:20 -0800483 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700484
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700485 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800486 }
487 case 8:
488 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700489 uint64_t value = 0;
490 size_t count = 0;
491 for (; begin != end && count < 8; ++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 != 8)
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 }
503 throw Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)");
504}
505
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800506inline size_t
507sizeOfNonNegativeInteger(uint64_t varNumber)
508{
509 if (varNumber < 253) {
510 return 1;
511 }
512 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
513 return 2;
514 }
515 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
516 return 4;
517 }
518 else {
519 return 8;
520 }
521}
522
523
524inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700525writeNonNegativeInteger(std::ostream& os, uint64_t varNumber)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800526{
527 if (varNumber < 253) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200528 os.put(static_cast<char>(varNumber));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800529 return 1;
530 }
531 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200532 uint16_t value = htobe16(static_cast<uint16_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700533 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800534 return 2;
535 }
536 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200537 uint32_t value = htobe32(static_cast<uint32_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700538 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800539 return 4;
540 }
541 else {
542 uint64_t value = htobe64(varNumber);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700543 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800544 return 8;
545 }
546}
547
548
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600549} // namespace tlv
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800550} // namespace ndn
551
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700552#endif // NDN_ENCODING_TLV_HPP