blob: 045d5f2b2512697ad771c1a5cae40b128b1add6a [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 Pesaventodd461432017-01-28 21:47:26 -05003 * Copyright (c) 2013-2017 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>
Alexander Afanasyev6486d522014-10-23 14:14:11 -070034
Alexander Afanasyev15f67312014-07-22 15:11:09 -070035namespace ndn {
36namespace name {
37
Junxiao Shic2b8d242014-11-04 08:35:29 -070038BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Component>));
39BOOST_CONCEPT_ASSERT((WireEncodable<Component>));
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070040BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer<Component>));
Junxiao Shic2b8d242014-11-04 08:35:29 -070041BOOST_CONCEPT_ASSERT((WireDecodable<Component>));
42static_assert(std::is_base_of<tlv::Error, Component::Error>::value,
43 "name::Component::Error must inherit from tlv::Error");
44
Alexander Afanasyev6486d522014-10-23 14:14:11 -070045static const std::string&
46getSha256DigestUriPrefix()
47{
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070048 static const std::string prefix{"sha256digest="};
Alexander Afanasyev6486d522014-10-23 14:14:11 -070049 return prefix;
50}
51
Alexander Afanasyev15f67312014-07-22 15:11:09 -070052Component::Component()
53 : Block(tlv::NameComponent)
54{
55}
56
57Component::Component(const Block& wire)
58 : Block(wire)
59{
Qiuhan Ding2c3cbe42014-11-25 18:10:23 -080060 if (!isGeneric() && !isImplicitSha256Digest())
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -070061 BOOST_THROW_EXCEPTION(Error("Cannot construct name::Component from not a NameComponent "
62 "or ImplicitSha256DigestComponent TLV wire block"));
Alexander Afanasyev15f67312014-07-22 15:11:09 -070063}
64
65Component::Component(const ConstBufferPtr& buffer)
66 : Block(tlv::NameComponent, buffer)
67{
68}
69
70Component::Component(const Buffer& value)
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070071 : Block(makeBinaryBlock(tlv::NameComponent, value.buf(), value.size()))
Alexander Afanasyev15f67312014-07-22 15:11:09 -070072{
73}
74
75Component::Component(const uint8_t* value, size_t valueLen)
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070076 : Block(makeBinaryBlock(tlv::NameComponent, value, valueLen))
Alexander Afanasyev15f67312014-07-22 15:11:09 -070077{
78}
79
80Component::Component(const char* str)
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070081 : Block(makeBinaryBlock(tlv::NameComponent, str, std::char_traits<char>::length(str)))
Alexander Afanasyev15f67312014-07-22 15:11:09 -070082{
83}
84
85Component::Component(const std::string& str)
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -070086 : Block(makeStringBlock(tlv::NameComponent, str))
Alexander Afanasyev15f67312014-07-22 15:11:09 -070087{
88}
89
Alexander Afanasyev15f67312014-07-22 15:11:09 -070090Component
91Component::fromEscapedString(const char* escapedString, size_t beginOffset, size_t endOffset)
92{
93 std::string trimmedString(escapedString + beginOffset, escapedString + endOffset);
Davide Pesaventodd461432017-01-28 21:47:26 -050094 boost::algorithm::trim(trimmedString);
Alexander Afanasyev15f67312014-07-22 15:11:09 -070095
Alexander Afanasyev6486d522014-10-23 14:14:11 -070096 if (trimmedString.compare(0, getSha256DigestUriPrefix().size(),
97 getSha256DigestUriPrefix()) == 0) {
Davide Pesavento10b24be2017-07-12 23:23:46 -040098 if (trimmedString.size() != getSha256DigestUriPrefix().size() + util::Sha256::DIGEST_SIZE * 2)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -070099 BOOST_THROW_EXCEPTION(Error("Cannot convert to ImplicitSha256DigestComponent"
100 "(expected sha256 in hex encoding)"));
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700101
102 try {
Alexander Afanasyev8828ca62015-07-02 13:40:09 -0700103 trimmedString.erase(0, getSha256DigestUriPrefix().size());
104 return fromImplicitSha256Digest(fromHex(trimmedString));
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700105 }
Davide Pesaventoe78eeca2017-02-23 23:22:32 -0500106 catch (const StringHelperError&) {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700107 BOOST_THROW_EXCEPTION(Error("Cannot convert to a ImplicitSha256DigestComponent (invalid hex "
108 "encoding)"));
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700109 }
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700110 }
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700111 else {
112 std::string value = unescape(trimmedString);
113
114 if (value.find_first_not_of(".") == std::string::npos) {
115 // Special case for component of only periods.
116 if (value.size() <= 2)
117 // Zero, one or two periods is illegal. Ignore this component.
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700118 BOOST_THROW_EXCEPTION(Error("Illegal URI (name component cannot be . or ..)"));
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700119 else
120 // Remove 3 periods.
121 return Component(reinterpret_cast<const uint8_t*>(&value[3]), value.size() - 3);
122 }
123 else
124 return Component(reinterpret_cast<const uint8_t*>(&value[0]), value.size());
125 }
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700126}
127
128
129void
130Component::toUri(std::ostream& result) const
131{
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700132 if (type() == tlv::ImplicitSha256DigestComponent) {
133 result << getSha256DigestUriPrefix();
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700134
Alexander Afanasyev8828ca62015-07-02 13:40:09 -0700135 printHex(result, value(), value_size(), false);
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700136 }
137 else {
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700138 const uint8_t* value = this->value();
139 size_t valueSize = value_size();
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700140
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700141 bool gotNonDot = false;
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700142 for (size_t i = 0; i < valueSize; ++i) {
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700143 if (value[i] != 0x2e) {
144 gotNonDot = true;
145 break;
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700146 }
147 }
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700148 if (!gotNonDot) {
149 // Special case for component of zero or more periods. Add 3 periods.
150 result << "...";
151 for (size_t i = 0; i < valueSize; ++i)
152 result << '.';
153 }
154 else {
155 // In case we need to escape, set to upper case hex and save the previous flags.
Davide Pesaventoe78eeca2017-02-23 23:22:32 -0500156 auto savedFlags = result.flags(std::ios::hex | std::ios::uppercase);
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700157
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700158 for (size_t i = 0; i < valueSize; ++i) {
159 uint8_t x = value[i];
160 // Check for 0-9, A-Z, a-z, (+), (-), (.), (_)
161 if ((x >= 0x30 && x <= 0x39) || (x >= 0x41 && x <= 0x5a) ||
162 (x >= 0x61 && x <= 0x7a) || x == 0x2b || x == 0x2d ||
163 x == 0x2e || x == 0x5f)
164 result << x;
165 else {
166 result << '%';
167 if (x < 16)
168 result << '0';
169 result << static_cast<uint32_t>(x);
170 }
171 }
172
173 // Restore.
Davide Pesaventoe78eeca2017-02-23 23:22:32 -0500174 result.flags(savedFlags);
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700175 }
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700176 }
177}
178
179std::string
180Component::toUri() const
181{
182 std::ostringstream os;
183 toUri(os);
184 return os.str();
185}
186
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700187////////////////////////////////////////////////////////////////////////////////
Alexander Afanasyev0f232c52014-10-23 13:07:31 -0700188
189bool
190Component::isNumber() const
191{
192 return (value_size() == 1 || value_size() == 2 ||
193 value_size() == 4 || value_size() == 8);
194}
195
196bool
197Component::isNumberWithMarker(uint8_t marker) const
198{
199 return (!empty() && value()[0] == marker &&
200 (value_size() == 2 || value_size() == 3 ||
201 value_size() == 5 || value_size() == 9));
202}
203
204bool
205Component::isVersion() const
206{
207 return isNumberWithMarker(VERSION_MARKER);
208}
209
210bool
211Component::isSegment() const
212{
213 return isNumberWithMarker(SEGMENT_MARKER);
214}
215
216bool
217Component::isSegmentOffset() const
218{
219 return isNumberWithMarker(SEGMENT_OFFSET_MARKER);
220}
221
222bool
223Component::isTimestamp() const
224{
225 return isNumberWithMarker(TIMESTAMP_MARKER);
226}
227
228bool
229Component::isSequenceNumber() const
230{
231 return isNumberWithMarker(SEQUENCE_NUMBER_MARKER);
232}
233
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700234////////////////////////////////////////////////////////////////////////////////
Alexander Afanasyev0f232c52014-10-23 13:07:31 -0700235
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700236uint64_t
237Component::toNumber() const
238{
Alexander Afanasyev0f232c52014-10-23 13:07:31 -0700239 if (!isNumber())
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700240 BOOST_THROW_EXCEPTION(Error("Name component does not have nonNegativeInteger value"));
Alexander Afanasyev0f232c52014-10-23 13:07:31 -0700241
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700242 return readNonNegativeInteger(*this);
243}
244
245uint64_t
246Component::toNumberWithMarker(uint8_t marker) const
247{
Alexander Afanasyev0f232c52014-10-23 13:07:31 -0700248 if (!isNumberWithMarker(marker))
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700249 BOOST_THROW_EXCEPTION(Error("Name component does not have the requested marker "
250 "or the value is not a nonNegativeInteger"));
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700251
252 Buffer::const_iterator valueBegin = value_begin() + 1;
253 return tlv::readNonNegativeInteger(value_size() - 1, valueBegin, value_end());
254}
255
256uint64_t
257Component::toVersion() const
258{
259 return toNumberWithMarker(VERSION_MARKER);
260}
261
262uint64_t
263Component::toSegment() const
264{
265 return toNumberWithMarker(SEGMENT_MARKER);
266}
267
268uint64_t
269Component::toSegmentOffset() const
270{
271 return toNumberWithMarker(SEGMENT_OFFSET_MARKER);
272}
273
274time::system_clock::TimePoint
275Component::toTimestamp() const
276{
277 uint64_t value = toNumberWithMarker(TIMESTAMP_MARKER);
278 return time::getUnixEpoch() + time::microseconds(value);
279}
280
281uint64_t
282Component::toSequenceNumber() const
283{
284 return toNumberWithMarker(SEQUENCE_NUMBER_MARKER);
285}
286
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700287////////////////////////////////////////////////////////////////////////////////
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700288
289Component
290Component::fromNumber(uint64_t number)
291{
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700292 return makeNonNegativeIntegerBlock(tlv::NameComponent, number);
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700293}
294
295Component
296Component::fromNumberWithMarker(uint8_t marker, uint64_t number)
297{
298 EncodingEstimator estimator;
299
300 size_t valueLength = estimator.prependNonNegativeInteger(number);
301 valueLength += estimator.prependByteArray(&marker, 1);
302 size_t totalLength = valueLength;
303 totalLength += estimator.prependVarNumber(valueLength);
304 totalLength += estimator.prependVarNumber(tlv::NameComponent);
305
306 EncodingBuffer encoder(totalLength, 0);
307 encoder.prependNonNegativeInteger(number);
308 encoder.prependByteArray(&marker, 1);
309 encoder.prependVarNumber(valueLength);
310 encoder.prependVarNumber(tlv::NameComponent);
311
312 return encoder.block();
313}
314
315Component
316Component::fromVersion(uint64_t version)
317{
318 return fromNumberWithMarker(VERSION_MARKER, version);
319}
320
321Component
322Component::fromSegment(uint64_t segmentNo)
323{
324 return fromNumberWithMarker(SEGMENT_MARKER, segmentNo);
325}
326
327Component
328Component::fromSegmentOffset(uint64_t offset)
329{
330 return fromNumberWithMarker(SEGMENT_OFFSET_MARKER, offset);
331}
332
333Component
334Component::fromTimestamp(const time::system_clock::TimePoint& timePoint)
335{
336 using namespace time;
337 uint64_t value = duration_cast<microseconds>(timePoint - getUnixEpoch()).count();
338 return fromNumberWithMarker(TIMESTAMP_MARKER, value);
339}
340
341Component
342Component::fromSequenceNumber(uint64_t seqNo)
343{
344 return fromNumberWithMarker(SEQUENCE_NUMBER_MARKER, seqNo);
345}
346
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700347////////////////////////////////////////////////////////////////////////////////
348
349bool
350Component::isGeneric() const
351{
352 return (type() == tlv::NameComponent);
353}
354
355bool
356Component::isImplicitSha256Digest() const
357{
358 return (type() == tlv::ImplicitSha256DigestComponent &&
Davide Pesavento10b24be2017-07-12 23:23:46 -0400359 value_size() == util::Sha256::DIGEST_SIZE);
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700360}
361
362Component
363Component::fromImplicitSha256Digest(const ConstBufferPtr& digest)
364{
Davide Pesavento10b24be2017-07-12 23:23:46 -0400365 if (digest->size() != util::Sha256::DIGEST_SIZE)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700366 BOOST_THROW_EXCEPTION(Error("Cannot create ImplicitSha256DigestComponent (input digest must be " +
Davide Pesavento10b24be2017-07-12 23:23:46 -0400367 to_string(util::Sha256::DIGEST_SIZE) + " octets)"));
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700368
369 return Block(tlv::ImplicitSha256DigestComponent, digest);
370}
371
372Component
373Component::fromImplicitSha256Digest(const uint8_t* digest, size_t digestSize)
374{
Davide Pesavento10b24be2017-07-12 23:23:46 -0400375 if (digestSize != util::Sha256::DIGEST_SIZE)
Davide Pesavento96b96af2015-09-19 23:00:40 +0200376 BOOST_THROW_EXCEPTION(Error("Cannot create ImplicitSha256DigestComponent (input digest must be " +
Davide Pesavento10b24be2017-07-12 23:23:46 -0400377 to_string(util::Sha256::DIGEST_SIZE) + " octets)"));
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700378
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700379 return makeBinaryBlock(tlv::ImplicitSha256DigestComponent, digest, digestSize);
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700380}
381
382////////////////////////////////////////////////////////////////////////////////
383
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000384bool
385Component::equals(const Component& other) const
386{
387 return type() == other.type() &&
388 value_size() == other.value_size() &&
389 (empty() || // needed on OSX 10.9 due to STL bug
390 std::equal(value_begin(), value_end(), other.value_begin()));
391}
392
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700393int
394Component::compare(const Component& other) const
395{
Junxiao Shi010f0862016-10-11 21:08:32 +0000396 if (this->hasWire() && other.hasWire()) {
397 // In the common case where both components have wire encoding,
398 // it's more efficient to simply compare the wire encoding.
399 // This works because lexical order of TLV encoding happens to be
400 // the same as canonical order of the value.
401 return std::memcmp(wire(), other.wire(), std::min(size(), other.size()));
402 }
403
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000404 int cmpType = type() - other.type();
405 if (cmpType != 0)
406 return cmpType;
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700407
Junxiao Shidf4b24e2016-07-14 21:41:43 +0000408 int cmpSize = value_size() - other.value_size();
409 if (cmpSize != 0)
410 return cmpSize;
411
412 if (empty()) // needed on OSX 10.9 due to STL bug
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700413 return 0;
414
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700415 return std::memcmp(value(), other.value(), value_size());
416}
417
418Component
419Component::getSuccessor() const
420{
421 size_t totalLength = 0;
422 EncodingBuffer encoder(size() + 1, 1); // + 1 in case there is an overflow
423 // in unlikely case TLV length increases,
424 // EncodingBuffer will take care of that
425
426 bool isOverflow = true;
427 size_t i = value_size();
428 for (; isOverflow && i > 0; i--) {
429 uint8_t newValue = static_cast<uint8_t>((value()[i - 1] + 1) & 0xFF);
430 totalLength += encoder.prependByte(newValue);
431 isOverflow = (newValue == 0);
432 }
433 totalLength += encoder.prependByteArray(value(), i);
434
435 if (isOverflow) {
436 // new name components has to be extended
437 totalLength += encoder.appendByte(0);
438 }
439
Davide Pesavento9bd4d982015-05-13 14:31:19 +0200440 encoder.prependVarNumber(totalLength);
441 encoder.prependVarNumber(type());
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700442
443 return encoder.block();
444}
445
446
Alexander Afanasyev74633892015-02-08 18:08:46 -0800447template<encoding::Tag TAG>
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700448size_t
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700449Component::wireEncode(EncodingImpl<TAG>& encoder) const
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700450{
451 size_t totalLength = 0;
452 if (value_size() > 0)
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700453 totalLength += encoder.prependByteArray(value(), value_size());
454 totalLength += encoder.prependVarNumber(value_size());
455 totalLength += encoder.prependVarNumber(type());
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700456 return totalLength;
457}
458
459template size_t
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700460Component::wireEncode<encoding::EncoderTag>(EncodingImpl<encoding::EncoderTag>& encoder) const;
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700461
462template size_t
Alexander Afanasyevd5c48e02015-06-24 11:58:14 -0700463Component::wireEncode<encoding::EstimatorTag>(EncodingImpl<encoding::EstimatorTag>& encoder) const;
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700464
465const Block&
466Component::wireEncode() const
467{
468 if (this->hasWire())
469 return *this;
470
471 EncodingEstimator estimator;
472 size_t estimatedSize = wireEncode(estimator);
473
474 EncodingBuffer buffer(estimatedSize, 0);
475 wireEncode(buffer);
476
477 const_cast<Component&>(*this) = buffer.block();
478 return *this;
479}
480
481void
482Component::wireDecode(const Block& wire)
483{
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700484 *this = wire;
Qiuhan Ding2c3cbe42014-11-25 18:10:23 -0800485 // validity check is done within Component(const Block& wire)
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700486}
487
488} // namespace name
489} // namespace ndn