blob: 9cb1a0f2ebd871174d41f8ea8202d78c3437da6d [file] [log] [blame]
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/*
3 * Copyright (c) 2013, Regents of the University of California
4 *
5 * BSD license, See the LICENSE file for more information
6 *
7 * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
8 */
9
10#ifndef NDN_TLV_HPP
11#define NDN_TLV_HPP
12
Alexander Afanasyev54467af2014-01-06 15:45:32 -080013#include <stdexcept>
Yingdi Yu27158392014-01-20 13:04:20 -080014#include <iterator>
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080015#include "buffer.hpp"
Alexander Afanasyev200dd6f2014-01-28 19:04:25 -080016#include "endian.hpp"
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080017
18namespace ndn {
19
20/**
21 * @brief Namespace defining NDN-TLV related constants and procedures
22 */
23namespace Tlv {
24
Alexander Afanasyeva465e972014-03-22 17:21:49 -070025class Error : public std::runtime_error
26{
27public:
28 explicit
29 Error(const std::string& what)
30 : std::runtime_error(what)
31 {
32 }
33};
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080034
35enum {
Alexander Afanasyev4b456282014-02-13 00:34:34 -080036 Interest = 5,
37 Data = 6,
38 Name = 7,
39 NameComponent = 8,
40 Selectors = 9,
41 Nonce = 10,
Alexander Afanasyeva465e972014-03-22 17:21:49 -070042 Scope = 11, // deprecated
Alexander Afanasyev4b456282014-02-13 00:34:34 -080043 InterestLifetime = 12,
44 MinSuffixComponents = 13,
45 MaxSuffixComponents = 14,
46 PublisherPublicKeyLocator = 15,
47 Exclude = 16,
48 ChildSelector = 17,
49 MustBeFresh = 18,
50 Any = 19,
51 MetaInfo = 20,
52 Content = 21,
53 SignatureInfo = 22,
54 SignatureValue = 23,
55 ContentType = 24,
56 FreshnessPeriod = 25,
57 FinalBlockId = 26,
58 SignatureType = 27,
59 KeyLocator = 28,
60 KeyLocatorDigest = 29,
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080061
62 AppPrivateBlock1 = 128,
63 AppPrivateBlock2 = 32767
64};
65
66enum SignatureType {
67 DigestSha256 = 0,
68 SignatureSha256WithRsa = 1,
69};
70
71enum ConentType {
72 ContentType_Default = 0,
73 ContentType_Link = 1,
74 ContentType_Key = 2,
75};
76
77/**
78 * @brief Read VAR-NUMBER in NDN-TLV encoding
79 *
Alexander Afanasyev937aa782014-03-21 13:17:57 -070080 * @param [in] begin Begin (pointer or iterator) of the buffer
81 * @param [in] end End (pointer or iterator) of the buffer
82 * @param [out] number Read number
83 *
84 * @throws This call never throws exception
85 *
86 * @return true if number successfully read from input, false otherwise
87 */
88template<class InputIterator>
89inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -070090readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -070091
92/**
93 * @brief Read TLV Type
94 *
95 * @param [in] begin Begin (pointer or iterator) of the buffer
96 * @param [in] end End (pointer or iterator) of the buffer
97 * @param [out] number Read type number
98 *
99 * @throws This call never throws exception
100 *
101 * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
102 * is larger than 2^32-1 (type in this library is implemented as uint32_t)
103 */
104template<class InputIterator>
105inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700106readType(InputIterator& begin, const InputIterator& end, uint32_t& type);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700107
108
109/**
110 * @brief Read VAR-NUMBER in NDN-TLV encoding
111 *
112 * @throws This call will throw ndn::Tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800113 *
114 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
115 */
116template<class InputIterator>
117inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700118readVarNumber(InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800119
120/**
121 * @brief Read TLV Type
122 *
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700123 * @throws This call will throw ndn::Tlv::Error (aka std::runtime_error) if number cannot be read
124 *
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800125 * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
126 * is larger than 2^32-1 (type in this library is implemented as uint32_t)
127 */
128template<class InputIterator>
129inline uint32_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700130readType(InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800131
132/**
133 * @brief Get number of bytes necessary to hold value of VAR-NUMBER
134 */
135inline size_t
136sizeOfVarNumber(uint64_t varNumber);
137
138/**
139 * @brief Write VAR-NUMBER to the specified stream
140 */
141inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700142writeVarNumber(std::ostream& os, uint64_t varNumber);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800143
144/**
145 * @brief Read nonNegativeInteger in NDN-TLV encoding
146 *
147 * This call will throw ndn::Tlv::Error (aka std::runtime_error) if number cannot be read
148 *
149 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
150 *
151 * How many bytes will be read is directly controlled by the size parameter, which can be either
152 * 1, 2, 4, or 8. If the value of size is different, then an exception will be thrown.
153 */
154template<class InputIterator>
155inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700156readNonNegativeInteger(size_t size, 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 nonNegativeInteger
160 */
161inline size_t
162sizeOfNonNegativeInteger(uint64_t varNumber);
163
164/**
165 * @brief Write nonNegativeInteger to the specified stream
166 */
167inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700168writeNonNegativeInteger(std::ostream& os, uint64_t varNumber);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800169
170/////////////////////////////////////////////////////////////////////////////////
171/////////////////////////////////////////////////////////////////////////////////
172/////////////////////////////////////////////////////////////////////////////////
173
174// Inline implementations
175
176/////////////////////////////////////////////////////////////////////////////////
177/////////////////////////////////////////////////////////////////////////////////
178/////////////////////////////////////////////////////////////////////////////////
179
180template<class InputIterator>
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700181inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700182readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700183{
184 if (begin == end)
185 return false;
186
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700187 uint8_t firstOctet = *begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700188 ++begin;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700189 if (firstOctet < 253)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700190 {
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700191 number = firstOctet;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700192 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700193 else if (firstOctet == 253)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700194 {
195 if (end - begin < 2)
196 return false;
197
198 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin); // kind of dangerous... but should be efficient
199 begin += 2;
200 number = be16toh(value);
201 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700202 else if (firstOctet == 254)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700203 {
204 if (end - begin < 4)
205 return false;
206
207 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin); // kind of dangerous... but should be efficient
208 begin += 4;
209 number = be32toh(value);
210 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700211 else // if (firstOctet == 255)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700212 {
213 if (end - begin < 8)
214 return false;
215
216 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
217 begin += 8;
218
219 number = be64toh(value);
220 }
221
222 return true;
223}
224
225template<class InputIterator>
226inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700227readType(InputIterator& begin, const InputIterator& end, uint32_t& type)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700228{
229 uint64_t number;
230 bool ok = readVarNumber(begin, end, number);
231 if (number > std::numeric_limits<uint32_t>::max())
232 {
233 return false;
234 }
235
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700236 type = static_cast<uint64_t>(number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700237 return true;
238}
239
240template<class InputIterator>
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800241inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700242readVarNumber(InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800243{
244 if (begin == end)
245 throw Error("Empty buffer during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700246
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700247 uint8_t firstOctet = *begin;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800248 ++begin;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700249 if (firstOctet < 253)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800250 {
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700251 return firstOctet;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800252 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700253 else if (firstOctet == 253)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800254 {
255 if (end - begin < 2)
256 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700257
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800258 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin); // kind of dangerous... but should be efficient
259 begin += 2;
260 return be16toh(value);
261 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700262 else if (firstOctet == 254)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800263 {
264 if (end - begin < 4)
265 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700266
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800267 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin); // kind of dangerous... but should be efficient
268 begin += 4;
269 return be32toh(value);
270 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700271 else // if (firstOctet == 255)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800272 {
273 if (end - begin < 8)
274 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700275
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800276 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
277 begin += 8;
278
279 return be64toh(value);
280 }
281}
282
Yingdi Yu27158392014-01-20 13:04:20 -0800283template<>
284inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700285readVarNumber<std::istream_iterator<uint8_t> >(std::istream_iterator<uint8_t>& begin,
286 const std::istream_iterator<uint8_t>& end)
Yingdi Yu27158392014-01-20 13:04:20 -0800287{
288 if (begin == end)
289 throw Error("Empty buffer during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700290
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700291 uint8_t firstOctet = *begin;
Yingdi Yu27158392014-01-20 13:04:20 -0800292 ++begin;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700293 if (firstOctet < 253)
Yingdi Yu27158392014-01-20 13:04:20 -0800294 {
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700295 return firstOctet;
Yingdi Yu27158392014-01-20 13:04:20 -0800296 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700297 else if (firstOctet == 253)
Yingdi Yu27158392014-01-20 13:04:20 -0800298 {
299 uint8_t buffer[2];
300 int count = 0;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700301
Yingdi Yu27158392014-01-20 13:04:20 -0800302 while(begin != end && count < 2){
303 buffer[count] = *begin;
304 begin++;
305 count++;
306 }
307
308 if (count < 2)
309 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700310
311 uint16_t value = *reinterpret_cast<const uint16_t*>(buffer);
Yingdi Yu27158392014-01-20 13:04:20 -0800312 return be16toh(value);
313 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700314 else if (firstOctet == 254)
Yingdi Yu27158392014-01-20 13:04:20 -0800315 {
316 uint8_t buffer[4];
317 int count = 0;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700318
Yingdi Yu27158392014-01-20 13:04:20 -0800319 while(begin != end && count < 4){
320 buffer[count] = *begin;
321 begin++;
322 count++;
323 }
324
325 if (count < 4)
326 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700327
Yingdi Yu27158392014-01-20 13:04:20 -0800328 uint32_t value = *reinterpret_cast<const uint32_t*>(buffer);
329 return be32toh(value);
330 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700331 else // if (firstOctet == 255)
Yingdi Yu27158392014-01-20 13:04:20 -0800332 {
333 uint8_t buffer[8];
334 int count = 0;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700335
Yingdi Yu27158392014-01-20 13:04:20 -0800336 while(begin != end && count < 8){
337 buffer[count] = *begin;
338 begin++;
339 count++;
340 }
341
342 if (count < 8)
343 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700344
Yingdi Yu27158392014-01-20 13:04:20 -0800345 uint64_t value = *reinterpret_cast<const uint64_t*>(buffer);
346 return be64toh(value);
347 }
348}
349
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800350template<class InputIterator>
351inline uint32_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700352readType(InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800353{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700354 uint64_t type = readVarNumber(begin, end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800355 if (type > std::numeric_limits<uint32_t>::max())
356 {
357 throw Error("TLV type code exceeds allowed maximum");
358 }
359
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700360 return static_cast<uint32_t>(type);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800361}
362
363size_t
364sizeOfVarNumber(uint64_t varNumber)
365{
366 if (varNumber < 253) {
367 return 1;
368 }
369 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
370 return 3;
371 }
372 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
373 return 5;
374 }
375 else {
376 return 9;
377 }
378}
379
380inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700381writeVarNumber(std::ostream& os, uint64_t varNumber)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800382{
383 if (varNumber < 253) {
384 os.put(static_cast<uint8_t> (varNumber));
385 return 1;
386 }
387 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
388 os.put(253);
389 uint16_t value = htobe16(static_cast<uint16_t> (varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700390 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800391 return 3;
392 }
393 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
394 os.put(254);
395 uint32_t value = htobe32(static_cast<uint32_t> (varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700396 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800397 return 5;
398 }
399 else {
400 os.put(255);
401 uint64_t value = htobe64(varNumber);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700402 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800403 return 9;
404 }
405}
406
407template<class InputIterator>
408inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700409readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800410{
411 switch (size) {
412 case 1:
413 {
414 if (end - begin < 1)
415 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700416
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800417 uint8_t value = *begin;
418 begin++;
419 return value;
420 }
421 case 2:
422 {
423 if (end - begin < 2)
424 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700425
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800426 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin); // kind of dangerous... but should be efficient
427 begin += 2;
428 return be16toh(value);
429 }
430 case 4:
431 {
432 if (end - begin < 4)
433 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700434
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800435 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin); // kind of dangerous... but should be efficient
436 begin += 4;
437 return be32toh(value);
438 }
439 case 8:
440 {
441 if (end - begin < 8)
442 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700443
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800444 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
445 begin += 8;
446 return be64toh(value);
447 }
448 }
449 throw Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)");
450}
451
Yingdi Yu27158392014-01-20 13:04:20 -0800452template<>
453inline uint64_t
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700454readNonNegativeInteger<std::istream_iterator<uint8_t> >(size_t size,
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700455 std::istream_iterator<uint8_t>& begin,
456 const std::istream_iterator<uint8_t>& end)
Yingdi Yu27158392014-01-20 13:04:20 -0800457{
458 switch (size) {
459 case 1:
460 {
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700461 if (begin == end)
Yingdi Yu27158392014-01-20 13:04:20 -0800462 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700463
Yingdi Yu27158392014-01-20 13:04:20 -0800464 uint8_t value = *begin;
465 begin++;
466 return value;
467 }
468 case 2:
469 {
470 uint8_t buffer[2];
471 int count = 0;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700472
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700473 while (begin != end && count < 2) {
Yingdi Yu27158392014-01-20 13:04:20 -0800474 buffer[count] = *begin;
475 begin++;
476 count++;
477 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700478
Yingdi Yu27158392014-01-20 13:04:20 -0800479 if (count < 2)
480 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700481
Yingdi Yu27158392014-01-20 13:04:20 -0800482 uint16_t value = *reinterpret_cast<const uint16_t*>(buffer);
483 return be16toh(value);
484 }
485 case 4:
486 {
487 uint8_t buffer[4];
488 int count = 0;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700489
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700490 while (begin != end && count < 4) {
Yingdi Yu27158392014-01-20 13:04:20 -0800491 buffer[count] = *begin;
492 begin++;
493 count++;
494 }
495
496 if (count < 4)
497 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700498
Yingdi Yu27158392014-01-20 13:04:20 -0800499 uint32_t value = *reinterpret_cast<const uint32_t*>(buffer);
500 return be32toh(value);
501 }
502 case 8:
503 {
504 uint8_t buffer[8];
505 int count = 0;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700506
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700507 while (begin != end && count < 8){
Yingdi Yu27158392014-01-20 13:04:20 -0800508 buffer[count] = *begin;
509 begin++;
510 count++;
511 }
512
513 if (count < 8)
514 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700515
Yingdi Yu27158392014-01-20 13:04:20 -0800516 uint64_t value = *reinterpret_cast<const uint64_t*>(buffer);
517 return be64toh(value);
518 }
519 }
520 throw Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)");
521}
522
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800523inline size_t
524sizeOfNonNegativeInteger(uint64_t varNumber)
525{
526 if (varNumber < 253) {
527 return 1;
528 }
529 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
530 return 2;
531 }
532 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
533 return 4;
534 }
535 else {
536 return 8;
537 }
538}
539
540
541inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700542writeNonNegativeInteger(std::ostream& os, uint64_t varNumber)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800543{
544 if (varNumber < 253) {
545 os.put(static_cast<uint8_t> (varNumber));
546 return 1;
547 }
548 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
549 uint16_t value = htobe16(static_cast<uint16_t> (varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700550 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800551 return 2;
552 }
553 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
554 uint32_t value = htobe32(static_cast<uint32_t> (varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700555 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800556 return 4;
557 }
558 else {
559 uint64_t value = htobe64(varNumber);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700560 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800561 return 8;
562 }
563}
564
565
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700566} // namespace Tlv
567
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800568} // namespace ndn
569
570#endif // NDN_TLV_HPP