blob: 66cf247a6060a4fe4c416b11927390661250de0f [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 Shi4053bd52018-08-16 13:39:25 -0600310 return detail::getComponentType1().match(*this);
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700311}
312
313Component
Davide Pesavento3b101d02018-07-21 22:44:09 -0400314Component::fromImplicitSha256Digest(ConstBufferPtr digest)
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700315{
Junxiao Shi4053bd52018-08-16 13:39:25 -0600316 return detail::getComponentType1().create(digest);
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700317}
318
319Component
320Component::fromImplicitSha256Digest(const uint8_t* digest, size_t digestSize)
321{
Junxiao Shi4053bd52018-08-16 13:39:25 -0600322 return detail::getComponentType1().create(digest, digestSize);
323}
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700324
Junxiao Shi4053bd52018-08-16 13:39:25 -0600325bool
326Component::isParametersSha256Digest() const
327{
328 return detail::getComponentType2().match(*this);
329}
330
331Component
332Component::fromParametersSha256Digest(ConstBufferPtr digest)
333{
334 return detail::getComponentType2().create(digest);
335}
336
337Component
338Component::fromParametersSha256Digest(const uint8_t* digest, size_t digestSize)
339{
340 return detail::getComponentType2().create(digest, digestSize);
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700341}
342
343////////////////////////////////////////////////////////////////////////////////
344
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000345bool
346Component::equals(const Component& other) const
347{
348 return type() == other.type() &&
349 value_size() == other.value_size() &&
Davide Pesaventoe245b052017-10-31 13:00:44 -0400350 (empty() || // needed with Apple clang < 9.0.0 due to libc++ bug
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000351 std::equal(value_begin(), value_end(), other.value_begin()));
352}
353
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700354int
355Component::compare(const Component& other) const
356{
Junxiao Shi010f0862016-10-11 21:08:32 +0000357 if (this->hasWire() && other.hasWire()) {
358 // In the common case where both components have wire encoding,
359 // it's more efficient to simply compare the wire encoding.
360 // This works because lexical order of TLV encoding happens to be
361 // the same as canonical order of the value.
362 return std::memcmp(wire(), other.wire(), std::min(size(), other.size()));
363 }
364
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000365 int cmpType = type() - other.type();
366 if (cmpType != 0)
367 return cmpType;
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700368
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000369 int cmpSize = value_size() - other.value_size();
370 if (cmpSize != 0)
371 return cmpSize;
372
Davide Pesaventoe245b052017-10-31 13:00:44 -0400373 if (empty())
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700374 return 0;
375
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700376 return std::memcmp(value(), other.value(), value_size());
377}
378
379Component
380Component::getSuccessor() const
381{
Junxiao Shid2e60632018-08-10 10:48:44 -0600382 bool isOverflow = false;
383 Component successor;
384 std::tie(isOverflow, successor) =
385 detail::getComponentTypeTable().get(type()).getSuccessor(*this);
386 if (!isOverflow) {
387 return successor;
Junxiao Shicf0aff82018-07-23 06:42:13 -0600388 }
389
Junxiao Shid2e60632018-08-10 10:48:44 -0600390 uint32_t type = this->type() + 1;
391 const std::vector<uint8_t>& value = detail::getComponentTypeTable().get(type).getMinValue();
392 return Component(type, value.data(), value.size());
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700393}
394
Alexander Afanasyev74633892015-02-08 18:08:46 -0800395template<encoding::Tag TAG>
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700396size_t
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700397Component::wireEncode(EncodingImpl<TAG>& encoder) const
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700398{
399 size_t totalLength = 0;
400 if (value_size() > 0)
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700401 totalLength += encoder.prependByteArray(value(), value_size());
402 totalLength += encoder.prependVarNumber(value_size());
403 totalLength += encoder.prependVarNumber(type());
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700404 return totalLength;
405}
406
Davide Pesavento88a0d812017-08-19 21:31:42 -0400407NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(Component);
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700408
409const Block&
410Component::wireEncode() const
411{
412 if (this->hasWire())
413 return *this;
414
415 EncodingEstimator estimator;
416 size_t estimatedSize = wireEncode(estimator);
417
418 EncodingBuffer buffer(estimatedSize, 0);
419 wireEncode(buffer);
420
421 const_cast<Component&>(*this) = buffer.block();
422 return *this;
423}
424
425void
426Component::wireDecode(const Block& wire)
427{
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700428 *this = wire;
Qiuhan Ding2c3cbe42014-11-25 18:10:23 -0800429 // validity check is done within Component(const Block& wire)
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700430}
431
432} // namespace name
433} // namespace ndn