blob: d74323b04e5b552a1d0676c81f3dfbb6fe8e3197 [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
35/**
36 * @brief Namespace defining NDN-TLV related constants and procedures
37 */
Steve DiBenedetto54ce6682014-07-22 13:22:57 -060038namespace tlv {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080039
Alexander Afanasyeva465e972014-03-22 17:21:49 -070040class Error : public std::runtime_error
41{
42public:
43 explicit
44 Error(const std::string& what)
45 : std::runtime_error(what)
46 {
47 }
48};
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080049
50enum {
Alexander Afanasyev4b456282014-02-13 00:34:34 -080051 Interest = 5,
52 Data = 6,
53 Name = 7,
54 NameComponent = 8,
55 Selectors = 9,
56 Nonce = 10,
Alexander Afanasyeva465e972014-03-22 17:21:49 -070057 Scope = 11, // deprecated
Alexander Afanasyev4b456282014-02-13 00:34:34 -080058 InterestLifetime = 12,
59 MinSuffixComponents = 13,
60 MaxSuffixComponents = 14,
61 PublisherPublicKeyLocator = 15,
62 Exclude = 16,
63 ChildSelector = 17,
64 MustBeFresh = 18,
65 Any = 19,
66 MetaInfo = 20,
67 Content = 21,
68 SignatureInfo = 22,
69 SignatureValue = 23,
70 ContentType = 24,
71 FreshnessPeriod = 25,
72 FinalBlockId = 26,
73 SignatureType = 27,
74 KeyLocator = 28,
Junxiao Shibc5030d2014-09-01 11:53:12 -070075 KeyDigest = 29,
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080076
77 AppPrivateBlock1 = 128,
78 AppPrivateBlock2 = 32767
79};
80
Yingdi Yuebfa4cb2014-06-17 15:28:53 -070081enum SignatureTypeValue {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080082 DigestSha256 = 0,
Yingdi Yuebfa4cb2014-06-17 15:28:53 -070083 SignatureSha256WithRsa = 1,
84 SignatureSha256WithEcdsa = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080085};
86
Yingdi Yuebfa4cb2014-06-17 15:28:53 -070087enum ContentTypeValue {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080088 ContentType_Default = 0,
89 ContentType_Link = 1,
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -070090 ContentType_Key = 2
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080091};
92
Yingdi Yuebfa4cb2014-06-17 15:28:53 -070093/// @deprecated use ContentType instead
94typedef ContentTypeValue ConentType;
95
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080096/**
97 * @brief Read VAR-NUMBER in NDN-TLV encoding
98 *
Alexander Afanasyev937aa782014-03-21 13:17:57 -070099 * @param [in] begin Begin (pointer or iterator) of the buffer
100 * @param [in] end End (pointer or iterator) of the buffer
101 * @param [out] number Read number
102 *
103 * @throws This call never throws exception
104 *
105 * @return true if number successfully read from input, false otherwise
106 */
107template<class InputIterator>
108inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700109readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700110
111/**
112 * @brief Read TLV Type
113 *
114 * @param [in] begin Begin (pointer or iterator) of the buffer
115 * @param [in] end End (pointer or iterator) of the buffer
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700116 * @param [out] type Read type number
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700117 *
118 * @throws This call never throws exception
119 *
120 * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
121 * is larger than 2^32-1 (type in this library is implemented as uint32_t)
122 */
123template<class InputIterator>
124inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700125readType(InputIterator& begin, const InputIterator& end, uint32_t& type);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700126
127
128/**
129 * @brief Read VAR-NUMBER in NDN-TLV encoding
130 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600131 * @throws This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800132 *
133 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
134 */
135template<class InputIterator>
136inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700137readVarNumber(InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800138
139/**
140 * @brief Read TLV Type
141 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600142 * @throws This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700143 *
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800144 * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
145 * is larger than 2^32-1 (type in this library is implemented as uint32_t)
146 */
147template<class InputIterator>
148inline uint32_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700149readType(InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800150
151/**
152 * @brief Get number of bytes necessary to hold value of VAR-NUMBER
153 */
154inline size_t
155sizeOfVarNumber(uint64_t varNumber);
156
157/**
158 * @brief Write VAR-NUMBER to the specified stream
159 */
160inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700161writeVarNumber(std::ostream& os, uint64_t varNumber);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800162
163/**
164 * @brief Read nonNegativeInteger in NDN-TLV encoding
165 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600166 * This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800167 *
168 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
169 *
170 * How many bytes will be read is directly controlled by the size parameter, which can be either
171 * 1, 2, 4, or 8. If the value of size is different, then an exception will be thrown.
172 */
173template<class InputIterator>
174inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700175readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800176
177/**
178 * @brief Get number of bytes necessary to hold value of nonNegativeInteger
179 */
180inline size_t
181sizeOfNonNegativeInteger(uint64_t varNumber);
182
183/**
184 * @brief Write nonNegativeInteger to the specified stream
185 */
186inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700187writeNonNegativeInteger(std::ostream& os, uint64_t varNumber);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800188
189/////////////////////////////////////////////////////////////////////////////////
190/////////////////////////////////////////////////////////////////////////////////
191/////////////////////////////////////////////////////////////////////////////////
192
193// Inline implementations
194
195/////////////////////////////////////////////////////////////////////////////////
196/////////////////////////////////////////////////////////////////////////////////
197/////////////////////////////////////////////////////////////////////////////////
198
199template<class InputIterator>
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700200inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700201readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700202{
203 if (begin == end)
204 return false;
205
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700206 uint8_t firstOctet = *begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700207 ++begin;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700208 if (firstOctet < 253)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700209 {
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700210 number = firstOctet;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700211 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700212 else if (firstOctet == 253)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700213 {
214 if (end - begin < 2)
215 return false;
216
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700217 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700218 begin += 2;
219 number = be16toh(value);
220 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700221 else if (firstOctet == 254)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700222 {
223 if (end - begin < 4)
224 return false;
225
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700226 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700227 begin += 4;
228 number = be32toh(value);
229 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700230 else // if (firstOctet == 255)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700231 {
232 if (end - begin < 8)
233 return false;
234
235 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
236 begin += 8;
237
238 number = be64toh(value);
239 }
240
241 return true;
242}
243
244template<class InputIterator>
245inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700246readType(InputIterator& begin, const InputIterator& end, uint32_t& type)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700247{
Mickey Sweatt632e0572014-04-20 00:36:32 -0700248 uint64_t number = 0;
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700249 bool isOk = readVarNumber(begin, end, number);
250 if (!isOk || number > std::numeric_limits<uint32_t>::max())
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700251 {
252 return false;
253 }
254
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700255 type = static_cast<uint64_t>(number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700256 return true;
257}
258
259template<class InputIterator>
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800260inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700261readVarNumber(InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800262{
263 if (begin == end)
264 throw Error("Empty buffer during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700265
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700266 uint64_t value;
267 bool isOk = readVarNumber(begin, end, value);
268 if (!isOk)
269 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700270
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700271 return value;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800272}
273
Yingdi Yu27158392014-01-20 13:04:20 -0800274template<>
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700275inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700276readVarNumber<std::istream_iterator<uint8_t> >(std::istream_iterator<uint8_t>& begin,
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700277 const std::istream_iterator<uint8_t>& end,
278 uint64_t& value)
Yingdi Yu27158392014-01-20 13:04:20 -0800279{
280 if (begin == end)
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700281 return false;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700282
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700283 uint8_t firstOctet = *begin;
Yingdi Yu27158392014-01-20 13:04:20 -0800284 ++begin;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700285 if (firstOctet < 253)
Yingdi Yu27158392014-01-20 13:04:20 -0800286 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700287 value = firstOctet;
Yingdi Yu27158392014-01-20 13:04:20 -0800288 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700289 else if (firstOctet == 253)
Yingdi Yu27158392014-01-20 13:04:20 -0800290 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700291 value = 0;
292 size_t count = 0;
293 for (; begin != end && count < 2; ++count)
294 {
295 value = ((value << 8) | *begin);
296 begin++;
297 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700298
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700299 if (count != 2)
300 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800301 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700302 else if (firstOctet == 254)
Yingdi Yu27158392014-01-20 13:04:20 -0800303 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700304 value = 0;
305 size_t count = 0;
306 for (; begin != end && count < 4; ++count)
307 {
308 value = ((value << 8) | *begin);
309 begin++;
310 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700311
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700312 if (count != 4)
313 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800314 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700315 else // if (firstOctet == 255)
Yingdi Yu27158392014-01-20 13:04:20 -0800316 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700317 value = 0;
318 size_t count = 0;
319 for (; begin != end && count < 8; ++count)
320 {
321 value = ((value << 8) | *begin);
322 begin++;
323 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700324
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700325 if (count != 8)
326 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800327 }
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700328
329 return true;
Yingdi Yu27158392014-01-20 13:04:20 -0800330}
331
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800332template<class InputIterator>
333inline uint32_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700334readType(InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800335{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700336 uint64_t type = readVarNumber(begin, end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800337 if (type > std::numeric_limits<uint32_t>::max())
338 {
339 throw Error("TLV type code exceeds allowed maximum");
340 }
341
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700342 return static_cast<uint32_t>(type);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800343}
344
345size_t
346sizeOfVarNumber(uint64_t varNumber)
347{
348 if (varNumber < 253) {
349 return 1;
350 }
351 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
352 return 3;
353 }
354 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
355 return 5;
356 }
357 else {
358 return 9;
359 }
360}
361
362inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700363writeVarNumber(std::ostream& os, uint64_t varNumber)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800364{
365 if (varNumber < 253) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200366 os.put(static_cast<char>(varNumber));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800367 return 1;
368 }
369 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200370 os.put(static_cast<char>(253));
371 uint16_t value = htobe16(static_cast<uint16_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700372 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800373 return 3;
374 }
375 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200376 os.put(static_cast<char>(254));
377 uint32_t value = htobe32(static_cast<uint32_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700378 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800379 return 5;
380 }
381 else {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200382 os.put(static_cast<char>(255));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800383 uint64_t value = htobe64(varNumber);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700384 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800385 return 9;
386 }
387}
388
389template<class InputIterator>
390inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700391readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800392{
393 switch (size) {
394 case 1:
395 {
396 if (end - begin < 1)
397 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700398
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800399 uint8_t value = *begin;
400 begin++;
401 return value;
402 }
403 case 2:
404 {
405 if (end - begin < 2)
406 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700407
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700408 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800409 begin += 2;
410 return be16toh(value);
411 }
412 case 4:
413 {
414 if (end - begin < 4)
415 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700416
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700417 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800418 begin += 4;
419 return be32toh(value);
420 }
421 case 8:
422 {
423 if (end - begin < 8)
424 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700425
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800426 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
427 begin += 8;
428 return be64toh(value);
429 }
430 }
431 throw Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)");
432}
433
Yingdi Yu27158392014-01-20 13:04:20 -0800434template<>
435inline uint64_t
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700436readNonNegativeInteger<std::istream_iterator<uint8_t> >(size_t size,
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700437 std::istream_iterator<uint8_t>& begin,
438 const std::istream_iterator<uint8_t>& end)
Yingdi Yu27158392014-01-20 13:04:20 -0800439{
440 switch (size) {
441 case 1:
442 {
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700443 if (begin == end)
Yingdi Yu27158392014-01-20 13:04:20 -0800444 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700445
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700446 uint64_t value = *begin;
Yingdi Yu27158392014-01-20 13:04:20 -0800447 begin++;
448 return value;
449 }
450 case 2:
451 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700452 uint64_t value = 0;
453 size_t count = 0;
454 for (; begin != end && count < 2; ++count)
455 {
456 value = ((value << 8) | *begin);
457 begin++;
458 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700459
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700460 if (count != 2)
Yingdi Yu27158392014-01-20 13:04:20 -0800461 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700462
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700463 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800464 }
465 case 4:
466 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700467 uint64_t value = 0;
468 size_t count = 0;
469 for (; begin != end && count < 4; ++count)
470 {
471 value = ((value << 8) | *begin);
472 begin++;
473 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700474
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700475 if (count != 4)
Yingdi Yu27158392014-01-20 13:04:20 -0800476 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700477
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700478 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800479 }
480 case 8:
481 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700482 uint64_t value = 0;
483 size_t count = 0;
484 for (; begin != end && count < 8; ++count)
485 {
486 value = ((value << 8) | *begin);
487 begin++;
488 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700489
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700490 if (count != 8)
Yingdi Yu27158392014-01-20 13:04:20 -0800491 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700492
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700493 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800494 }
495 }
496 throw Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)");
497}
498
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800499inline size_t
500sizeOfNonNegativeInteger(uint64_t varNumber)
501{
502 if (varNumber < 253) {
503 return 1;
504 }
505 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
506 return 2;
507 }
508 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
509 return 4;
510 }
511 else {
512 return 8;
513 }
514}
515
516
517inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700518writeNonNegativeInteger(std::ostream& os, uint64_t varNumber)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800519{
520 if (varNumber < 253) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200521 os.put(static_cast<char>(varNumber));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800522 return 1;
523 }
524 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200525 uint16_t value = htobe16(static_cast<uint16_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700526 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800527 return 2;
528 }
529 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200530 uint32_t value = htobe32(static_cast<uint32_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700531 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800532 return 4;
533 }
534 else {
535 uint64_t value = htobe64(varNumber);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700536 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800537 return 8;
538 }
539}
540
541
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600542} // namespace tlv
543
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800544} // namespace ndn
545
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700546#endif // NDN_ENCODING_TLV_HPP