blob: 6ac6f316732dccc150e3dc8db8e7cf7fe7c1b433 [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"
Junxiao Shid2e60632018-08-10 10:48:44 -060027#include "detail/name-component-types.hpp"
Alexander Afanasyev15f67312014-07-22 15:11:09 -070028
Junxiao Shid2e60632018-08-10 10:48:44 -060029#include <cstdlib>
Davide Pesaventoe245b052017-10-31 13:00:44 -040030#include <cstring>
Davide Pesaventoa84f4642017-08-23 16:14:51 -040031#include <sstream>
Alexander Afanasyev6486d522014-10-23 14:14:11 -070032
Alexander Afanasyev15f67312014-07-22 15:11:09 -070033namespace ndn {
34namespace name {
35
Junxiao Shic2b8d242014-11-04 08:35:29 -070036BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Component>));
37BOOST_CONCEPT_ASSERT((WireEncodable<Component>));
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070038BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer<Component>));
Junxiao Shic2b8d242014-11-04 08:35:29 -070039BOOST_CONCEPT_ASSERT((WireDecodable<Component>));
40static_assert(std::is_base_of<tlv::Error, Component::Error>::value,
41 "name::Component::Error must inherit from tlv::Error");
42
Junxiao Shicf4ac5b2018-03-28 22:46:06 +000043void
44Component::ensureValid() const
Alexander Afanasyev15f67312014-07-22 15:11:09 -070045{
Junxiao Shicf4ac5b2018-03-28 22:46:06 +000046 if (type() < tlv::NameComponentMin || type() > tlv::NameComponentMax) {
47 BOOST_THROW_EXCEPTION(Error("TLV-TYPE " + to_string(type()) + " is not a valid NameComponent"));
48 }
Junxiao Shid2e60632018-08-10 10:48:44 -060049 detail::getComponentTypeTable().get(type()).check(*this);
Junxiao Shicf4ac5b2018-03-28 22:46:06 +000050}
51
52Component::Component(uint32_t type)
53 : Block(type)
54{
55 ensureValid();
Alexander Afanasyev15f67312014-07-22 15:11:09 -070056}
57
58Component::Component(const Block& wire)
59 : Block(wire)
60{
Junxiao Shicf4ac5b2018-03-28 22:46:06 +000061 ensureValid();
Alexander Afanasyev15f67312014-07-22 15:11:09 -070062}
63
Junxiao Shicf4ac5b2018-03-28 22:46:06 +000064Component::Component(uint32_t type, ConstBufferPtr buffer)
65 : Block(type, std::move(buffer))
Alexander Afanasyev15f67312014-07-22 15:11:09 -070066{
Junxiao Shid2e60632018-08-10 10:48:44 -060067 ensureValid();
Alexander Afanasyev15f67312014-07-22 15:11:09 -070068}
69
Junxiao Shicf4ac5b2018-03-28 22:46:06 +000070Component::Component(uint32_t type, const uint8_t* value, size_t valueLen)
71 : Block(makeBinaryBlock(type, value, valueLen))
Alexander Afanasyev15f67312014-07-22 15:11:09 -070072{
Junxiao Shid2e60632018-08-10 10:48:44 -060073 ensureValid();
Alexander Afanasyev15f67312014-07-22 15:11:09 -070074}
75
76Component::Component(const char* str)
Junxiao Shicf4ac5b2018-03-28 22:46:06 +000077 : Block(makeBinaryBlock(tlv::GenericNameComponent, str, std::char_traits<char>::length(str)))
Alexander Afanasyev15f67312014-07-22 15:11:09 -070078{
79}
80
81Component::Component(const std::string& str)
Junxiao Shicf4ac5b2018-03-28 22:46:06 +000082 : Block(makeStringBlock(tlv::GenericNameComponent, str))
Alexander Afanasyev15f67312014-07-22 15:11:09 -070083{
84}
85
Junxiao Shicf4ac5b2018-03-28 22:46:06 +000086static Component
Junxiao Shid2e60632018-08-10 10:48:44 -060087parseUriEscapedValue(uint32_t type, const char* input, size_t len)
Junxiao Shicf4ac5b2018-03-28 22:46:06 +000088{
Junxiao Shid2e60632018-08-10 10:48:44 -060089 std::ostringstream oss;
90 unescape(oss, input, len);
91 std::string value = oss.str();
Junxiao Shicf4ac5b2018-03-28 22:46:06 +000092 if (value.find_first_not_of('.') == std::string::npos) { // all periods
93 if (value.size() < 3) {
Junxiao Shid2e60632018-08-10 10:48:44 -060094 BOOST_THROW_EXCEPTION(Component::Error("Illegal URI (name component cannot be . or ..)"));
Alexander Afanasyev6486d522014-10-23 14:14:11 -070095 }
Junxiao Shicf4ac5b2018-03-28 22:46:06 +000096 return Component(type, reinterpret_cast<const uint8_t*>(value.data()), value.size() - 3);
Alexander Afanasyev6486d522014-10-23 14:14:11 -070097 }
Junxiao Shicf4ac5b2018-03-28 22:46:06 +000098 return Component(type, reinterpret_cast<const uint8_t*>(value.data()), value.size());
Alexander Afanasyev15f67312014-07-22 15:11:09 -070099}
100
Junxiao Shid2e60632018-08-10 10:48:44 -0600101Component
102Component::fromEscapedString(const std::string& input)
103{
104 size_t equalPos = input.find('=');
105 if (equalPos == std::string::npos) {
106 return parseUriEscapedValue(tlv::GenericNameComponent, input.data(), input.size());
107 }
108
109 long type = std::strtol(input.data(), nullptr, 10);
110 if (type >= tlv::NameComponentMin && type <= tlv::NameComponentMax &&
111 to_string(type).size() == equalPos) {
112 size_t valuePos = equalPos + 1;
113 return parseUriEscapedValue(static_cast<uint32_t>(type), input.data() + valuePos,
114 input.size() - valuePos);
115 }
116
117 auto typePrefix = input.substr(0, equalPos);
118 auto ct = detail::getComponentTypeTable().findByUriPrefix(typePrefix);
119 if (ct == nullptr) {
120 BOOST_THROW_EXCEPTION(Error("Incorrect TLV-TYPE '" + typePrefix + "' in NameComponent URI"));
121 }
122 return ct->parseAltUriValue(input.substr(equalPos + 1));
123}
124
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700125void
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000126Component::toUri(std::ostream& os) const
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700127{
Junxiao Shid2e60632018-08-10 10:48:44 -0600128 detail::getComponentTypeTable().get(type()).writeUri(os, *this);
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700129}
130
131std::string
132Component::toUri() const
133{
134 std::ostringstream os;
135 toUri(os);
136 return os.str();
137}
138
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700139////////////////////////////////////////////////////////////////////////////////
Alexander Afanasyev0f232c52014-10-23 13:07:31 -0700140
141bool
142Component::isNumber() const
143{
144 return (value_size() == 1 || value_size() == 2 ||
145 value_size() == 4 || value_size() == 8);
146}
147
148bool
149Component::isNumberWithMarker(uint8_t marker) const
150{
151 return (!empty() && value()[0] == marker &&
152 (value_size() == 2 || value_size() == 3 ||
153 value_size() == 5 || value_size() == 9));
154}
155
156bool
157Component::isVersion() const
158{
159 return isNumberWithMarker(VERSION_MARKER);
160}
161
162bool
163Component::isSegment() const
164{
165 return isNumberWithMarker(SEGMENT_MARKER);
166}
167
168bool
169Component::isSegmentOffset() const
170{
171 return isNumberWithMarker(SEGMENT_OFFSET_MARKER);
172}
173
174bool
175Component::isTimestamp() const
176{
177 return isNumberWithMarker(TIMESTAMP_MARKER);
178}
179
180bool
181Component::isSequenceNumber() const
182{
183 return isNumberWithMarker(SEQUENCE_NUMBER_MARKER);
184}
185
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700186////////////////////////////////////////////////////////////////////////////////
Alexander Afanasyev0f232c52014-10-23 13:07:31 -0700187
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700188uint64_t
189Component::toNumber() const
190{
Alexander Afanasyev0f232c52014-10-23 13:07:31 -0700191 if (!isNumber())
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700192 BOOST_THROW_EXCEPTION(Error("Name component does not have nonNegativeInteger value"));
Alexander Afanasyev0f232c52014-10-23 13:07:31 -0700193
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700194 return readNonNegativeInteger(*this);
195}
196
197uint64_t
198Component::toNumberWithMarker(uint8_t marker) const
199{
Alexander Afanasyev0f232c52014-10-23 13:07:31 -0700200 if (!isNumberWithMarker(marker))
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700201 BOOST_THROW_EXCEPTION(Error("Name component does not have the requested marker "
202 "or the value is not a nonNegativeInteger"));
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700203
204 Buffer::const_iterator valueBegin = value_begin() + 1;
205 return tlv::readNonNegativeInteger(value_size() - 1, valueBegin, value_end());
206}
207
208uint64_t
209Component::toVersion() const
210{
211 return toNumberWithMarker(VERSION_MARKER);
212}
213
214uint64_t
215Component::toSegment() const
216{
217 return toNumberWithMarker(SEGMENT_MARKER);
218}
219
220uint64_t
221Component::toSegmentOffset() const
222{
223 return toNumberWithMarker(SEGMENT_OFFSET_MARKER);
224}
225
226time::system_clock::TimePoint
227Component::toTimestamp() const
228{
229 uint64_t value = toNumberWithMarker(TIMESTAMP_MARKER);
230 return time::getUnixEpoch() + time::microseconds(value);
231}
232
233uint64_t
234Component::toSequenceNumber() const
235{
236 return toNumberWithMarker(SEQUENCE_NUMBER_MARKER);
237}
238
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700239////////////////////////////////////////////////////////////////////////////////
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700240
241Component
242Component::fromNumber(uint64_t number)
243{
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000244 return makeNonNegativeIntegerBlock(tlv::GenericNameComponent, number);
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700245}
246
247Component
248Component::fromNumberWithMarker(uint8_t marker, uint64_t number)
249{
250 EncodingEstimator estimator;
251
252 size_t valueLength = estimator.prependNonNegativeInteger(number);
253 valueLength += estimator.prependByteArray(&marker, 1);
254 size_t totalLength = valueLength;
255 totalLength += estimator.prependVarNumber(valueLength);
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000256 totalLength += estimator.prependVarNumber(tlv::GenericNameComponent);
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700257
258 EncodingBuffer encoder(totalLength, 0);
259 encoder.prependNonNegativeInteger(number);
260 encoder.prependByteArray(&marker, 1);
261 encoder.prependVarNumber(valueLength);
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000262 encoder.prependVarNumber(tlv::GenericNameComponent);
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700263
264 return encoder.block();
265}
266
267Component
268Component::fromVersion(uint64_t version)
269{
270 return fromNumberWithMarker(VERSION_MARKER, version);
271}
272
273Component
274Component::fromSegment(uint64_t segmentNo)
275{
276 return fromNumberWithMarker(SEGMENT_MARKER, segmentNo);
277}
278
279Component
280Component::fromSegmentOffset(uint64_t offset)
281{
282 return fromNumberWithMarker(SEGMENT_OFFSET_MARKER, offset);
283}
284
285Component
286Component::fromTimestamp(const time::system_clock::TimePoint& timePoint)
287{
288 using namespace time;
289 uint64_t value = duration_cast<microseconds>(timePoint - getUnixEpoch()).count();
290 return fromNumberWithMarker(TIMESTAMP_MARKER, value);
291}
292
293Component
294Component::fromSequenceNumber(uint64_t seqNo)
295{
296 return fromNumberWithMarker(SEQUENCE_NUMBER_MARKER, seqNo);
297}
298
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700299////////////////////////////////////////////////////////////////////////////////
300
301bool
302Component::isGeneric() const
303{
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000304 return type() == tlv::GenericNameComponent;
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700305}
306
307bool
308Component::isImplicitSha256Digest() const
309{
Junxiao Shicf4ac5b2018-03-28 22:46:06 +0000310 return type() == tlv::ImplicitSha256DigestComponent &&
311 value_size() == util::Sha256::DIGEST_SIZE;
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700312}
313
314Component
Davide Pesavento3b101d02018-07-21 22:44:09 -0400315Component::fromImplicitSha256Digest(ConstBufferPtr digest)
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700316{
Davide Pesavento10b24be2017-07-12 23:23:46 -0400317 if (digest->size() != util::Sha256::DIGEST_SIZE)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700318 BOOST_THROW_EXCEPTION(Error("Cannot create ImplicitSha256DigestComponent (input digest must be " +
Davide Pesavento10b24be2017-07-12 23:23:46 -0400319 to_string(util::Sha256::DIGEST_SIZE) + " octets)"));
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700320
Davide Pesavento3b101d02018-07-21 22:44:09 -0400321 return Block(tlv::ImplicitSha256DigestComponent, std::move(digest));
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700322}
323
324Component
325Component::fromImplicitSha256Digest(const uint8_t* digest, size_t digestSize)
326{
Davide Pesavento10b24be2017-07-12 23:23:46 -0400327 if (digestSize != util::Sha256::DIGEST_SIZE)
Davide Pesavento96b96af2015-09-19 23:00:40 +0200328 BOOST_THROW_EXCEPTION(Error("Cannot create ImplicitSha256DigestComponent (input digest must be " +
Davide Pesavento10b24be2017-07-12 23:23:46 -0400329 to_string(util::Sha256::DIGEST_SIZE) + " octets)"));
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700330
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700331 return makeBinaryBlock(tlv::ImplicitSha256DigestComponent, digest, digestSize);
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700332}
333
334////////////////////////////////////////////////////////////////////////////////
335
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000336bool
337Component::equals(const Component& other) const
338{
339 return type() == other.type() &&
340 value_size() == other.value_size() &&
Davide Pesaventoe245b052017-10-31 13:00:44 -0400341 (empty() || // needed with Apple clang < 9.0.0 due to libc++ bug
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000342 std::equal(value_begin(), value_end(), other.value_begin()));
343}
344
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700345int
346Component::compare(const Component& other) const
347{
Junxiao Shi010f0862016-10-11 21:08:32 +0000348 if (this->hasWire() && other.hasWire()) {
349 // In the common case where both components have wire encoding,
350 // it's more efficient to simply compare the wire encoding.
351 // This works because lexical order of TLV encoding happens to be
352 // the same as canonical order of the value.
353 return std::memcmp(wire(), other.wire(), std::min(size(), other.size()));
354 }
355
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000356 int cmpType = type() - other.type();
357 if (cmpType != 0)
358 return cmpType;
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700359
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000360 int cmpSize = value_size() - other.value_size();
361 if (cmpSize != 0)
362 return cmpSize;
363
Davide Pesaventoe245b052017-10-31 13:00:44 -0400364 if (empty())
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700365 return 0;
366
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700367 return std::memcmp(value(), other.value(), value_size());
368}
369
370Component
371Component::getSuccessor() const
372{
Junxiao Shid2e60632018-08-10 10:48:44 -0600373 bool isOverflow = false;
374 Component successor;
375 std::tie(isOverflow, successor) =
376 detail::getComponentTypeTable().get(type()).getSuccessor(*this);
377 if (!isOverflow) {
378 return successor;
Junxiao Shicf0aff82018-07-23 06:42:13 -0600379 }
380
Junxiao Shid2e60632018-08-10 10:48:44 -0600381 uint32_t type = this->type() + 1;
382 const std::vector<uint8_t>& value = detail::getComponentTypeTable().get(type).getMinValue();
383 return Component(type, value.data(), value.size());
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700384}
385
Alexander Afanasyev74633892015-02-08 18:08:46 -0800386template<encoding::Tag TAG>
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700387size_t
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700388Component::wireEncode(EncodingImpl<TAG>& encoder) const
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700389{
390 size_t totalLength = 0;
391 if (value_size() > 0)
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700392 totalLength += encoder.prependByteArray(value(), value_size());
393 totalLength += encoder.prependVarNumber(value_size());
394 totalLength += encoder.prependVarNumber(type());
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700395 return totalLength;
396}
397
Davide Pesavento88a0d812017-08-19 21:31:42 -0400398NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(Component);
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700399
400const Block&
401Component::wireEncode() const
402{
403 if (this->hasWire())
404 return *this;
405
406 EncodingEstimator estimator;
407 size_t estimatedSize = wireEncode(estimator);
408
409 EncodingBuffer buffer(estimatedSize, 0);
410 wireEncode(buffer);
411
412 const_cast<Component&>(*this) = buffer.block();
413 return *this;
414}
415
416void
417Component::wireDecode(const Block& wire)
418{
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700419 *this = wire;
Qiuhan Ding2c3cbe42014-11-25 18:10:23 -0800420 // validity check is done within Component(const Block& wire)
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700421}
422
423} // namespace name
424} // namespace ndn