NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.5: NDN, CCN, CCNx, content centric networks
API Documentation
name-component.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2013-2022 Regents of the University of California.
4  *
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 
28 
29 #include <cstdlib>
30 #include <cstring>
31 #include <sstream>
32 
33 #include <boost/logic/tribool.hpp>
34 
35 namespace ndn {
36 namespace name {
37 
38 BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Component>));
39 BOOST_CONCEPT_ASSERT((WireEncodable<Component>));
41 BOOST_CONCEPT_ASSERT((WireDecodable<Component>));
43  "name::Component::Error must inherit from tlv::Error");
44 
47 
50 {
51  return g_conventionEncoding;
52 }
53 
54 void
56 {
57  switch (convention) {
58  case Convention::MARKER:
59  case Convention::TYPED:
60  g_conventionEncoding = convention;
61  break;
62  default:
63  NDN_THROW(std::invalid_argument("Unknown naming convention"));
64  }
65 }
66 
69 {
70  return g_conventionDecoding;
71 }
72 
73 void
75 {
76  g_conventionDecoding = convention;
77 }
78 
79 static bool
81 {
82  return (to_underlying(g_conventionDecoding) & to_underlying(Convention::MARKER)) != 0;
83 }
84 
85 static bool
87 {
88  return (to_underlying(g_conventionDecoding) & to_underlying(Convention::TYPED)) != 0;
89 }
90 
91 static bool
93 {
94  static const auto wantAltEnv = []() -> boost::tribool {
95  const char* env = std::getenv("NDN_NAME_ALT_URI");
96  if (env == nullptr)
97  return boost::indeterminate;
98  else if (env[0] == '0')
99  return false;
100  else if (env[0] == '1')
101  return true;
102  else
103  return boost::indeterminate;
104  }();
105 
106  if (format == UriFormat::ENV_OR_CANONICAL) {
107  static const bool wantAlt = boost::indeterminate(wantAltEnv) ? false : bool(wantAltEnv);
108  return wantAlt;
109  }
110  else if (format == UriFormat::ENV_OR_ALTERNATE) {
111  static const bool wantAlt = boost::indeterminate(wantAltEnv) ? true : bool(wantAltEnv);
112  return wantAlt;
113  }
114  else {
115  return format == UriFormat::ALTERNATE;
116  }
117 }
118 
119 void
120 Component::ensureValid() const
121 {
123  NDN_THROW(Error("TLV-TYPE " + to_string(type()) + " is not a valid NameComponent"));
124  }
125  getComponentTypeTable().get(type()).check(*this);
126 }
127 
129  : Block(type)
130 {
131  ensureValid();
132 }
133 
135  : Block(wire)
136 {
137  ensureValid();
138 }
139 
141  : Block(type, std::move(buffer))
142 {
143  ensureValid();
144 }
145 
146 Component::Component(uint32_t type, span<const uint8_t> value)
147  : Block(makeBinaryBlock(type, value))
148 {
149  ensureValid();
150 }
151 
152 Component::Component(const char* str)
153  : Block(makeBinaryBlock(tlv::GenericNameComponent, str, std::char_traits<char>::length(str)))
154 {
155 }
156 
157 Component::Component(const std::string& str)
159 {
160 }
161 
162 static Component
163 parseUriEscapedValue(uint32_t type, const char* input, size_t len)
164 {
165  std::ostringstream oss;
166  unescape(oss, input, len);
167  std::string value = oss.str();
168  if (value.find_first_not_of('.') == std::string::npos) { // all periods
169  if (value.size() < 3) {
170  NDN_THROW(Component::Error("Illegal URI (name component cannot be . or ..)"));
171  }
172  return Component(type, {reinterpret_cast<const uint8_t*>(value.data()), value.size() - 3});
173  }
174  return Component(type, {reinterpret_cast<const uint8_t*>(value.data()), value.size()});
175 }
176 
177 Component
178 Component::fromEscapedString(const std::string& input)
179 {
180  size_t equalPos = input.find('=');
181  if (equalPos == std::string::npos) {
182  return parseUriEscapedValue(tlv::GenericNameComponent, input.data(), input.size());
183  }
184 
185  auto typePrefix = input.substr(0, equalPos);
186  auto type = std::strtoul(typePrefix.data(), nullptr, 10);
188  to_string(type) == typePrefix) {
189  size_t valuePos = equalPos + 1;
190  return parseUriEscapedValue(static_cast<uint32_t>(type),
191  input.data() + valuePos, input.size() - valuePos);
192  }
193 
194  auto ct = getComponentTypeTable().findByUriPrefix(typePrefix);
195  if (ct == nullptr) {
196  NDN_THROW(Error("Unknown TLV-TYPE '" + typePrefix + "' in NameComponent URI"));
197  }
198  return ct->parseAltUriValue(input.substr(equalPos + 1));
199 }
200 
201 void
202 Component::toUri(std::ostream& os, UriFormat format) const
203 {
204  if (wantAltUri(format)) {
205  getComponentTypeTable().get(type()).writeUri(os, *this);
206  }
207  else {
208  ComponentType().writeUri(os, *this);
209  }
210 }
211 
212 std::string
214 {
215  std::ostringstream os;
216  toUri(os, format);
217  return os.str();
218 }
219 
221 
222 bool
224 {
225  return value_size() == 1 || value_size() == 2 ||
226  value_size() == 4 || value_size() == 8;
227 }
228 
229 bool
230 Component::isNumberWithMarker(uint8_t marker) const
231 {
232  return (value_size() == 2 || value_size() == 3 ||
233  value_size() == 5 || value_size() == 9) && value()[0] == marker;
234 }
235 
236 bool
238 {
241 }
242 
243 bool
245 {
248 }
249 
250 bool
252 {
255 }
256 
257 bool
259 {
262 }
263 
264 bool
266 {
269 }
270 
272 
273 uint64_t
275 {
276  if (!isNumber())
277  NDN_THROW(Error("Name component does not have NonNegativeInteger value"));
278 
279  return readNonNegativeInteger(*this);
280 }
281 
282 uint64_t
283 Component::toNumberWithMarker(uint8_t marker) const
284 {
285  if (!isNumberWithMarker(marker))
286  NDN_THROW(Error("Name component does not have the requested marker "
287  "or the value is not a NonNegativeInteger"));
288 
289  auto valueBegin = value_begin() + 1;
290  return tlv::readNonNegativeInteger(value_size() - 1, valueBegin, value_end());
291 }
292 
293 uint64_t
295 {
298  }
300  return toNumber();
301  }
302  NDN_THROW(Error("Not a Segment component"));
303 }
304 
305 uint64_t
307 {
310  }
312  return toNumber();
313  }
314  NDN_THROW(Error("Not a ByteOffset component"));
315 }
316 
317 uint64_t
319 {
322  }
324  return toNumber();
325  }
326  NDN_THROW(Error("Not a Version component"));
327 }
328 
331 {
332  uint64_t value = 0;
335  }
337  value = toNumber();
338  }
339  else {
340  NDN_THROW(Error("Not a Timestamp component"));
341  }
342  return time::getUnixEpoch() + time::microseconds(value);
343 }
344 
345 uint64_t
347 {
350  }
352  return toNumber();
353  }
354  NDN_THROW(Error("Not a SequenceNumber component"));
355 }
356 
358 
359 Component
360 Component::fromNumber(uint64_t number, uint32_t type)
361 {
362  return Component(makeNonNegativeIntegerBlock(type, number));
363 }
364 
365 Component
366 Component::fromNumberWithMarker(uint8_t marker, uint64_t number)
367 {
368  EncodingEstimator estimator;
369  size_t valueLength = estimator.prependNonNegativeInteger(number);
370  valueLength += estimator.prependBytes({marker});
371  size_t totalLength = valueLength;
372  totalLength += estimator.prependVarNumber(valueLength);
373  totalLength += estimator.prependVarNumber(tlv::GenericNameComponent);
374 
375  EncodingBuffer encoder(totalLength, 0);
376  encoder.prependNonNegativeInteger(number);
377  encoder.prependBytes({marker});
378  encoder.prependVarNumber(valueLength);
379  encoder.prependVarNumber(tlv::GenericNameComponent);
380 
381  return Component(encoder.block());
382 }
383 
384 Component
385 Component::fromSegment(uint64_t segmentNo)
386 {
387  return g_conventionEncoding == Convention::MARKER ?
390 }
391 
392 Component
394 {
395  return g_conventionEncoding == Convention::MARKER ?
398 }
399 
400 Component
402 {
403  return g_conventionEncoding == Convention::MARKER ?
406 }
407 
408 Component
410 {
411  uint64_t value = time::duration_cast<time::microseconds>(timePoint - time::getUnixEpoch()).count();
412  return g_conventionEncoding == Convention::MARKER ?
415 }
416 
417 Component
419 {
420  return g_conventionEncoding == Convention::MARKER ?
423 }
424 
426 
427 bool
429 {
431 }
432 
433 Component
435 {
437 }
438 
439 Component
440 Component::fromImplicitSha256Digest(span<const uint8_t> digest)
441 {
442  return {tlv::ImplicitSha256DigestComponent, digest};
443 }
444 
445 bool
447 {
449 }
450 
451 Component
453 {
455 }
456 
457 Component
458 Component::fromParametersSha256Digest(span<const uint8_t> digest)
459 {
460  return {tlv::ParametersSha256DigestComponent, digest};
461 }
462 
464 
465 bool
466 Component::equals(const Component& other) const
467 {
468  return type() == other.type() &&
469  value_size() == other.value_size() &&
470  std::equal(value_begin(), value_end(), other.value_begin());
471 }
472 
473 int
474 Component::compare(const Component& other) const
475 {
476  if (this->hasWire() && other.hasWire()) {
477  // In the common case where both components have wire encoding,
478  // it's more efficient to simply compare the wire encoding.
479  // This works because lexical order of TLV encoding happens to be
480  // the same as canonical order of the value.
481  return std::memcmp(data(), other.data(), std::min(size(), other.size()));
482  }
483 
484  int cmpType = type() - other.type();
485  if (cmpType != 0)
486  return cmpType;
487 
488  int cmpSize = value_size() - other.value_size();
489  if (cmpSize != 0)
490  return cmpSize;
491 
492  if (empty())
493  return 0;
494 
495  return std::memcmp(value(), other.value(), value_size());
496 }
497 
498 Component
500 {
501  bool isOverflow = false;
502  Component successor;
503  std::tie(isOverflow, successor) = getComponentTypeTable().get(type()).getSuccessor(*this);
504  if (!isOverflow) {
505  return successor;
506  }
507 
508  uint32_t type = this->type() + 1;
509  auto value = getComponentTypeTable().get(type).getMinValue();
510  return {type, value};
511 }
512 
513 template<encoding::Tag TAG>
514 size_t
516 {
517  size_t totalLength = 0;
518  if (value_size() > 0) {
519  totalLength += encoder.prependBytes(value_bytes());
520  }
521  totalLength += encoder.prependVarNumber(value_size());
522  totalLength += encoder.prependVarNumber(type());
523  return totalLength;
524 }
525 
527 
528 const Block&
530 {
531  if (this->hasWire())
532  return *this;
533 
534  EncodingEstimator estimator;
535  size_t estimatedSize = wireEncode(estimator);
536 
537  EncodingBuffer buffer(estimatedSize, 0);
538  wireEncode(buffer);
539 
540  const_cast<Component*>(this)->wireDecode(buffer.block());
541  return *this;
542 }
543 
544 void
546 {
547  *this = Component(wire);
548  // validity check is done within Component(const Block& wire)
549 }
550 
551 } // namespace name
552 } // namespace ndn
static Component fromParametersSha256Digest(ConstBufferPtr digest)
Create ParametersSha256DigestComponent component.
void setConventionDecoding(Convention convention)
Set which Naming Conventions style(s) to accept while decoding.
static Component fromSequenceNumber(uint64_t seqNo)
Create a sequence number component using NDN naming conventions.
Same as UriFormat::CANONICAL, unless NDN_NAME_ALT_URI environment variable is set to &#39;1&#39;...
Copyright (c) 2011-2015 Regents of the University of California.
bool isSequenceNumber() const
Check if the component is a sequence number per NDN naming conventions.
static Convention g_conventionEncoding
uint64_t toSequenceNumber() const
Interpret as sequence number component using NDN naming conventions.
static Component fromNumberWithMarker(uint8_t marker, uint64_t number)
Create a component encoded as NameComponentWithMarker.
constexpr size_t prependNonNegativeInteger(uint64_t n) const noexcept
Prepend n in NonNegativeInteger encoding.
Definition: estimator.hpp:100
UriFormat
Format used for the URI representation of a name.
std::string to_string(const T &val)
Definition: backports.hpp:86
static bool canDecodeMarkerConvention()
static const size_t DIGEST_SIZE
Length in bytes of a SHA-256 digest.
Definition: sha256.hpp:56
boost::chrono::time_point< system_clock > time_point
Definition: time.hpp:200
bool isByteOffset() const
Check if the component is a byte offset per NDN naming conventions.
Component(uint32_t type=tlv::GenericNameComponent)
Construct a NameComponent of TLV-TYPE type and with empty TLV-VALUE.
bool isNumberWithMarker(uint8_t marker) const
Check if the component is a NameComponentWithMarker per NDN naming conventions rev1.
const_iterator value_begin() const noexcept
Get begin iterator of TLV-VALUE.
Definition: block.hpp:301
boost::chrono::microseconds microseconds
Definition: time.hpp:49
Same as UriFormat::ALTERNATE, unless NDN_NAME_ALT_URI environment variable is set to &#39;0&#39;...
STL namespace.
size_t value_size() const noexcept
Return the size of TLV-VALUE, i.e., the TLV-LENGTH.
Definition: block.hpp:321
NDN_CXX_NODISCARD bool empty() const
static Convention g_conventionDecoding
void setConventionEncoding(Convention convention)
Set which Naming Conventions style to use while encoding.
Represents a TLV element of the NDN packet format.
Definition: block.hpp:44
uint64_t readNonNegativeInteger(size_t size, Iterator &begin, Iterator end)
Read a NonNegativeInteger in NDN-TLV encoding.
Definition: tlv.hpp:490
bool hasWire() const noexcept
Check if the Block contains a fully encoded wire representation.
Definition: block.hpp:221
const uint8_t * wire() const
Definition: block.hpp:250
int compare(const Component &other) const
Compare this to the other Component using NDN canonical ordering.
Block makeNonNegativeIntegerBlock(uint32_t type, uint64_t value)
Create a TLV block containing a non-negative integer.
uint64_t readNonNegativeInteger(const Block &block)
Read a non-negative integer from a TLV element.
#define NDN_THROW(e)
Definition: exception.hpp:61
Typed name components (revision 3)
bool isNumber() const
Check if the component is a NonNegativeInteger.
time::system_clock::time_point toTimestamp() const
Interpret as timestamp component using NDN naming conventions.
bool isParametersSha256Digest() const
Check if the component is a ParametersSha256DigestComponent.
static Component fromSegment(uint64_t segmentNo)
Create a segment number component using NDN naming conventions.
Component getSuccessor() const
Get the successor of this name component.
a concept check for TLV abstraction with .wireEncode method
Definition: concepts.hpp:60
Convention getConventionDecoding()
Return which Naming Conventions style(s) to accept while decoding.
size_t size() const
Return the size of the encoded wire, i.e., of the whole TLV.
Definition: block.cpp:294
NDN_CXX_NODISCARD constexpr std::underlying_type_t< T > to_underlying(T val) noexcept
Definition: backports.hpp:125
const uint8_t * data() const
Return a raw pointer to the beginning of the encoded wire.
Definition: block.cpp:285
const Block & get(uint32_t type) const
Return the first sub-element of the specified TLV-TYPE.
Definition: block.cpp:412
element_const_iterator find(uint32_t type) const
Find the first sub-element of the specified TLV-TYPE.
Definition: block.cpp:424
static Component fromByteOffset(uint64_t offset)
Create a byte offset component using NDN naming conventions.
static Component fromEscapedString(const char *input, size_t beginOffset, size_t endOffset)
Decode NameComponent from a URI component.
bool isSegment() const
Check if the component is a segment number per NDN naming conventions.
static bool canDecodeTypedConvention()
Block makeStringBlock(uint32_t type, const std::string &value)
Create a TLV block containing a string.
const system_clock::time_point & getUnixEpoch()
Return a system_clock::time_point representing the UNIX time epoch, i.e., 00:00:00 UTC on 1 January 1...
Definition: time.cpp:106
bool isImplicitSha256Digest() const
Check if the component is an ImplicitSha256DigestComponent.
bool equals(const Component &other) const
Check if this is the same component as other.
const Block & wireEncode() const
Encode to a wire format.
Always prefer the alternate format when available.
Block makeBinaryBlock(uint32_t type, span< const uint8_t > value)
Create a TLV block copying the TLV-VALUE from a byte range.
uint64_t toNumber() const
Interpret this name component as a NonNegativeInteger.
static Component parseUriEscapedValue(uint32_t type, const char *input, size_t len)
const uint8_t * value() const noexcept
Return a raw pointer to the beginning of TLV-VALUE.
Definition: block.cpp:306
span< const uint8_t > value_bytes() const noexcept
Return a read-only view of TLV-VALUE as a contiguous range of bytes.
Definition: block.hpp:330
Represents a name component.
void wireDecode(const Block &wire)
Decode from the wire format.
uint64_t toVersion() const
Interpret as version component using NDN naming conventions.
uint32_t type() const noexcept
Return the TLV-TYPE of the Block.
Definition: block.hpp:277
static Component fromTimestamp(const time::system_clock::time_point &timePoint)
Create a timestamp component using NDN naming conventions.
uint64_t toSegment() const
Interpret as segment number component using NDN naming conventions.
static Component fromNumber(uint64_t number, uint32_t type=tlv::GenericNameComponent)
Create a component encoded as NonNegativeInteger.
Component markers (revision 1)
NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(Component)
bool isTimestamp() const
Check if the component is a timestamp per NDN naming conventions.
Convention getConventionEncoding()
Return which Naming Conventions style to use while encoding.
static Component fromVersion(uint64_t version)
Create a version component using NDN naming conventions.
const_iterator value_end() const noexcept
Get end iterator of TLV-VALUE.
Definition: block.hpp:311
uint64_t toNumberWithMarker(uint8_t marker) const
Interpret this name component as a NameComponentWithMarker.
Convention
Identify a style of NDN Naming Conventions.
bool isVersion() const
Check if the component is a version per NDN naming conventions.
uint64_t toByteOffset() const
Interpret as byte offset component using NDN naming conventions.
static bool wantAltUri(UriFormat format)
static Component fromImplicitSha256Digest(ConstBufferPtr digest)
Create ImplicitSha256DigestComponent component.
a concept check for TLV abstraction with .wireEncode method
Definition: concepts.hpp:44
a concept check for TLV abstraction with .wireDecode method and constructible from Block ...
Definition: concepts.hpp:80
void toUri(std::ostream &os, UriFormat format=UriFormat::DEFAULT) const
Write *this to the output stream, escaping characters according to the NDN URI format.
EncodingImpl< EncoderTag > EncodingBuffer
std::string unescape(const std::string &str)
Decode a percent-encoded string.
EncodingImpl< EstimatorTag > EncodingEstimator
shared_ptr< const Buffer > ConstBufferPtr
Definition: buffer.hpp:139