blob: 0fb4704cf13ac8ba90b211623eb13a6615b6070b [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>
Alexander Afanasyevd1de3972014-08-14 19:47:41 -070028
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080029#include "buffer.hpp"
Alexander Afanasyev200dd6f2014-01-28 19:04:25 -080030#include "endian.hpp"
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080031
32namespace ndn {
33
34/**
35 * @brief Namespace defining NDN-TLV related constants and procedures
36 */
Steve DiBenedetto54ce6682014-07-22 13:22:57 -060037namespace tlv {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080038
Alexander Afanasyeva465e972014-03-22 17:21:49 -070039class Error : public std::runtime_error
40{
41public:
42 explicit
43 Error(const std::string& what)
44 : std::runtime_error(what)
45 {
46 }
47};
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080048
49enum {
Alexander Afanasyev4b456282014-02-13 00:34:34 -080050 Interest = 5,
51 Data = 6,
52 Name = 7,
53 NameComponent = 8,
54 Selectors = 9,
55 Nonce = 10,
Alexander Afanasyeva465e972014-03-22 17:21:49 -070056 Scope = 11, // deprecated
Alexander Afanasyev4b456282014-02-13 00:34:34 -080057 InterestLifetime = 12,
58 MinSuffixComponents = 13,
59 MaxSuffixComponents = 14,
60 PublisherPublicKeyLocator = 15,
61 Exclude = 16,
62 ChildSelector = 17,
63 MustBeFresh = 18,
64 Any = 19,
65 MetaInfo = 20,
66 Content = 21,
67 SignatureInfo = 22,
68 SignatureValue = 23,
69 ContentType = 24,
70 FreshnessPeriod = 25,
71 FinalBlockId = 26,
72 SignatureType = 27,
73 KeyLocator = 28,
Junxiao Shibc5030d2014-09-01 11:53:12 -070074 KeyDigest = 29,
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080075
76 AppPrivateBlock1 = 128,
77 AppPrivateBlock2 = 32767
78};
79
Yingdi Yuebfa4cb2014-06-17 15:28:53 -070080enum SignatureTypeValue {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080081 DigestSha256 = 0,
Yingdi Yuebfa4cb2014-06-17 15:28:53 -070082 SignatureSha256WithRsa = 1,
83 SignatureSha256WithEcdsa = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080084};
85
Yingdi Yuebfa4cb2014-06-17 15:28:53 -070086enum ContentTypeValue {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080087 ContentType_Default = 0,
88 ContentType_Link = 1,
Alexander Afanasyevb78bc4d2014-04-09 21:20:52 -070089 ContentType_Key = 2
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080090};
91
Yingdi Yuebfa4cb2014-06-17 15:28:53 -070092/// @deprecated use ContentType instead
93typedef ContentTypeValue ConentType;
94
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080095/**
96 * @brief Read VAR-NUMBER in NDN-TLV encoding
97 *
Alexander Afanasyev937aa782014-03-21 13:17:57 -070098 * @param [in] begin Begin (pointer or iterator) of the buffer
99 * @param [in] end End (pointer or iterator) of the buffer
100 * @param [out] number Read number
101 *
102 * @throws This call never throws exception
103 *
104 * @return true if number successfully read from input, false otherwise
105 */
106template<class InputIterator>
107inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700108readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700109
110/**
111 * @brief Read TLV Type
112 *
113 * @param [in] begin Begin (pointer or iterator) of the buffer
114 * @param [in] end End (pointer or iterator) of the buffer
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700115 * @param [out] type Read type number
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700116 *
117 * @throws This call never throws exception
118 *
119 * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
120 * is larger than 2^32-1 (type in this library is implemented as uint32_t)
121 */
122template<class InputIterator>
123inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700124readType(InputIterator& begin, const InputIterator& end, uint32_t& type);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700125
126
127/**
128 * @brief Read VAR-NUMBER in NDN-TLV encoding
129 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600130 * @throws This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800131 *
132 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
133 */
134template<class InputIterator>
135inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700136readVarNumber(InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800137
138/**
139 * @brief Read TLV Type
140 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600141 * @throws This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700142 *
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800143 * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
144 * is larger than 2^32-1 (type in this library is implemented as uint32_t)
145 */
146template<class InputIterator>
147inline uint32_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700148readType(InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800149
150/**
151 * @brief Get number of bytes necessary to hold value of VAR-NUMBER
152 */
153inline size_t
154sizeOfVarNumber(uint64_t varNumber);
155
156/**
157 * @brief Write VAR-NUMBER to the specified stream
158 */
159inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700160writeVarNumber(std::ostream& os, uint64_t varNumber);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800161
162/**
163 * @brief Read nonNegativeInteger in NDN-TLV encoding
164 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600165 * This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800166 *
167 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
168 *
169 * How many bytes will be read is directly controlled by the size parameter, which can be either
170 * 1, 2, 4, or 8. If the value of size is different, then an exception will be thrown.
171 */
172template<class InputIterator>
173inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700174readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800175
176/**
177 * @brief Get number of bytes necessary to hold value of nonNegativeInteger
178 */
179inline size_t
180sizeOfNonNegativeInteger(uint64_t varNumber);
181
182/**
183 * @brief Write nonNegativeInteger to the specified stream
184 */
185inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700186writeNonNegativeInteger(std::ostream& os, uint64_t varNumber);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800187
188/////////////////////////////////////////////////////////////////////////////////
189/////////////////////////////////////////////////////////////////////////////////
190/////////////////////////////////////////////////////////////////////////////////
191
192// Inline implementations
193
194/////////////////////////////////////////////////////////////////////////////////
195/////////////////////////////////////////////////////////////////////////////////
196/////////////////////////////////////////////////////////////////////////////////
197
198template<class InputIterator>
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700199inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700200readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700201{
202 if (begin == end)
203 return false;
204
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700205 uint8_t firstOctet = *begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700206 ++begin;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700207 if (firstOctet < 253)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700208 {
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700209 number = firstOctet;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700210 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700211 else if (firstOctet == 253)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700212 {
213 if (end - begin < 2)
214 return false;
215
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700216 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700217 begin += 2;
218 number = be16toh(value);
219 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700220 else if (firstOctet == 254)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700221 {
222 if (end - begin < 4)
223 return false;
224
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700225 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700226 begin += 4;
227 number = be32toh(value);
228 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700229 else // if (firstOctet == 255)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700230 {
231 if (end - begin < 8)
232 return false;
233
234 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
235 begin += 8;
236
237 number = be64toh(value);
238 }
239
240 return true;
241}
242
243template<class InputIterator>
244inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700245readType(InputIterator& begin, const InputIterator& end, uint32_t& type)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700246{
Mickey Sweatt632e0572014-04-20 00:36:32 -0700247 uint64_t number = 0;
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700248 bool isOk = readVarNumber(begin, end, number);
249 if (!isOk || number > std::numeric_limits<uint32_t>::max())
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700250 {
251 return false;
252 }
253
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700254 type = static_cast<uint64_t>(number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700255 return true;
256}
257
258template<class InputIterator>
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800259inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700260readVarNumber(InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800261{
262 if (begin == end)
263 throw Error("Empty buffer during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700264
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700265 uint64_t value;
266 bool isOk = readVarNumber(begin, end, value);
267 if (!isOk)
268 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700269
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700270 return value;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800271}
272
Yingdi Yu27158392014-01-20 13:04:20 -0800273template<>
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700274inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700275readVarNumber<std::istream_iterator<uint8_t> >(std::istream_iterator<uint8_t>& begin,
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700276 const std::istream_iterator<uint8_t>& end,
277 uint64_t& value)
Yingdi Yu27158392014-01-20 13:04:20 -0800278{
279 if (begin == end)
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700280 return false;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700281
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700282 uint8_t firstOctet = *begin;
Yingdi Yu27158392014-01-20 13:04:20 -0800283 ++begin;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700284 if (firstOctet < 253)
Yingdi Yu27158392014-01-20 13:04:20 -0800285 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700286 value = firstOctet;
Yingdi Yu27158392014-01-20 13:04:20 -0800287 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700288 else if (firstOctet == 253)
Yingdi Yu27158392014-01-20 13:04:20 -0800289 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700290 value = 0;
291 size_t count = 0;
292 for (; begin != end && count < 2; ++count)
293 {
294 value = ((value << 8) | *begin);
295 begin++;
296 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700297
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700298 if (count != 2)
299 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800300 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700301 else if (firstOctet == 254)
Yingdi Yu27158392014-01-20 13:04:20 -0800302 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700303 value = 0;
304 size_t count = 0;
305 for (; begin != end && count < 4; ++count)
306 {
307 value = ((value << 8) | *begin);
308 begin++;
309 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700310
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700311 if (count != 4)
312 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800313 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700314 else // if (firstOctet == 255)
Yingdi Yu27158392014-01-20 13:04:20 -0800315 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700316 value = 0;
317 size_t count = 0;
318 for (; begin != end && count < 8; ++count)
319 {
320 value = ((value << 8) | *begin);
321 begin++;
322 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700323
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700324 if (count != 8)
325 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800326 }
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700327
328 return true;
Yingdi Yu27158392014-01-20 13:04:20 -0800329}
330
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800331template<class InputIterator>
332inline uint32_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700333readType(InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800334{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700335 uint64_t type = readVarNumber(begin, end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800336 if (type > std::numeric_limits<uint32_t>::max())
337 {
338 throw Error("TLV type code exceeds allowed maximum");
339 }
340
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700341 return static_cast<uint32_t>(type);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800342}
343
344size_t
345sizeOfVarNumber(uint64_t varNumber)
346{
347 if (varNumber < 253) {
348 return 1;
349 }
350 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
351 return 3;
352 }
353 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
354 return 5;
355 }
356 else {
357 return 9;
358 }
359}
360
361inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700362writeVarNumber(std::ostream& os, uint64_t varNumber)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800363{
364 if (varNumber < 253) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200365 os.put(static_cast<char>(varNumber));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800366 return 1;
367 }
368 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200369 os.put(static_cast<char>(253));
370 uint16_t value = htobe16(static_cast<uint16_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700371 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800372 return 3;
373 }
374 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200375 os.put(static_cast<char>(254));
376 uint32_t value = htobe32(static_cast<uint32_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700377 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800378 return 5;
379 }
380 else {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200381 os.put(static_cast<char>(255));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800382 uint64_t value = htobe64(varNumber);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700383 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800384 return 9;
385 }
386}
387
388template<class InputIterator>
389inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700390readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800391{
392 switch (size) {
393 case 1:
394 {
395 if (end - begin < 1)
396 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700397
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800398 uint8_t value = *begin;
399 begin++;
400 return value;
401 }
402 case 2:
403 {
404 if (end - begin < 2)
405 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700406
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700407 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800408 begin += 2;
409 return be16toh(value);
410 }
411 case 4:
412 {
413 if (end - begin < 4)
414 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700415
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700416 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800417 begin += 4;
418 return be32toh(value);
419 }
420 case 8:
421 {
422 if (end - begin < 8)
423 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700424
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800425 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
426 begin += 8;
427 return be64toh(value);
428 }
429 }
430 throw Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)");
431}
432
Yingdi Yu27158392014-01-20 13:04:20 -0800433template<>
434inline uint64_t
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700435readNonNegativeInteger<std::istream_iterator<uint8_t> >(size_t size,
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700436 std::istream_iterator<uint8_t>& begin,
437 const std::istream_iterator<uint8_t>& end)
Yingdi Yu27158392014-01-20 13:04:20 -0800438{
439 switch (size) {
440 case 1:
441 {
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700442 if (begin == end)
Yingdi Yu27158392014-01-20 13:04:20 -0800443 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700444
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700445 uint64_t value = *begin;
Yingdi Yu27158392014-01-20 13:04:20 -0800446 begin++;
447 return value;
448 }
449 case 2:
450 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700451 uint64_t value = 0;
452 size_t count = 0;
453 for (; begin != end && count < 2; ++count)
454 {
455 value = ((value << 8) | *begin);
456 begin++;
457 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700458
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700459 if (count != 2)
Yingdi Yu27158392014-01-20 13:04:20 -0800460 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700461
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700462 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800463 }
464 case 4:
465 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700466 uint64_t value = 0;
467 size_t count = 0;
468 for (; begin != end && count < 4; ++count)
469 {
470 value = ((value << 8) | *begin);
471 begin++;
472 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700473
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700474 if (count != 4)
Yingdi Yu27158392014-01-20 13:04:20 -0800475 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700476
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700477 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800478 }
479 case 8:
480 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700481 uint64_t value = 0;
482 size_t count = 0;
483 for (; begin != end && count < 8; ++count)
484 {
485 value = ((value << 8) | *begin);
486 begin++;
487 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700488
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700489 if (count != 8)
Yingdi Yu27158392014-01-20 13:04:20 -0800490 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700491
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700492 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800493 }
494 }
495 throw Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)");
496}
497
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800498inline size_t
499sizeOfNonNegativeInteger(uint64_t varNumber)
500{
501 if (varNumber < 253) {
502 return 1;
503 }
504 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
505 return 2;
506 }
507 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
508 return 4;
509 }
510 else {
511 return 8;
512 }
513}
514
515
516inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700517writeNonNegativeInteger(std::ostream& os, uint64_t varNumber)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800518{
519 if (varNumber < 253) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200520 os.put(static_cast<char>(varNumber));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800521 return 1;
522 }
523 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200524 uint16_t value = htobe16(static_cast<uint16_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700525 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800526 return 2;
527 }
528 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200529 uint32_t value = htobe32(static_cast<uint32_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700530 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800531 return 4;
532 }
533 else {
534 uint64_t value = htobe64(varNumber);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700535 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800536 return 8;
537 }
538}
539
540
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600541} // namespace tlv
542
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800543} // namespace ndn
544
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700545#endif // NDN_ENCODING_TLV_HPP