blob: 893a852eb46f33db74eae72d262854222b8598e6 [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 Pesaventoe245b052017-10-31 13:00:44 -040033#include <cstring>
Davide Pesaventoa84f4642017-08-23 16:14:51 -040034#include <sstream>
Alexander Afanasyev6486d522014-10-23 14:14:11 -070035
Alexander Afanasyev15f67312014-07-22 15:11:09 -070036namespace ndn {
37namespace name {
38
Junxiao Shic2b8d242014-11-04 08:35:29 -070039BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Component>));
40BOOST_CONCEPT_ASSERT((WireEncodable<Component>));
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070041BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer<Component>));
Junxiao Shic2b8d242014-11-04 08:35:29 -070042BOOST_CONCEPT_ASSERT((WireDecodable<Component>));
43static_assert(std::is_base_of<tlv::Error, Component::Error>::value,
44 "name::Component::Error must inherit from tlv::Error");
45
Alexander Afanasyev6486d522014-10-23 14:14:11 -070046static const std::string&
47getSha256DigestUriPrefix()
48{
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070049 static const std::string prefix{"sha256digest="};
Alexander Afanasyev6486d522014-10-23 14:14:11 -070050 return prefix;
51}
52
Junxiao Shicf4ac5b2018-03-28 22:46:06 +000053void
54Component::ensureValid() const
Alexander Afanasyev15f67312014-07-22 15:11:09 -070055{
Junxiao Shicf4ac5b2018-03-28 22:46:06 +000056 if (type() < tlv::NameComponentMin || type() > tlv::NameComponentMax) {
57 BOOST_THROW_EXCEPTION(Error("TLV-TYPE " + to_string(type()) + " is not a valid NameComponent"));
58 }
59 if (type() == tlv::ImplicitSha256DigestComponent && value_size() != util::Sha256::DIGEST_SIZE) {
60 BOOST_THROW_EXCEPTION(Error("ImplicitSha256DigestComponent TLV-LENGTH must be " +
61 to_string(util::Sha256::DIGEST_SIZE)));
62 }
63}
64
65Component::Component(uint32_t type)
66 : Block(type)
67{
68 ensureValid();
Alexander Afanasyev15f67312014-07-22 15:11:09 -070069}
70
71Component::Component(const Block& wire)
72 : Block(wire)
73{
Junxiao Shicf4ac5b2018-03-28 22:46:06 +000074 ensureValid();
Alexander Afanasyev15f67312014-07-22 15:11:09 -070075}
76
Junxiao Shicf4ac5b2018-03-28 22:46:06 +000077Component::Component(uint32_t type, ConstBufferPtr buffer)
78 : Block(type, std::move(buffer))
Alexander Afanasyev15f67312014-07-22 15:11:09 -070079{
80}
81
Junxiao Shicf4ac5b2018-03-28 22:46:06 +000082Component::Component(uint32_t type, const uint8_t* value, size_t valueLen)
83 : Block(makeBinaryBlock(type, value, valueLen))
Alexander Afanasyev15f67312014-07-22 15:11:09 -070084{
85}
86
87Component::Component(const char* str)
Junxiao Shicf4ac5b2018-03-28 22:46:06 +000088 : Block(makeBinaryBlock(tlv::GenericNameComponent, str, std::char_traits<char>::length(str)))
Alexander Afanasyev15f67312014-07-22 15:11:09 -070089{
90}
91
92Component::Component(const std::string& str)
Junxiao Shicf4ac5b2018-03-28 22:46:06 +000093 : Block(makeStringBlock(tlv::GenericNameComponent, str))
Alexander Afanasyev15f67312014-07-22 15:11:09 -070094{
95}
96
Junxiao Shicf4ac5b2018-03-28 22:46:06 +000097static Component
98parseSha256DigestUri(std::string input)
99{
100 input.erase(0, getSha256DigestUriPrefix().size());
101
102 try {
103 return Component::fromImplicitSha256Digest(fromHex(input));
104 }
105 catch (const StringHelperError&) {
106 BOOST_THROW_EXCEPTION(Component::Error("Cannot convert to a ImplicitSha256DigestComponent "
107 "(invalid hex encoding)"));
108 }
109}
110
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700111Component
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000112Component::fromEscapedString(std::string input)
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700113{
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000114 uint32_t type = tlv::GenericNameComponent;
115 size_t equalPos = input.find('=');
116 if (equalPos != std::string::npos) {
117 if (equalPos + 1 == getSha256DigestUriPrefix().size() &&
118 input.compare(0, getSha256DigestUriPrefix().size(), getSha256DigestUriPrefix()) == 0) {
119 return parseSha256DigestUri(std::move(input));
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700120 }
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000121
122 long parsedType = std::strtol(input.data(), nullptr, 10);
123 if (parsedType < tlv::NameComponentMin || parsedType > tlv::NameComponentMax ||
124 parsedType == tlv::ImplicitSha256DigestComponent || parsedType == tlv::GenericNameComponent ||
125 to_string(parsedType).size() != equalPos) {
126 BOOST_THROW_EXCEPTION(Error("Incorrect TLV-TYPE in NameComponent URI"));
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700127 }
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000128 type = static_cast<uint32_t>(parsedType);
129 input.erase(0, equalPos + 1);
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700130 }
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700131
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000132 std::string value = unescape(input);
133 if (value.find_first_not_of('.') == std::string::npos) { // all periods
134 if (value.size() < 3) {
135 BOOST_THROW_EXCEPTION(Error("Illegal URI (name component cannot be . or ..)"));
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700136 }
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000137 return Component(type, reinterpret_cast<const uint8_t*>(value.data()), value.size() - 3);
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());
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700140}
141
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700142void
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000143Component::toUri(std::ostream& os) const
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700144{
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700145 if (type() == tlv::ImplicitSha256DigestComponent) {
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000146 os << getSha256DigestUriPrefix();
147 printHex(os, value(), value_size(), false);
148 return;
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700149 }
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000150
151 if (type() != tlv::GenericNameComponent) {
152 os << type() << '=';
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700153 }
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000154
155 if (std::all_of(value_begin(), value_end(), [] (uint8_t x) { return x == '.'; })) { // all periods
156 os << "...";
157 }
158
159 escape(os, reinterpret_cast<const char*>(value()), value_size());
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700160}
161
162std::string
163Component::toUri() const
164{
165 std::ostringstream os;
166 toUri(os);
167 return os.str();
168}
169
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700170////////////////////////////////////////////////////////////////////////////////
Alexander Afanasyev0f232c52014-10-23 13:07:31 -0700171
172bool
173Component::isNumber() const
174{
175 return (value_size() == 1 || value_size() == 2 ||
176 value_size() == 4 || value_size() == 8);
177}
178
179bool
180Component::isNumberWithMarker(uint8_t marker) const
181{
182 return (!empty() && value()[0] == marker &&
183 (value_size() == 2 || value_size() == 3 ||
184 value_size() == 5 || value_size() == 9));
185}
186
187bool
188Component::isVersion() const
189{
190 return isNumberWithMarker(VERSION_MARKER);
191}
192
193bool
194Component::isSegment() const
195{
196 return isNumberWithMarker(SEGMENT_MARKER);
197}
198
199bool
200Component::isSegmentOffset() const
201{
202 return isNumberWithMarker(SEGMENT_OFFSET_MARKER);
203}
204
205bool
206Component::isTimestamp() const
207{
208 return isNumberWithMarker(TIMESTAMP_MARKER);
209}
210
211bool
212Component::isSequenceNumber() const
213{
214 return isNumberWithMarker(SEQUENCE_NUMBER_MARKER);
215}
216
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700217////////////////////////////////////////////////////////////////////////////////
Alexander Afanasyev0f232c52014-10-23 13:07:31 -0700218
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700219uint64_t
220Component::toNumber() const
221{
Alexander Afanasyev0f232c52014-10-23 13:07:31 -0700222 if (!isNumber())
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700223 BOOST_THROW_EXCEPTION(Error("Name component does not have nonNegativeInteger value"));
Alexander Afanasyev0f232c52014-10-23 13:07:31 -0700224
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700225 return readNonNegativeInteger(*this);
226}
227
228uint64_t
229Component::toNumberWithMarker(uint8_t marker) const
230{
Alexander Afanasyev0f232c52014-10-23 13:07:31 -0700231 if (!isNumberWithMarker(marker))
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700232 BOOST_THROW_EXCEPTION(Error("Name component does not have the requested marker "
233 "or the value is not a nonNegativeInteger"));
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700234
235 Buffer::const_iterator valueBegin = value_begin() + 1;
236 return tlv::readNonNegativeInteger(value_size() - 1, valueBegin, value_end());
237}
238
239uint64_t
240Component::toVersion() const
241{
242 return toNumberWithMarker(VERSION_MARKER);
243}
244
245uint64_t
246Component::toSegment() const
247{
248 return toNumberWithMarker(SEGMENT_MARKER);
249}
250
251uint64_t
252Component::toSegmentOffset() const
253{
254 return toNumberWithMarker(SEGMENT_OFFSET_MARKER);
255}
256
257time::system_clock::TimePoint
258Component::toTimestamp() const
259{
260 uint64_t value = toNumberWithMarker(TIMESTAMP_MARKER);
261 return time::getUnixEpoch() + time::microseconds(value);
262}
263
264uint64_t
265Component::toSequenceNumber() const
266{
267 return toNumberWithMarker(SEQUENCE_NUMBER_MARKER);
268}
269
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700270////////////////////////////////////////////////////////////////////////////////
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700271
272Component
273Component::fromNumber(uint64_t number)
274{
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000275 return makeNonNegativeIntegerBlock(tlv::GenericNameComponent, number);
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700276}
277
278Component
279Component::fromNumberWithMarker(uint8_t marker, uint64_t number)
280{
281 EncodingEstimator estimator;
282
283 size_t valueLength = estimator.prependNonNegativeInteger(number);
284 valueLength += estimator.prependByteArray(&marker, 1);
285 size_t totalLength = valueLength;
286 totalLength += estimator.prependVarNumber(valueLength);
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000287 totalLength += estimator.prependVarNumber(tlv::GenericNameComponent);
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700288
289 EncodingBuffer encoder(totalLength, 0);
290 encoder.prependNonNegativeInteger(number);
291 encoder.prependByteArray(&marker, 1);
292 encoder.prependVarNumber(valueLength);
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000293 encoder.prependVarNumber(tlv::GenericNameComponent);
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700294
295 return encoder.block();
296}
297
298Component
299Component::fromVersion(uint64_t version)
300{
301 return fromNumberWithMarker(VERSION_MARKER, version);
302}
303
304Component
305Component::fromSegment(uint64_t segmentNo)
306{
307 return fromNumberWithMarker(SEGMENT_MARKER, segmentNo);
308}
309
310Component
311Component::fromSegmentOffset(uint64_t offset)
312{
313 return fromNumberWithMarker(SEGMENT_OFFSET_MARKER, offset);
314}
315
316Component
317Component::fromTimestamp(const time::system_clock::TimePoint& timePoint)
318{
319 using namespace time;
320 uint64_t value = duration_cast<microseconds>(timePoint - getUnixEpoch()).count();
321 return fromNumberWithMarker(TIMESTAMP_MARKER, value);
322}
323
324Component
325Component::fromSequenceNumber(uint64_t seqNo)
326{
327 return fromNumberWithMarker(SEQUENCE_NUMBER_MARKER, seqNo);
328}
329
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700330////////////////////////////////////////////////////////////////////////////////
331
332bool
333Component::isGeneric() const
334{
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000335 return type() == tlv::GenericNameComponent;
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700336}
337
338bool
339Component::isImplicitSha256Digest() const
340{
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000341 return type() == tlv::ImplicitSha256DigestComponent &&
342 value_size() == util::Sha256::DIGEST_SIZE;
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700343}
344
345Component
346Component::fromImplicitSha256Digest(const ConstBufferPtr& digest)
347{
Davide Pesavento10b24be2017-07-12 23:23:46 -0400348 if (digest->size() != util::Sha256::DIGEST_SIZE)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700349 BOOST_THROW_EXCEPTION(Error("Cannot create ImplicitSha256DigestComponent (input digest must be " +
Davide Pesavento10b24be2017-07-12 23:23:46 -0400350 to_string(util::Sha256::DIGEST_SIZE) + " octets)"));
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700351
352 return Block(tlv::ImplicitSha256DigestComponent, digest);
353}
354
355Component
356Component::fromImplicitSha256Digest(const uint8_t* digest, size_t digestSize)
357{
Davide Pesavento10b24be2017-07-12 23:23:46 -0400358 if (digestSize != util::Sha256::DIGEST_SIZE)
Davide Pesavento96b96af2015-09-19 23:00:40 +0200359 BOOST_THROW_EXCEPTION(Error("Cannot create ImplicitSha256DigestComponent (input digest must be " +
Davide Pesavento10b24be2017-07-12 23:23:46 -0400360 to_string(util::Sha256::DIGEST_SIZE) + " octets)"));
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700361
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700362 return makeBinaryBlock(tlv::ImplicitSha256DigestComponent, digest, digestSize);
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700363}
364
365////////////////////////////////////////////////////////////////////////////////
366
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000367bool
368Component::equals(const Component& other) const
369{
370 return type() == other.type() &&
371 value_size() == other.value_size() &&
Davide Pesaventoe245b052017-10-31 13:00:44 -0400372 (empty() || // needed with Apple clang < 9.0.0 due to libc++ bug
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000373 std::equal(value_begin(), value_end(), other.value_begin()));
374}
375
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700376int
377Component::compare(const Component& other) const
378{
Junxiao Shi010f0862016-10-11 21:08:32 +0000379 if (this->hasWire() && other.hasWire()) {
380 // In the common case where both components have wire encoding,
381 // it's more efficient to simply compare the wire encoding.
382 // This works because lexical order of TLV encoding happens to be
383 // the same as canonical order of the value.
384 return std::memcmp(wire(), other.wire(), std::min(size(), other.size()));
385 }
386
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000387 int cmpType = type() - other.type();
388 if (cmpType != 0)
389 return cmpType;
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700390
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000391 int cmpSize = value_size() - other.value_size();
392 if (cmpSize != 0)
393 return cmpSize;
394
Davide Pesaventoe245b052017-10-31 13:00:44 -0400395 if (empty())
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700396 return 0;
397
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700398 return std::memcmp(value(), other.value(), value_size());
399}
400
401Component
402Component::getSuccessor() const
403{
404 size_t totalLength = 0;
405 EncodingBuffer encoder(size() + 1, 1); // + 1 in case there is an overflow
406 // in unlikely case TLV length increases,
407 // EncodingBuffer will take care of that
408
409 bool isOverflow = true;
410 size_t i = value_size();
411 for (; isOverflow && i > 0; i--) {
412 uint8_t newValue = static_cast<uint8_t>((value()[i - 1] + 1) & 0xFF);
413 totalLength += encoder.prependByte(newValue);
414 isOverflow = (newValue == 0);
415 }
416 totalLength += encoder.prependByteArray(value(), i);
417
418 if (isOverflow) {
419 // new name components has to be extended
420 totalLength += encoder.appendByte(0);
421 }
422
Davide Pesavento9bd4d982015-05-13 14:31:19 +0200423 encoder.prependVarNumber(totalLength);
424 encoder.prependVarNumber(type());
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700425
426 return encoder.block();
427}
428
Alexander Afanasyev74633892015-02-08 18:08:46 -0800429template<encoding::Tag TAG>
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700430size_t
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700431Component::wireEncode(EncodingImpl<TAG>& encoder) const
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700432{
433 size_t totalLength = 0;
434 if (value_size() > 0)
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700435 totalLength += encoder.prependByteArray(value(), value_size());
436 totalLength += encoder.prependVarNumber(value_size());
437 totalLength += encoder.prependVarNumber(type());
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700438 return totalLength;
439}
440
Davide Pesavento88a0d812017-08-19 21:31:42 -0400441NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(Component);
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700442
443const Block&
444Component::wireEncode() const
445{
446 if (this->hasWire())
447 return *this;
448
449 EncodingEstimator estimator;
450 size_t estimatedSize = wireEncode(estimator);
451
452 EncodingBuffer buffer(estimatedSize, 0);
453 wireEncode(buffer);
454
455 const_cast<Component&>(*this) = buffer.block();
456 return *this;
457}
458
459void
460Component::wireDecode(const Block& wire)
461{
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700462 *this = wire;
Qiuhan Ding2c3cbe42014-11-25 18:10:23 -0800463 // validity check is done within Component(const Block& wire)
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700464}
465
466} // namespace name
467} // namespace ndn