blob: 01a867962be6d7b7a59284e21c54e92a93ff5c18 [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07002/**
Alexander Afanasyevc169a812014-05-20 20:37:29 -04003 * Copyright (c) 2013-2014 Regents of the University of California.
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -08004 *
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07005 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -08006 *
Alexander Afanasyevc169a812014-05-20 20:37:29 -04007 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080020 */
21
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070022#ifndef NDN_ENCODING_TLV_HPP
23#define NDN_ENCODING_TLV_HPP
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080024
Alexander Afanasyev54467af2014-01-06 15:45:32 -080025#include <stdexcept>
Alexander Afanasyevd1de3972014-08-14 19:47:41 -070026#include <iostream>
Yingdi Yu27158392014-01-20 13:04:20 -080027#include <iterator>
Davide Pesaventodfe9c6b2014-08-25 21:17:10 +020028#include <limits>
Alexander Afanasyevd1de3972014-08-14 19:47:41 -070029
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080030#include "buffer.hpp"
Alexander Afanasyev200dd6f2014-01-28 19:04:25 -080031#include "endian.hpp"
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080032
33namespace ndn {
34
Junxiao Shi468abc32014-11-04 09:12:47 -070035/** @brief practical limit of network layer packet size
36 *
37 * If a packet is longer than this size, library and application MAY drop it.
38 */
39const size_t MAX_NDN_PACKET_SIZE = 8800;
40
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080041/**
42 * @brief Namespace defining NDN-TLV related constants and procedures
43 */
Steve DiBenedetto54ce6682014-07-22 13:22:57 -060044namespace tlv {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080045
Junxiao Shi468abc32014-11-04 09:12:47 -070046/** @brief represents an error in TLV encoding or decoding
47 *
48 * Element::Error SHOULD inherit from this Error class.
49 */
Alexander Afanasyeva465e972014-03-22 17:21:49 -070050class Error : public std::runtime_error
51{
52public:
53 explicit
54 Error(const std::string& what)
55 : std::runtime_error(what)
56 {
57 }
58};
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080059
60enum {
Alexander Afanasyev4b456282014-02-13 00:34:34 -080061 Interest = 5,
62 Data = 6,
63 Name = 7,
Alexander Afanasyev6486d522014-10-23 14:14:11 -070064 ImplicitSha256DigestComponent = 1,
Alexander Afanasyev4b456282014-02-13 00:34:34 -080065 NameComponent = 8,
66 Selectors = 9,
67 Nonce = 10,
Alexander Afanasyeva465e972014-03-22 17:21:49 -070068 Scope = 11, // deprecated
Alexander Afanasyev4b456282014-02-13 00:34:34 -080069 InterestLifetime = 12,
70 MinSuffixComponents = 13,
71 MaxSuffixComponents = 14,
72 PublisherPublicKeyLocator = 15,
73 Exclude = 16,
74 ChildSelector = 17,
75 MustBeFresh = 18,
76 Any = 19,
77 MetaInfo = 20,
78 Content = 21,
79 SignatureInfo = 22,
80 SignatureValue = 23,
81 ContentType = 24,
82 FreshnessPeriod = 25,
83 FinalBlockId = 26,
84 SignatureType = 27,
85 KeyLocator = 28,
Junxiao Shibc5030d2014-09-01 11:53:12 -070086 KeyDigest = 29,
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080087
88 AppPrivateBlock1 = 128,
89 AppPrivateBlock2 = 32767
90};
91
Yingdi Yuebfa4cb2014-06-17 15:28:53 -070092enum SignatureTypeValue {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080093 DigestSha256 = 0,
Yingdi Yuebfa4cb2014-06-17 15:28:53 -070094 SignatureSha256WithRsa = 1,
95 SignatureSha256WithEcdsa = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080096};
97
Junxiao Shia464b922014-11-12 21:13:06 -070098/** @brief indicates a possible value of ContentType field
99 */
Yingdi Yuebfa4cb2014-06-17 15:28:53 -0700100enum ContentTypeValue {
Junxiao Shia464b922014-11-12 21:13:06 -0700101 /** @brief indicates content is the actual data bits
102 */
103 ContentType_Blob = 0,
104
105 /** @brief indicates content is another name which identifies actual data content
106 */
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800107 ContentType_Link = 1,
Junxiao Shia464b922014-11-12 21:13:06 -0700108
109 /** @brief indicates content is a public key
110 */
111 ContentType_Key = 2,
112
113 /** @brief indicates a producer generated NACK
114 * @warning Experimental. Not defined in NDN-TLV spec.
115 */
116 ContentType_Nack = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800117};
118
119/**
120 * @brief Read VAR-NUMBER in NDN-TLV encoding
121 *
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700122 * @param [in] begin Begin (pointer or iterator) of the buffer
123 * @param [in] end End (pointer or iterator) of the buffer
124 * @param [out] number Read number
125 *
126 * @throws This call never throws exception
127 *
128 * @return true if number successfully read from input, false otherwise
129 */
130template<class InputIterator>
131inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700132readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700133
134/**
135 * @brief Read TLV Type
136 *
137 * @param [in] begin Begin (pointer or iterator) of the buffer
138 * @param [in] end End (pointer or iterator) of the buffer
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700139 * @param [out] type Read type number
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700140 *
141 * @throws This call never throws exception
142 *
143 * 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 bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700148readType(InputIterator& begin, const InputIterator& end, uint32_t& type);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700149
150
151/**
152 * @brief Read VAR-NUMBER in NDN-TLV encoding
153 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600154 * @throws This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800155 *
156 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
157 */
158template<class InputIterator>
159inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700160readVarNumber(InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800161
162/**
163 * @brief Read TLV Type
164 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600165 * @throws This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700166 *
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800167 * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
168 * is larger than 2^32-1 (type in this library is implemented as uint32_t)
169 */
170template<class InputIterator>
171inline uint32_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700172readType(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 VAR-NUMBER
176 */
177inline size_t
178sizeOfVarNumber(uint64_t varNumber);
179
180/**
181 * @brief Write VAR-NUMBER to the specified stream
182 */
183inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700184writeVarNumber(std::ostream& os, uint64_t varNumber);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800185
186/**
187 * @brief Read nonNegativeInteger in NDN-TLV encoding
188 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600189 * This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800190 *
191 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
192 *
193 * How many bytes will be read is directly controlled by the size parameter, which can be either
194 * 1, 2, 4, or 8. If the value of size is different, then an exception will be thrown.
195 */
196template<class InputIterator>
197inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700198readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800199
200/**
201 * @brief Get number of bytes necessary to hold value of nonNegativeInteger
202 */
203inline size_t
204sizeOfNonNegativeInteger(uint64_t varNumber);
205
206/**
207 * @brief Write nonNegativeInteger to the specified stream
208 */
209inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700210writeNonNegativeInteger(std::ostream& os, uint64_t varNumber);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800211
212/////////////////////////////////////////////////////////////////////////////////
213/////////////////////////////////////////////////////////////////////////////////
214/////////////////////////////////////////////////////////////////////////////////
215
216// Inline implementations
217
218/////////////////////////////////////////////////////////////////////////////////
219/////////////////////////////////////////////////////////////////////////////////
220/////////////////////////////////////////////////////////////////////////////////
221
222template<class InputIterator>
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700223inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700224readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700225{
226 if (begin == end)
227 return false;
228
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700229 uint8_t firstOctet = *begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700230 ++begin;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700231 if (firstOctet < 253)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700232 {
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700233 number = firstOctet;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700234 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700235 else if (firstOctet == 253)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700236 {
237 if (end - begin < 2)
238 return false;
239
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700240 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700241 begin += 2;
242 number = be16toh(value);
243 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700244 else if (firstOctet == 254)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700245 {
246 if (end - begin < 4)
247 return false;
248
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700249 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700250 begin += 4;
251 number = be32toh(value);
252 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700253 else // if (firstOctet == 255)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700254 {
255 if (end - begin < 8)
256 return false;
257
258 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
259 begin += 8;
260
261 number = be64toh(value);
262 }
263
264 return true;
265}
266
267template<class InputIterator>
268inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700269readType(InputIterator& begin, const InputIterator& end, uint32_t& type)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700270{
Mickey Sweatt632e0572014-04-20 00:36:32 -0700271 uint64_t number = 0;
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700272 bool isOk = readVarNumber(begin, end, number);
273 if (!isOk || number > std::numeric_limits<uint32_t>::max())
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700274 {
275 return false;
276 }
277
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700278 type = static_cast<uint64_t>(number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700279 return true;
280}
281
282template<class InputIterator>
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800283inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700284readVarNumber(InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800285{
286 if (begin == end)
287 throw Error("Empty buffer during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700288
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700289 uint64_t value;
290 bool isOk = readVarNumber(begin, end, value);
291 if (!isOk)
292 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700293
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700294 return value;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800295}
296
Yingdi Yu27158392014-01-20 13:04:20 -0800297template<>
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700298inline bool
Junxiao Shi468abc32014-11-04 09:12:47 -0700299readVarNumber<std::istream_iterator<uint8_t>>(std::istream_iterator<uint8_t>& begin,
300 const std::istream_iterator<uint8_t>& end,
301 uint64_t& value)
Yingdi Yu27158392014-01-20 13:04:20 -0800302{
303 if (begin == end)
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700304 return false;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700305
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700306 uint8_t firstOctet = *begin;
Yingdi Yu27158392014-01-20 13:04:20 -0800307 ++begin;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700308 if (firstOctet < 253)
Yingdi Yu27158392014-01-20 13:04:20 -0800309 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700310 value = firstOctet;
Yingdi Yu27158392014-01-20 13:04:20 -0800311 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700312 else if (firstOctet == 253)
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 < 2; ++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 != 2)
323 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800324 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700325 else if (firstOctet == 254)
Yingdi Yu27158392014-01-20 13:04:20 -0800326 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700327 value = 0;
328 size_t count = 0;
329 for (; begin != end && count < 4; ++count)
330 {
331 value = ((value << 8) | *begin);
332 begin++;
333 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700334
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700335 if (count != 4)
336 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800337 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700338 else // if (firstOctet == 255)
Yingdi Yu27158392014-01-20 13:04:20 -0800339 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700340 value = 0;
341 size_t count = 0;
342 for (; begin != end && count < 8; ++count)
343 {
344 value = ((value << 8) | *begin);
345 begin++;
346 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700347
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700348 if (count != 8)
349 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800350 }
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700351
352 return true;
Yingdi Yu27158392014-01-20 13:04:20 -0800353}
354
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800355template<class InputIterator>
356inline uint32_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700357readType(InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800358{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700359 uint64_t type = readVarNumber(begin, end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800360 if (type > std::numeric_limits<uint32_t>::max())
361 {
362 throw Error("TLV type code exceeds allowed maximum");
363 }
364
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700365 return static_cast<uint32_t>(type);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800366}
367
368size_t
369sizeOfVarNumber(uint64_t varNumber)
370{
371 if (varNumber < 253) {
372 return 1;
373 }
374 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
375 return 3;
376 }
377 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
378 return 5;
379 }
380 else {
381 return 9;
382 }
383}
384
385inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700386writeVarNumber(std::ostream& os, uint64_t varNumber)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800387{
388 if (varNumber < 253) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200389 os.put(static_cast<char>(varNumber));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800390 return 1;
391 }
392 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200393 os.put(static_cast<char>(253));
394 uint16_t value = htobe16(static_cast<uint16_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700395 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800396 return 3;
397 }
398 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200399 os.put(static_cast<char>(254));
400 uint32_t value = htobe32(static_cast<uint32_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700401 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800402 return 5;
403 }
404 else {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200405 os.put(static_cast<char>(255));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800406 uint64_t value = htobe64(varNumber);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700407 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800408 return 9;
409 }
410}
411
412template<class InputIterator>
413inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700414readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800415{
416 switch (size) {
417 case 1:
418 {
419 if (end - begin < 1)
420 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700421
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800422 uint8_t value = *begin;
423 begin++;
424 return value;
425 }
426 case 2:
427 {
428 if (end - begin < 2)
429 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700430
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700431 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800432 begin += 2;
433 return be16toh(value);
434 }
435 case 4:
436 {
437 if (end - begin < 4)
438 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700439
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700440 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800441 begin += 4;
442 return be32toh(value);
443 }
444 case 8:
445 {
446 if (end - begin < 8)
447 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700448
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800449 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
450 begin += 8;
451 return be64toh(value);
452 }
453 }
454 throw Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)");
455}
456
Yingdi Yu27158392014-01-20 13:04:20 -0800457template<>
458inline uint64_t
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700459readNonNegativeInteger<std::istream_iterator<uint8_t> >(size_t size,
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700460 std::istream_iterator<uint8_t>& begin,
461 const std::istream_iterator<uint8_t>& end)
Yingdi Yu27158392014-01-20 13:04:20 -0800462{
463 switch (size) {
464 case 1:
465 {
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700466 if (begin == end)
Yingdi Yu27158392014-01-20 13:04:20 -0800467 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700468
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700469 uint64_t value = *begin;
Yingdi Yu27158392014-01-20 13:04:20 -0800470 begin++;
471 return value;
472 }
473 case 2:
474 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700475 uint64_t value = 0;
476 size_t count = 0;
477 for (; begin != end && count < 2; ++count)
478 {
479 value = ((value << 8) | *begin);
480 begin++;
481 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700482
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700483 if (count != 2)
Yingdi Yu27158392014-01-20 13:04:20 -0800484 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700485
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700486 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800487 }
488 case 4:
489 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700490 uint64_t value = 0;
491 size_t count = 0;
492 for (; begin != end && count < 4; ++count)
493 {
494 value = ((value << 8) | *begin);
495 begin++;
496 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700497
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700498 if (count != 4)
Yingdi Yu27158392014-01-20 13:04:20 -0800499 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700500
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700501 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800502 }
503 case 8:
504 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700505 uint64_t value = 0;
506 size_t count = 0;
507 for (; begin != end && count < 8; ++count)
508 {
509 value = ((value << 8) | *begin);
510 begin++;
511 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700512
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700513 if (count != 8)
Yingdi Yu27158392014-01-20 13:04:20 -0800514 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700515
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700516 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800517 }
518 }
519 throw Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)");
520}
521
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800522inline size_t
523sizeOfNonNegativeInteger(uint64_t varNumber)
524{
525 if (varNumber < 253) {
526 return 1;
527 }
528 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
529 return 2;
530 }
531 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
532 return 4;
533 }
534 else {
535 return 8;
536 }
537}
538
539
540inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700541writeNonNegativeInteger(std::ostream& os, uint64_t varNumber)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800542{
543 if (varNumber < 253) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200544 os.put(static_cast<char>(varNumber));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800545 return 1;
546 }
547 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200548 uint16_t value = htobe16(static_cast<uint16_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700549 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800550 return 2;
551 }
552 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200553 uint32_t value = htobe32(static_cast<uint32_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700554 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800555 return 4;
556 }
557 else {
558 uint64_t value = htobe64(varNumber);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700559 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800560 return 8;
561 }
562}
563
564
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600565} // namespace tlv
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800566} // namespace ndn
567
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700568#endif // NDN_ENCODING_TLV_HPP