blob: bd551b23a00f7c474d09a7e82c2e848f2b206f49 [file] [log] [blame]
Alexander Afanasyev15f67312014-07-22 15:11:09 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesavento10b24be2017-07-12 23:23:46 -04002/*
Davide Pesavento08378cb2018-02-01 16:10:54 -05003 * Copyright (c) 2013-2018 Regents of the University of California.
Alexander Afanasyev15f67312014-07-22 15:11:09 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * 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.
20 *
21 * @author Jeff Thompson <jefft0@remap.ucla.edu>
22 * @author Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
23 * @author Zhenkai Zhu <http://irl.cs.ucla.edu/~zhenkai/>
24 */
25
26#include "name-component.hpp"
27
28#include "encoding/block-helpers.hpp"
29#include "encoding/encoding-buffer.hpp"
Junxiao Shi6938e342017-07-25 21:56:58 +000030#include "util/sha256.hpp"
Alexander Afanasyev15f67312014-07-22 15:11:09 -070031#include "util/string-helper.hpp"
32
Davide Pesaventodd461432017-01-28 21:47:26 -050033#include <boost/algorithm/string/trim.hpp>
Davide Pesaventoe245b052017-10-31 13:00:44 -040034#include <cstring>
Davide Pesaventoa84f4642017-08-23 16:14:51 -040035#include <sstream>
Alexander Afanasyev6486d522014-10-23 14:14:11 -070036
Alexander Afanasyev15f67312014-07-22 15:11:09 -070037namespace ndn {
38namespace name {
39
Junxiao Shic2b8d242014-11-04 08:35:29 -070040BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Component>));
41BOOST_CONCEPT_ASSERT((WireEncodable<Component>));
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070042BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer<Component>));
Junxiao Shic2b8d242014-11-04 08:35:29 -070043BOOST_CONCEPT_ASSERT((WireDecodable<Component>));
44static_assert(std::is_base_of<tlv::Error, Component::Error>::value,
45 "name::Component::Error must inherit from tlv::Error");
46
Alexander Afanasyev6486d522014-10-23 14:14:11 -070047static const std::string&
48getSha256DigestUriPrefix()
49{
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070050 static const std::string prefix{"sha256digest="};
Alexander Afanasyev6486d522014-10-23 14:14:11 -070051 return prefix;
52}
53
Junxiao Shicf4ac5b2018-03-28 22:46:06 +000054void
55Component::ensureValid() const
Alexander Afanasyev15f67312014-07-22 15:11:09 -070056{
Junxiao Shicf4ac5b2018-03-28 22:46:06 +000057 if (type() < tlv::NameComponentMin || type() > tlv::NameComponentMax) {
58 BOOST_THROW_EXCEPTION(Error("TLV-TYPE " + to_string(type()) + " is not a valid NameComponent"));
59 }
60 if (type() == tlv::ImplicitSha256DigestComponent && value_size() != util::Sha256::DIGEST_SIZE) {
61 BOOST_THROW_EXCEPTION(Error("ImplicitSha256DigestComponent TLV-LENGTH must be " +
62 to_string(util::Sha256::DIGEST_SIZE)));
63 }
64}
65
66Component::Component(uint32_t type)
67 : Block(type)
68{
69 ensureValid();
Alexander Afanasyev15f67312014-07-22 15:11:09 -070070}
71
72Component::Component(const Block& wire)
73 : Block(wire)
74{
Junxiao Shicf4ac5b2018-03-28 22:46:06 +000075 ensureValid();
Alexander Afanasyev15f67312014-07-22 15:11:09 -070076}
77
Junxiao Shicf4ac5b2018-03-28 22:46:06 +000078Component::Component(uint32_t type, ConstBufferPtr buffer)
79 : Block(type, std::move(buffer))
Alexander Afanasyev15f67312014-07-22 15:11:09 -070080{
81}
82
Junxiao Shicf4ac5b2018-03-28 22:46:06 +000083Component::Component(uint32_t type, const uint8_t* value, size_t valueLen)
84 : Block(makeBinaryBlock(type, value, valueLen))
Alexander Afanasyev15f67312014-07-22 15:11:09 -070085{
86}
87
88Component::Component(const char* str)
Junxiao Shicf4ac5b2018-03-28 22:46:06 +000089 : Block(makeBinaryBlock(tlv::GenericNameComponent, str, std::char_traits<char>::length(str)))
Alexander Afanasyev15f67312014-07-22 15:11:09 -070090{
91}
92
93Component::Component(const std::string& str)
Junxiao Shicf4ac5b2018-03-28 22:46:06 +000094 : Block(makeStringBlock(tlv::GenericNameComponent, str))
Alexander Afanasyev15f67312014-07-22 15:11:09 -070095{
96}
97
Junxiao Shicf4ac5b2018-03-28 22:46:06 +000098static Component
99parseSha256DigestUri(std::string input)
100{
101 input.erase(0, getSha256DigestUriPrefix().size());
102
103 try {
104 return Component::fromImplicitSha256Digest(fromHex(input));
105 }
106 catch (const StringHelperError&) {
107 BOOST_THROW_EXCEPTION(Component::Error("Cannot convert to a ImplicitSha256DigestComponent "
108 "(invalid hex encoding)"));
109 }
110}
111
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700112Component
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000113Component::fromEscapedString(std::string input)
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700114{
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000115 boost::algorithm::trim(input);
116 uint32_t type = tlv::GenericNameComponent;
117 size_t equalPos = input.find('=');
118 if (equalPos != std::string::npos) {
119 if (equalPos + 1 == getSha256DigestUriPrefix().size() &&
120 input.compare(0, getSha256DigestUriPrefix().size(), getSha256DigestUriPrefix()) == 0) {
121 return parseSha256DigestUri(std::move(input));
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700122 }
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000123
124 long parsedType = std::strtol(input.data(), nullptr, 10);
125 if (parsedType < tlv::NameComponentMin || parsedType > tlv::NameComponentMax ||
126 parsedType == tlv::ImplicitSha256DigestComponent || parsedType == tlv::GenericNameComponent ||
127 to_string(parsedType).size() != equalPos) {
128 BOOST_THROW_EXCEPTION(Error("Incorrect TLV-TYPE in NameComponent URI"));
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700129 }
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000130 type = static_cast<uint32_t>(parsedType);
131 input.erase(0, equalPos + 1);
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700132 }
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700133
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000134 std::string value = unescape(input);
135 if (value.find_first_not_of('.') == std::string::npos) { // all periods
136 if (value.size() < 3) {
137 BOOST_THROW_EXCEPTION(Error("Illegal URI (name component cannot be . or ..)"));
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700138 }
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000139 return Component(type, reinterpret_cast<const uint8_t*>(value.data()), value.size() - 3);
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700140 }
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000141 return Component(type, reinterpret_cast<const uint8_t*>(value.data()), value.size());
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700142}
143
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700144void
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000145Component::toUri(std::ostream& os) const
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700146{
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700147 if (type() == tlv::ImplicitSha256DigestComponent) {
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000148 os << getSha256DigestUriPrefix();
149 printHex(os, value(), value_size(), false);
150 return;
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700151 }
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000152
153 if (type() != tlv::GenericNameComponent) {
154 os << type() << '=';
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700155 }
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000156
157 if (std::all_of(value_begin(), value_end(), [] (uint8_t x) { return x == '.'; })) { // all periods
158 os << "...";
159 }
160
161 escape(os, reinterpret_cast<const char*>(value()), value_size());
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700162}
163
164std::string
165Component::toUri() const
166{
167 std::ostringstream os;
168 toUri(os);
169 return os.str();
170}
171
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700172////////////////////////////////////////////////////////////////////////////////
Alexander Afanasyev0f232c52014-10-23 13:07:31 -0700173
174bool
175Component::isNumber() const
176{
177 return (value_size() == 1 || value_size() == 2 ||
178 value_size() == 4 || value_size() == 8);
179}
180
181bool
182Component::isNumberWithMarker(uint8_t marker) const
183{
184 return (!empty() && value()[0] == marker &&
185 (value_size() == 2 || value_size() == 3 ||
186 value_size() == 5 || value_size() == 9));
187}
188
189bool
190Component::isVersion() const
191{
192 return isNumberWithMarker(VERSION_MARKER);
193}
194
195bool
196Component::isSegment() const
197{
198 return isNumberWithMarker(SEGMENT_MARKER);
199}
200
201bool
202Component::isSegmentOffset() const
203{
204 return isNumberWithMarker(SEGMENT_OFFSET_MARKER);
205}
206
207bool
208Component::isTimestamp() const
209{
210 return isNumberWithMarker(TIMESTAMP_MARKER);
211}
212
213bool
214Component::isSequenceNumber() const
215{
216 return isNumberWithMarker(SEQUENCE_NUMBER_MARKER);
217}
218
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700219////////////////////////////////////////////////////////////////////////////////
Alexander Afanasyev0f232c52014-10-23 13:07:31 -0700220
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700221uint64_t
222Component::toNumber() const
223{
Alexander Afanasyev0f232c52014-10-23 13:07:31 -0700224 if (!isNumber())
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700225 BOOST_THROW_EXCEPTION(Error("Name component does not have nonNegativeInteger value"));
Alexander Afanasyev0f232c52014-10-23 13:07:31 -0700226
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700227 return readNonNegativeInteger(*this);
228}
229
230uint64_t
231Component::toNumberWithMarker(uint8_t marker) const
232{
Alexander Afanasyev0f232c52014-10-23 13:07:31 -0700233 if (!isNumberWithMarker(marker))
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700234 BOOST_THROW_EXCEPTION(Error("Name component does not have the requested marker "
235 "or the value is not a nonNegativeInteger"));
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700236
237 Buffer::const_iterator valueBegin = value_begin() + 1;
238 return tlv::readNonNegativeInteger(value_size() - 1, valueBegin, value_end());
239}
240
241uint64_t
242Component::toVersion() const
243{
244 return toNumberWithMarker(VERSION_MARKER);
245}
246
247uint64_t
248Component::toSegment() const
249{
250 return toNumberWithMarker(SEGMENT_MARKER);
251}
252
253uint64_t
254Component::toSegmentOffset() const
255{
256 return toNumberWithMarker(SEGMENT_OFFSET_MARKER);
257}
258
259time::system_clock::TimePoint
260Component::toTimestamp() const
261{
262 uint64_t value = toNumberWithMarker(TIMESTAMP_MARKER);
263 return time::getUnixEpoch() + time::microseconds(value);
264}
265
266uint64_t
267Component::toSequenceNumber() const
268{
269 return toNumberWithMarker(SEQUENCE_NUMBER_MARKER);
270}
271
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700272////////////////////////////////////////////////////////////////////////////////
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700273
274Component
275Component::fromNumber(uint64_t number)
276{
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000277 return makeNonNegativeIntegerBlock(tlv::GenericNameComponent, number);
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700278}
279
280Component
281Component::fromNumberWithMarker(uint8_t marker, uint64_t number)
282{
283 EncodingEstimator estimator;
284
285 size_t valueLength = estimator.prependNonNegativeInteger(number);
286 valueLength += estimator.prependByteArray(&marker, 1);
287 size_t totalLength = valueLength;
288 totalLength += estimator.prependVarNumber(valueLength);
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000289 totalLength += estimator.prependVarNumber(tlv::GenericNameComponent);
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700290
291 EncodingBuffer encoder(totalLength, 0);
292 encoder.prependNonNegativeInteger(number);
293 encoder.prependByteArray(&marker, 1);
294 encoder.prependVarNumber(valueLength);
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000295 encoder.prependVarNumber(tlv::GenericNameComponent);
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700296
297 return encoder.block();
298}
299
300Component
301Component::fromVersion(uint64_t version)
302{
303 return fromNumberWithMarker(VERSION_MARKER, version);
304}
305
306Component
307Component::fromSegment(uint64_t segmentNo)
308{
309 return fromNumberWithMarker(SEGMENT_MARKER, segmentNo);
310}
311
312Component
313Component::fromSegmentOffset(uint64_t offset)
314{
315 return fromNumberWithMarker(SEGMENT_OFFSET_MARKER, offset);
316}
317
318Component
319Component::fromTimestamp(const time::system_clock::TimePoint& timePoint)
320{
321 using namespace time;
322 uint64_t value = duration_cast<microseconds>(timePoint - getUnixEpoch()).count();
323 return fromNumberWithMarker(TIMESTAMP_MARKER, value);
324}
325
326Component
327Component::fromSequenceNumber(uint64_t seqNo)
328{
329 return fromNumberWithMarker(SEQUENCE_NUMBER_MARKER, seqNo);
330}
331
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700332////////////////////////////////////////////////////////////////////////////////
333
334bool
335Component::isGeneric() const
336{
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000337 return type() == tlv::GenericNameComponent;
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700338}
339
340bool
341Component::isImplicitSha256Digest() const
342{
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000343 return type() == tlv::ImplicitSha256DigestComponent &&
344 value_size() == util::Sha256::DIGEST_SIZE;
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700345}
346
347Component
348Component::fromImplicitSha256Digest(const ConstBufferPtr& digest)
349{
Davide Pesavento10b24be2017-07-12 23:23:46 -0400350 if (digest->size() != util::Sha256::DIGEST_SIZE)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700351 BOOST_THROW_EXCEPTION(Error("Cannot create ImplicitSha256DigestComponent (input digest must be " +
Davide Pesavento10b24be2017-07-12 23:23:46 -0400352 to_string(util::Sha256::DIGEST_SIZE) + " octets)"));
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700353
354 return Block(tlv::ImplicitSha256DigestComponent, digest);
355}
356
357Component
358Component::fromImplicitSha256Digest(const uint8_t* digest, size_t digestSize)
359{
Davide Pesavento10b24be2017-07-12 23:23:46 -0400360 if (digestSize != util::Sha256::DIGEST_SIZE)
Davide Pesavento96b96af2015-09-19 23:00:40 +0200361 BOOST_THROW_EXCEPTION(Error("Cannot create ImplicitSha256DigestComponent (input digest must be " +
Davide Pesavento10b24be2017-07-12 23:23:46 -0400362 to_string(util::Sha256::DIGEST_SIZE) + " octets)"));
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700363
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700364 return makeBinaryBlock(tlv::ImplicitSha256DigestComponent, digest, digestSize);
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700365}
366
367////////////////////////////////////////////////////////////////////////////////
368
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000369bool
370Component::equals(const Component& other) const
371{
372 return type() == other.type() &&
373 value_size() == other.value_size() &&
Davide Pesaventoe245b052017-10-31 13:00:44 -0400374 (empty() || // needed with Apple clang < 9.0.0 due to libc++ bug
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000375 std::equal(value_begin(), value_end(), other.value_begin()));
376}
377
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700378int
379Component::compare(const Component& other) const
380{
Junxiao Shi010f0862016-10-11 21:08:32 +0000381 if (this->hasWire() && other.hasWire()) {
382 // In the common case where both components have wire encoding,
383 // it's more efficient to simply compare the wire encoding.
384 // This works because lexical order of TLV encoding happens to be
385 // the same as canonical order of the value.
386 return std::memcmp(wire(), other.wire(), std::min(size(), other.size()));
387 }
388
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000389 int cmpType = type() - other.type();
390 if (cmpType != 0)
391 return cmpType;
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700392
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000393 int cmpSize = value_size() - other.value_size();
394 if (cmpSize != 0)
395 return cmpSize;
396
Davide Pesaventoe245b052017-10-31 13:00:44 -0400397 if (empty())
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700398 return 0;
399
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700400 return std::memcmp(value(), other.value(), value_size());
401}
402
403Component
404Component::getSuccessor() const
405{
406 size_t totalLength = 0;
407 EncodingBuffer encoder(size() + 1, 1); // + 1 in case there is an overflow
408 // in unlikely case TLV length increases,
409 // EncodingBuffer will take care of that
410
411 bool isOverflow = true;
412 size_t i = value_size();
413 for (; isOverflow && i > 0; i--) {
414 uint8_t newValue = static_cast<uint8_t>((value()[i - 1] + 1) & 0xFF);
415 totalLength += encoder.prependByte(newValue);
416 isOverflow = (newValue == 0);
417 }
418 totalLength += encoder.prependByteArray(value(), i);
419
420 if (isOverflow) {
421 // new name components has to be extended
422 totalLength += encoder.appendByte(0);
423 }
424
Davide Pesavento9bd4d982015-05-13 14:31:19 +0200425 encoder.prependVarNumber(totalLength);
426 encoder.prependVarNumber(type());
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700427
428 return encoder.block();
429}
430
Alexander Afanasyev74633892015-02-08 18:08:46 -0800431template<encoding::Tag TAG>
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700432size_t
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700433Component::wireEncode(EncodingImpl<TAG>& encoder) const
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700434{
435 size_t totalLength = 0;
436 if (value_size() > 0)
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700437 totalLength += encoder.prependByteArray(value(), value_size());
438 totalLength += encoder.prependVarNumber(value_size());
439 totalLength += encoder.prependVarNumber(type());
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700440 return totalLength;
441}
442
Davide Pesavento88a0d812017-08-19 21:31:42 -0400443NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(Component);
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700444
445const Block&
446Component::wireEncode() const
447{
448 if (this->hasWire())
449 return *this;
450
451 EncodingEstimator estimator;
452 size_t estimatedSize = wireEncode(estimator);
453
454 EncodingBuffer buffer(estimatedSize, 0);
455 wireEncode(buffer);
456
457 const_cast<Component&>(*this) = buffer.block();
458 return *this;
459}
460
461void
462Component::wireDecode(const Block& wire)
463{
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700464 *this = wire;
Qiuhan Ding2c3cbe42014-11-25 18:10:23 -0800465 // validity check is done within Component(const Block& wire)
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700466}
467
468} // namespace name
469} // namespace ndn