blob: 9d70ee6e39648d6bdc620d5fa308bb96771eba1b [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>
Yingdi Yu27158392014-01-20 13:04:20 -080026#include <iterator>
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080027#include "buffer.hpp"
Alexander Afanasyev200dd6f2014-01-28 19:04:25 -080028#include "endian.hpp"
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080029
30namespace ndn {
31
32/**
33 * @brief Namespace defining NDN-TLV related constants and procedures
34 */
35namespace Tlv {
36
Alexander Afanasyeva465e972014-03-22 17:21:49 -070037class Error : public std::runtime_error
38{
39public:
40 explicit
41 Error(const std::string& what)
42 : std::runtime_error(what)
43 {
44 }
45};
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080046
47enum {
Alexander Afanasyev4b456282014-02-13 00:34:34 -080048 Interest = 5,
49 Data = 6,
50 Name = 7,
51 NameComponent = 8,
52 Selectors = 9,
53 Nonce = 10,
Alexander Afanasyeva465e972014-03-22 17:21:49 -070054 Scope = 11, // deprecated
Alexander Afanasyev4b456282014-02-13 00:34:34 -080055 InterestLifetime = 12,
56 MinSuffixComponents = 13,
57 MaxSuffixComponents = 14,
58 PublisherPublicKeyLocator = 15,
59 Exclude = 16,
60 ChildSelector = 17,
61 MustBeFresh = 18,
62 Any = 19,
63 MetaInfo = 20,
64 Content = 21,
65 SignatureInfo = 22,
66 SignatureValue = 23,
67 ContentType = 24,
68 FreshnessPeriod = 25,
69 FinalBlockId = 26,
70 SignatureType = 27,
71 KeyLocator = 28,
72 KeyLocatorDigest = 29,
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080073
74 AppPrivateBlock1 = 128,
75 AppPrivateBlock2 = 32767
76};
77
Yingdi Yuebfa4cb2014-06-17 15:28:53 -070078enum SignatureTypeValue {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080079 DigestSha256 = 0,
Yingdi Yuebfa4cb2014-06-17 15:28:53 -070080 SignatureSha256WithRsa = 1,
81 SignatureSha256WithEcdsa = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080082};
83
Yingdi Yuebfa4cb2014-06-17 15:28:53 -070084enum ContentTypeValue {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080085 ContentType_Default = 0,
86 ContentType_Link = 1,
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -070087 ContentType_Key = 2
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080088};
89
Yingdi Yuebfa4cb2014-06-17 15:28:53 -070090/// @deprecated use ContentType instead
91typedef ContentTypeValue ConentType;
92
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080093/**
94 * @brief Read VAR-NUMBER in NDN-TLV encoding
95 *
Alexander Afanasyev937aa782014-03-21 13:17:57 -070096 * @param [in] begin Begin (pointer or iterator) of the buffer
97 * @param [in] end End (pointer or iterator) of the buffer
98 * @param [out] number Read number
99 *
100 * @throws This call never throws exception
101 *
102 * @return true if number successfully read from input, false otherwise
103 */
104template<class InputIterator>
105inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700106readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700107
108/**
109 * @brief Read TLV Type
110 *
111 * @param [in] begin Begin (pointer or iterator) of the buffer
112 * @param [in] end End (pointer or iterator) of the buffer
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700113 * @param [out] type Read type number
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700114 *
115 * @throws This call never throws exception
116 *
117 * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
118 * is larger than 2^32-1 (type in this library is implemented as uint32_t)
119 */
120template<class InputIterator>
121inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700122readType(InputIterator& begin, const InputIterator& end, uint32_t& type);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700123
124
125/**
126 * @brief Read VAR-NUMBER in NDN-TLV encoding
127 *
128 * @throws This call will throw ndn::Tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800129 *
130 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
131 */
132template<class InputIterator>
133inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700134readVarNumber(InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800135
136/**
137 * @brief Read TLV Type
138 *
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700139 * @throws This call will throw ndn::Tlv::Error (aka std::runtime_error) if number cannot be read
140 *
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800141 * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
142 * is larger than 2^32-1 (type in this library is implemented as uint32_t)
143 */
144template<class InputIterator>
145inline uint32_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700146readType(InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800147
148/**
149 * @brief Get number of bytes necessary to hold value of VAR-NUMBER
150 */
151inline size_t
152sizeOfVarNumber(uint64_t varNumber);
153
154/**
155 * @brief Write VAR-NUMBER to the specified stream
156 */
157inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700158writeVarNumber(std::ostream& os, uint64_t varNumber);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800159
160/**
161 * @brief Read nonNegativeInteger in NDN-TLV encoding
162 *
163 * This call will throw ndn::Tlv::Error (aka std::runtime_error) if number cannot be read
164 *
165 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
166 *
167 * How many bytes will be read is directly controlled by the size parameter, which can be either
168 * 1, 2, 4, or 8. If the value of size is different, then an exception will be thrown.
169 */
170template<class InputIterator>
171inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700172readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800173
174/**
175 * @brief Get number of bytes necessary to hold value of nonNegativeInteger
176 */
177inline size_t
178sizeOfNonNegativeInteger(uint64_t varNumber);
179
180/**
181 * @brief Write nonNegativeInteger to the specified stream
182 */
183inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700184writeNonNegativeInteger(std::ostream& os, uint64_t varNumber);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800185
186/////////////////////////////////////////////////////////////////////////////////
187/////////////////////////////////////////////////////////////////////////////////
188/////////////////////////////////////////////////////////////////////////////////
189
190// Inline implementations
191
192/////////////////////////////////////////////////////////////////////////////////
193/////////////////////////////////////////////////////////////////////////////////
194/////////////////////////////////////////////////////////////////////////////////
195
196template<class InputIterator>
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700197inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700198readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700199{
200 if (begin == end)
201 return false;
202
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700203 uint8_t firstOctet = *begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700204 ++begin;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700205 if (firstOctet < 253)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700206 {
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700207 number = firstOctet;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700208 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700209 else if (firstOctet == 253)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700210 {
211 if (end - begin < 2)
212 return false;
213
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700214 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700215 begin += 2;
216 number = be16toh(value);
217 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700218 else if (firstOctet == 254)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700219 {
220 if (end - begin < 4)
221 return false;
222
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700223 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700224 begin += 4;
225 number = be32toh(value);
226 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700227 else // if (firstOctet == 255)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700228 {
229 if (end - begin < 8)
230 return false;
231
232 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
233 begin += 8;
234
235 number = be64toh(value);
236 }
237
238 return true;
239}
240
241template<class InputIterator>
242inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700243readType(InputIterator& begin, const InputIterator& end, uint32_t& type)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700244{
Mickey Sweatt632e0572014-04-20 00:36:32 -0700245 uint64_t number = 0;
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700246 bool isOk = readVarNumber(begin, end, number);
247 if (!isOk || number > std::numeric_limits<uint32_t>::max())
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700248 {
249 return false;
250 }
251
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700252 type = static_cast<uint64_t>(number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700253 return true;
254}
255
256template<class InputIterator>
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800257inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700258readVarNumber(InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800259{
260 if (begin == end)
261 throw Error("Empty buffer during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700262
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700263 uint64_t value;
264 bool isOk = readVarNumber(begin, end, value);
265 if (!isOk)
266 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700267
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700268 return value;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800269}
270
Yingdi Yu27158392014-01-20 13:04:20 -0800271template<>
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700272inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700273readVarNumber<std::istream_iterator<uint8_t> >(std::istream_iterator<uint8_t>& begin,
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700274 const std::istream_iterator<uint8_t>& end,
275 uint64_t& value)
Yingdi Yu27158392014-01-20 13:04:20 -0800276{
277 if (begin == end)
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700278 return false;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700279
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700280 uint8_t firstOctet = *begin;
Yingdi Yu27158392014-01-20 13:04:20 -0800281 ++begin;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700282 if (firstOctet < 253)
Yingdi Yu27158392014-01-20 13:04:20 -0800283 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700284 value = firstOctet;
Yingdi Yu27158392014-01-20 13:04:20 -0800285 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700286 else if (firstOctet == 253)
Yingdi Yu27158392014-01-20 13:04:20 -0800287 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700288 value = 0;
289 size_t count = 0;
290 for (; begin != end && count < 2; ++count)
291 {
292 value = ((value << 8) | *begin);
293 begin++;
294 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700295
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700296 if (count != 2)
297 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800298 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700299 else if (firstOctet == 254)
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 < 4; ++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 != 4)
310 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800311 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700312 else // if (firstOctet == 255)
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 < 8; ++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 != 8)
323 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800324 }
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700325
326 return true;
Yingdi Yu27158392014-01-20 13:04:20 -0800327}
328
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800329template<class InputIterator>
330inline uint32_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700331readType(InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800332{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700333 uint64_t type = readVarNumber(begin, end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800334 if (type > std::numeric_limits<uint32_t>::max())
335 {
336 throw Error("TLV type code exceeds allowed maximum");
337 }
338
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700339 return static_cast<uint32_t>(type);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800340}
341
342size_t
343sizeOfVarNumber(uint64_t varNumber)
344{
345 if (varNumber < 253) {
346 return 1;
347 }
348 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
349 return 3;
350 }
351 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
352 return 5;
353 }
354 else {
355 return 9;
356 }
357}
358
359inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700360writeVarNumber(std::ostream& os, uint64_t varNumber)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800361{
362 if (varNumber < 253) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200363 os.put(static_cast<char>(varNumber));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800364 return 1;
365 }
366 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200367 os.put(static_cast<char>(253));
368 uint16_t value = htobe16(static_cast<uint16_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700369 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800370 return 3;
371 }
372 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200373 os.put(static_cast<char>(254));
374 uint32_t value = htobe32(static_cast<uint32_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700375 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800376 return 5;
377 }
378 else {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200379 os.put(static_cast<char>(255));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800380 uint64_t value = htobe64(varNumber);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700381 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800382 return 9;
383 }
384}
385
386template<class InputIterator>
387inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700388readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800389{
390 switch (size) {
391 case 1:
392 {
393 if (end - begin < 1)
394 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700395
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800396 uint8_t value = *begin;
397 begin++;
398 return value;
399 }
400 case 2:
401 {
402 if (end - begin < 2)
403 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700404
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700405 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800406 begin += 2;
407 return be16toh(value);
408 }
409 case 4:
410 {
411 if (end - begin < 4)
412 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700413
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700414 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800415 begin += 4;
416 return be32toh(value);
417 }
418 case 8:
419 {
420 if (end - begin < 8)
421 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700422
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800423 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
424 begin += 8;
425 return be64toh(value);
426 }
427 }
428 throw Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)");
429}
430
Yingdi Yu27158392014-01-20 13:04:20 -0800431template<>
432inline uint64_t
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700433readNonNegativeInteger<std::istream_iterator<uint8_t> >(size_t size,
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700434 std::istream_iterator<uint8_t>& begin,
435 const std::istream_iterator<uint8_t>& end)
Yingdi Yu27158392014-01-20 13:04:20 -0800436{
437 switch (size) {
438 case 1:
439 {
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700440 if (begin == end)
Yingdi Yu27158392014-01-20 13:04:20 -0800441 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700442
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700443 uint64_t value = *begin;
Yingdi Yu27158392014-01-20 13:04:20 -0800444 begin++;
445 return value;
446 }
447 case 2:
448 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700449 uint64_t value = 0;
450 size_t count = 0;
451 for (; begin != end && count < 2; ++count)
452 {
453 value = ((value << 8) | *begin);
454 begin++;
455 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700456
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700457 if (count != 2)
Yingdi Yu27158392014-01-20 13:04:20 -0800458 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700459
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700460 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800461 }
462 case 4:
463 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700464 uint64_t value = 0;
465 size_t count = 0;
466 for (; begin != end && count < 4; ++count)
467 {
468 value = ((value << 8) | *begin);
469 begin++;
470 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700471
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700472 if (count != 4)
Yingdi Yu27158392014-01-20 13:04:20 -0800473 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700474
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700475 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800476 }
477 case 8:
478 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700479 uint64_t value = 0;
480 size_t count = 0;
481 for (; begin != end && count < 8; ++count)
482 {
483 value = ((value << 8) | *begin);
484 begin++;
485 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700486
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700487 if (count != 8)
Yingdi Yu27158392014-01-20 13:04:20 -0800488 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700489
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700490 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800491 }
492 }
493 throw Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)");
494}
495
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800496inline size_t
497sizeOfNonNegativeInteger(uint64_t varNumber)
498{
499 if (varNumber < 253) {
500 return 1;
501 }
502 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
503 return 2;
504 }
505 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
506 return 4;
507 }
508 else {
509 return 8;
510 }
511}
512
513
514inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700515writeNonNegativeInteger(std::ostream& os, uint64_t varNumber)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800516{
517 if (varNumber < 253) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200518 os.put(static_cast<char>(varNumber));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800519 return 1;
520 }
521 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200522 uint16_t value = htobe16(static_cast<uint16_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700523 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800524 return 2;
525 }
526 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200527 uint32_t value = htobe32(static_cast<uint32_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700528 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800529 return 4;
530 }
531 else {
532 uint64_t value = htobe64(varNumber);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700533 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800534 return 8;
535 }
536}
537
538
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700539} // namespace Tlv
540
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800541} // namespace ndn
542
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700543#endif // NDN_ENCODING_TLV_HPP