blob: da7b8eab3731446b5cd766cc53cbbd373b0d3c34 [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,
Spyridon Mastorakis3b54e852015-04-07 08:03:25 -070087 LinkPreference = 30,
88 LinkDelegation = 31,
89 SelectedDelegation = 32,
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080090
91 AppPrivateBlock1 = 128,
92 AppPrivateBlock2 = 32767
93};
94
Yingdi Yuebfa4cb2014-06-17 15:28:53 -070095enum SignatureTypeValue {
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080096 DigestSha256 = 0,
Yingdi Yuebfa4cb2014-06-17 15:28:53 -070097 SignatureSha256WithRsa = 1,
98 SignatureSha256WithEcdsa = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -080099};
100
Junxiao Shia464b922014-11-12 21:13:06 -0700101/** @brief indicates a possible value of ContentType field
102 */
Yingdi Yuebfa4cb2014-06-17 15:28:53 -0700103enum ContentTypeValue {
Junxiao Shia464b922014-11-12 21:13:06 -0700104 /** @brief indicates content is the actual data bits
105 */
106 ContentType_Blob = 0,
107
108 /** @brief indicates content is another name which identifies actual data content
109 */
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800110 ContentType_Link = 1,
Junxiao Shia464b922014-11-12 21:13:06 -0700111
112 /** @brief indicates content is a public key
113 */
114 ContentType_Key = 2,
115
116 /** @brief indicates a producer generated NACK
117 * @warning Experimental. Not defined in NDN-TLV spec.
118 */
119 ContentType_Nack = 3
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800120};
121
122/**
123 * @brief Read VAR-NUMBER in NDN-TLV encoding
124 *
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700125 * @param [in] begin Begin (pointer or iterator) of the buffer
126 * @param [in] end End (pointer or iterator) of the buffer
127 * @param [out] number Read number
128 *
129 * @throws This call never throws exception
130 *
131 * @return true if number successfully read from input, false otherwise
132 */
133template<class InputIterator>
134inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700135readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700136
137/**
138 * @brief Read TLV Type
139 *
140 * @param [in] begin Begin (pointer or iterator) of the buffer
141 * @param [in] end End (pointer or iterator) of the buffer
Alexander Afanasyev770827c2014-05-13 17:42:55 -0700142 * @param [out] type Read type number
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700143 *
144 * @throws This call never throws exception
145 *
146 * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
147 * is larger than 2^32-1 (type in this library is implemented as uint32_t)
148 */
149template<class InputIterator>
150inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700151readType(InputIterator& begin, const InputIterator& end, uint32_t& type);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700152
153
154/**
155 * @brief Read VAR-NUMBER in NDN-TLV encoding
156 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600157 * @throws This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800158 *
159 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
160 */
161template<class InputIterator>
162inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700163readVarNumber(InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800164
165/**
166 * @brief Read TLV Type
167 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600168 * @throws This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700169 *
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800170 * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
171 * is larger than 2^32-1 (type in this library is implemented as uint32_t)
172 */
173template<class InputIterator>
174inline uint32_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700175readType(InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800176
177/**
178 * @brief Get number of bytes necessary to hold value of VAR-NUMBER
179 */
180inline size_t
181sizeOfVarNumber(uint64_t varNumber);
182
183/**
184 * @brief Write VAR-NUMBER to the specified stream
185 */
186inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700187writeVarNumber(std::ostream& os, uint64_t varNumber);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800188
189/**
190 * @brief Read nonNegativeInteger in NDN-TLV encoding
191 *
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600192 * This call will throw ndn::tlv::Error (aka std::runtime_error) if number cannot be read
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800193 *
194 * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
195 *
196 * How many bytes will be read is directly controlled by the size parameter, which can be either
197 * 1, 2, 4, or 8. If the value of size is different, then an exception will be thrown.
198 */
199template<class InputIterator>
200inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700201readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800202
203/**
204 * @brief Get number of bytes necessary to hold value of nonNegativeInteger
205 */
206inline size_t
207sizeOfNonNegativeInteger(uint64_t varNumber);
208
209/**
210 * @brief Write nonNegativeInteger to the specified stream
211 */
212inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700213writeNonNegativeInteger(std::ostream& os, uint64_t varNumber);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800214
215/////////////////////////////////////////////////////////////////////////////////
216/////////////////////////////////////////////////////////////////////////////////
217/////////////////////////////////////////////////////////////////////////////////
218
219// Inline implementations
220
221/////////////////////////////////////////////////////////////////////////////////
222/////////////////////////////////////////////////////////////////////////////////
223/////////////////////////////////////////////////////////////////////////////////
224
225template<class InputIterator>
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700226inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700227readVarNumber(InputIterator& begin, const InputIterator& end, uint64_t& number)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700228{
229 if (begin == end)
230 return false;
231
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700232 uint8_t firstOctet = *begin;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700233 ++begin;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700234 if (firstOctet < 253)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700235 {
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700236 number = firstOctet;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700237 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700238 else if (firstOctet == 253)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700239 {
240 if (end - begin < 2)
241 return false;
242
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700243 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700244 begin += 2;
245 number = be16toh(value);
246 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700247 else if (firstOctet == 254)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700248 {
249 if (end - begin < 4)
250 return false;
251
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700252 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700253 begin += 4;
254 number = be32toh(value);
255 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700256 else // if (firstOctet == 255)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700257 {
258 if (end - begin < 8)
259 return false;
260
261 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
262 begin += 8;
263
264 number = be64toh(value);
265 }
266
267 return true;
268}
269
270template<class InputIterator>
271inline bool
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700272readType(InputIterator& begin, const InputIterator& end, uint32_t& type)
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700273{
Mickey Sweatt632e0572014-04-20 00:36:32 -0700274 uint64_t number = 0;
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700275 bool isOk = readVarNumber(begin, end, number);
276 if (!isOk || number > std::numeric_limits<uint32_t>::max())
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700277 {
278 return false;
279 }
280
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700281 type = static_cast<uint64_t>(number);
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700282 return true;
283}
284
285template<class InputIterator>
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800286inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700287readVarNumber(InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800288{
289 if (begin == end)
290 throw Error("Empty buffer during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700291
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700292 uint64_t value;
293 bool isOk = readVarNumber(begin, end, value);
294 if (!isOk)
295 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700296
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700297 return value;
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800298}
299
Yingdi Yu27158392014-01-20 13:04:20 -0800300template<>
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700301inline bool
Junxiao Shi468abc32014-11-04 09:12:47 -0700302readVarNumber<std::istream_iterator<uint8_t>>(std::istream_iterator<uint8_t>& begin,
303 const std::istream_iterator<uint8_t>& end,
304 uint64_t& value)
Yingdi Yu27158392014-01-20 13:04:20 -0800305{
306 if (begin == end)
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700307 return false;
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700308
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700309 uint8_t firstOctet = *begin;
Yingdi Yu27158392014-01-20 13:04:20 -0800310 ++begin;
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700311 if (firstOctet < 253)
Yingdi Yu27158392014-01-20 13:04:20 -0800312 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700313 value = firstOctet;
Yingdi Yu27158392014-01-20 13:04:20 -0800314 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700315 else if (firstOctet == 253)
Yingdi Yu27158392014-01-20 13:04:20 -0800316 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700317 value = 0;
318 size_t count = 0;
319 for (; begin != end && count < 2; ++count)
320 {
321 value = ((value << 8) | *begin);
322 begin++;
323 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700324
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700325 if (count != 2)
326 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800327 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700328 else if (firstOctet == 254)
Yingdi Yu27158392014-01-20 13:04:20 -0800329 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700330 value = 0;
331 size_t count = 0;
332 for (; begin != end && count < 4; ++count)
333 {
334 value = ((value << 8) | *begin);
335 begin++;
336 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700337
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700338 if (count != 4)
339 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800340 }
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700341 else // if (firstOctet == 255)
Yingdi Yu27158392014-01-20 13:04:20 -0800342 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700343 value = 0;
344 size_t count = 0;
345 for (; begin != end && count < 8; ++count)
346 {
347 value = ((value << 8) | *begin);
348 begin++;
349 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700350
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700351 if (count != 8)
352 return false;
Yingdi Yu27158392014-01-20 13:04:20 -0800353 }
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700354
355 return true;
Yingdi Yu27158392014-01-20 13:04:20 -0800356}
357
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800358template<class InputIterator>
359inline uint32_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700360readType(InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800361{
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700362 uint64_t type = readVarNumber(begin, end);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800363 if (type > std::numeric_limits<uint32_t>::max())
364 {
365 throw Error("TLV type code exceeds allowed maximum");
366 }
367
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700368 return static_cast<uint32_t>(type);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800369}
370
371size_t
372sizeOfVarNumber(uint64_t varNumber)
373{
374 if (varNumber < 253) {
375 return 1;
376 }
377 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
378 return 3;
379 }
380 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
381 return 5;
382 }
383 else {
384 return 9;
385 }
386}
387
388inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700389writeVarNumber(std::ostream& os, uint64_t varNumber)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800390{
391 if (varNumber < 253) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200392 os.put(static_cast<char>(varNumber));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800393 return 1;
394 }
395 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200396 os.put(static_cast<char>(253));
397 uint16_t value = htobe16(static_cast<uint16_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700398 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800399 return 3;
400 }
401 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200402 os.put(static_cast<char>(254));
403 uint32_t value = htobe32(static_cast<uint32_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700404 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800405 return 5;
406 }
407 else {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200408 os.put(static_cast<char>(255));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800409 uint64_t value = htobe64(varNumber);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700410 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800411 return 9;
412 }
413}
414
415template<class InputIterator>
416inline uint64_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700417readNonNegativeInteger(size_t size, InputIterator& begin, const InputIterator& end)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800418{
419 switch (size) {
420 case 1:
421 {
422 if (end - begin < 1)
423 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700424
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800425 uint8_t value = *begin;
426 begin++;
427 return value;
428 }
429 case 2:
430 {
431 if (end - begin < 2)
432 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700433
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700434 uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800435 begin += 2;
436 return be16toh(value);
437 }
438 case 4:
439 {
440 if (end - begin < 4)
441 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700442
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700443 uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800444 begin += 4;
445 return be32toh(value);
446 }
447 case 8:
448 {
449 if (end - begin < 8)
450 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700451
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800452 uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
453 begin += 8;
454 return be64toh(value);
455 }
456 }
457 throw Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)");
458}
459
Yingdi Yu27158392014-01-20 13:04:20 -0800460template<>
461inline uint64_t
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700462readNonNegativeInteger<std::istream_iterator<uint8_t> >(size_t size,
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700463 std::istream_iterator<uint8_t>& begin,
464 const std::istream_iterator<uint8_t>& end)
Yingdi Yu27158392014-01-20 13:04:20 -0800465{
466 switch (size) {
467 case 1:
468 {
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700469 if (begin == end)
Yingdi Yu27158392014-01-20 13:04:20 -0800470 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700471
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700472 uint64_t value = *begin;
Yingdi Yu27158392014-01-20 13:04:20 -0800473 begin++;
474 return value;
475 }
476 case 2:
477 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700478 uint64_t value = 0;
479 size_t count = 0;
480 for (; begin != end && count < 2; ++count)
481 {
482 value = ((value << 8) | *begin);
483 begin++;
484 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700485
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700486 if (count != 2)
Yingdi Yu27158392014-01-20 13:04:20 -0800487 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700488
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700489 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800490 }
491 case 4:
492 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700493 uint64_t value = 0;
494 size_t count = 0;
495 for (; begin != end && count < 4; ++count)
496 {
497 value = ((value << 8) | *begin);
498 begin++;
499 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700500
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700501 if (count != 4)
Yingdi Yu27158392014-01-20 13:04:20 -0800502 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700503
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700504 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800505 }
506 case 8:
507 {
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700508 uint64_t value = 0;
509 size_t count = 0;
510 for (; begin != end && count < 8; ++count)
511 {
512 value = ((value << 8) | *begin);
513 begin++;
514 }
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700515
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700516 if (count != 8)
Yingdi Yu27158392014-01-20 13:04:20 -0800517 throw Error("Insufficient data during TLV processing");
Alexander Afanasyev937aa782014-03-21 13:17:57 -0700518
Alexander Afanasyev21ef2392014-03-25 12:40:22 -0700519 return value;
Yingdi Yu27158392014-01-20 13:04:20 -0800520 }
521 }
522 throw Error("Invalid length for nonNegativeInteger (only 1, 2, 4, and 8 are allowed)");
523}
524
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800525inline size_t
526sizeOfNonNegativeInteger(uint64_t varNumber)
527{
528 if (varNumber < 253) {
529 return 1;
530 }
531 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
532 return 2;
533 }
534 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
535 return 4;
536 }
537 else {
538 return 8;
539 }
540}
541
542
543inline size_t
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700544writeNonNegativeInteger(std::ostream& os, uint64_t varNumber)
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800545{
546 if (varNumber < 253) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200547 os.put(static_cast<char>(varNumber));
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800548 return 1;
549 }
550 else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200551 uint16_t value = htobe16(static_cast<uint16_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700552 os.write(reinterpret_cast<const char*>(&value), 2);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800553 return 2;
554 }
555 else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
Davide Pesavento07ffe0d2014-04-10 20:21:55 +0200556 uint32_t value = htobe32(static_cast<uint32_t>(varNumber));
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700557 os.write(reinterpret_cast<const char*>(&value), 4);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800558 return 4;
559 }
560 else {
561 uint64_t value = htobe64(varNumber);
Alexander Afanasyeva465e972014-03-22 17:21:49 -0700562 os.write(reinterpret_cast<const char*>(&value), 8);
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800563 return 8;
564 }
565}
566
567
Steve DiBenedetto54ce6682014-07-22 13:22:57 -0600568} // namespace tlv
Alexander Afanasyev13bb51a2014-01-02 19:13:26 -0800569} // namespace ndn
570
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -0700571#endif // NDN_ENCODING_TLV_HPP