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-2020 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 
27 #include "ndn-cxx/impl/name-component-types.hpp"
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>));
40 BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer<Component>));
41 BOOST_CONCEPT_ASSERT((WireDecodable<Component>));
42 static_assert(std::is_base_of<tlv::Error, Component::Error>::value,
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  detail::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, const uint8_t* value, size_t valueLen)
147  : Block(makeBinaryBlock(type, value, valueLen))
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 = detail::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  detail::getComponentTypeTable().get(type()).writeUri(os, *this);
206  }
207  else {
208  detail::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  Buffer::const_iterator 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 Version component"));
303 }
304 
305 uint64_t
307 {
310  }
312  return toNumber();
313  }
314  NDN_THROW(Error("Not a Segment component"));
315 }
316 
317 uint64_t
319 {
322  }
324  return toNumber();
325  }
326  NDN_THROW(Error("Not a ByteOffset 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 makeNonNegativeIntegerBlock(type, number);
363 }
364 
365 Component
366 Component::fromNumberWithMarker(uint8_t marker, uint64_t number)
367 {
368  EncodingEstimator estimator;
369 
370  size_t valueLength = estimator.prependNonNegativeInteger(number);
371  valueLength += estimator.prependByteArray(&marker, 1);
372  size_t totalLength = valueLength;
373  totalLength += estimator.prependVarNumber(valueLength);
374  totalLength += estimator.prependVarNumber(tlv::GenericNameComponent);
375 
376  EncodingBuffer encoder(totalLength, 0);
377  encoder.prependNonNegativeInteger(number);
378  encoder.prependByteArray(&marker, 1);
379  encoder.prependVarNumber(valueLength);
380  encoder.prependVarNumber(tlv::GenericNameComponent);
381 
382  return encoder.block();
383 }
384 
385 Component
386 Component::fromVersion(uint64_t version)
387 {
388  return g_conventionEncoding == Convention::MARKER ?
391 }
392 
393 Component
394 Component::fromSegment(uint64_t segmentNo)
395 {
396  return g_conventionEncoding == Convention::MARKER ?
399 }
400 
401 Component
403 {
404  return g_conventionEncoding == Convention::MARKER ?
407 }
408 
409 Component
411 {
412  uint64_t value = time::duration_cast<time::microseconds>(timePoint - time::getUnixEpoch()).count();
413  return g_conventionEncoding == Convention::MARKER ?
416 }
417 
418 Component
420 {
421  return g_conventionEncoding == Convention::MARKER ?
424 }
425 
427 
428 bool
430 {
431  return type() == tlv::GenericNameComponent;
432 }
433 
434 bool
436 {
437  return detail::getComponentType1().match(*this);
438 }
439 
440 Component
442 {
443  return detail::getComponentType1().create(digest);
444 }
445 
446 Component
447 Component::fromImplicitSha256Digest(const uint8_t* digest, size_t digestSize)
448 {
449  return detail::getComponentType1().create(digest, digestSize);
450 }
451 
452 bool
454 {
455  return detail::getComponentType2().match(*this);
456 }
457 
458 Component
460 {
461  return detail::getComponentType2().create(digest);
462 }
463 
464 Component
465 Component::fromParametersSha256Digest(const uint8_t* digest, size_t digestSize)
466 {
467  return detail::getComponentType2().create(digest, digestSize);
468 }
469 
471 
472 bool
473 Component::equals(const Component& other) const
474 {
475  return type() == other.type() &&
476  value_size() == other.value_size() &&
477  std::equal(value_begin(), value_end(), other.value_begin());
478 }
479 
480 int
481 Component::compare(const Component& other) const
482 {
483  if (this->hasWire() && other.hasWire()) {
484  // In the common case where both components have wire encoding,
485  // it's more efficient to simply compare the wire encoding.
486  // This works because lexical order of TLV encoding happens to be
487  // the same as canonical order of the value.
488  return std::memcmp(wire(), other.wire(), std::min(size(), other.size()));
489  }
490 
491  int cmpType = type() - other.type();
492  if (cmpType != 0)
493  return cmpType;
494 
495  int cmpSize = value_size() - other.value_size();
496  if (cmpSize != 0)
497  return cmpSize;
498 
499  if (empty())
500  return 0;
501 
502  return std::memcmp(value(), other.value(), value_size());
503 }
504 
505 Component
507 {
508  bool isOverflow = false;
509  Component successor;
510  std::tie(isOverflow, successor) =
511  detail::getComponentTypeTable().get(type()).getSuccessor(*this);
512  if (!isOverflow) {
513  return successor;
514  }
515 
516  uint32_t type = this->type() + 1;
517  const std::vector<uint8_t>& value = detail::getComponentTypeTable().get(type).getMinValue();
518  return Component(type, value.data(), value.size());
519 }
520 
521 template<encoding::Tag TAG>
522 size_t
524 {
525  size_t totalLength = 0;
526  if (value_size() > 0)
527  totalLength += encoder.prependByteArray(value(), value_size());
528  totalLength += encoder.prependVarNumber(value_size());
529  totalLength += encoder.prependVarNumber(type());
530  return totalLength;
531 }
532 
534 
535 const Block&
537 {
538  if (this->hasWire())
539  return *this;
540 
541  EncodingEstimator estimator;
542  size_t estimatedSize = wireEncode(estimator);
543 
544  EncodingBuffer buffer(estimatedSize, 0);
545  wireEncode(buffer);
546 
547  const_cast<Component&>(*this) = buffer.block();
548  return *this;
549 }
550 
551 void
553 {
554  *this = wire;
555  // validity check is done within Component(const Block& wire)
556 }
557 
558 } // namespace name
559 } // 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 sequence number component using NDN naming conventions.
Same as UriFormat::CANONICAL, unless NDN_NAME_ALT_URI environment variable is set to &#39;1&#39;...
Definition: data.cpp:26
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.
UriFormat
Format used for the URI representation of a name.
std::string to_string(const T &val)
Definition: backports.hpp:101
static bool canDecodeMarkerConvention()
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, using empty TLV-VALUE.
bool isNumberWithMarker(uint8_t marker) const
Check if the component is a NameComponentWithMarker per NDN naming conventions rev1.
static Component fromTimestamp(const time::system_clock::TimePoint &timePoint)
Create sequence number component using NDN naming conventions.
const uint8_t * wire() const
Return a raw pointer to the beginning of the encoded wire.
Definition: block.cpp:281
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, aka TLV-LENGTH.
Definition: block.cpp:308
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:42
uint64_t readNonNegativeInteger(size_t size, Iterator &begin, Iterator end)
Read nonNegativeInteger in NDN-TLV encoding.
Definition: tlv.hpp:489
bool hasWire() const noexcept
Check if the Block contains a fully encoded wire representation.
Definition: block.hpp:217
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 2)
bool isNumber() const
Check if the component is a nonNegativeInteger.
Buffer::const_iterator value_begin() const
Get begin iterator of TLV-VALUE.
Definition: block.hpp:283
bool isParametersSha256Digest() const
Check if the component is ParametersSha256DigestComponent.
static Component fromSegment(uint64_t segmentNo)
Create 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.
Definition: block.cpp:290
const Block & get(uint32_t type) const
Return the first sub-element of the specified TLV-TYPE.
Definition: block.cpp:414
element_const_iterator find(uint32_t type) const
Find the first sub-element of the specified TLV-TYPE.
Definition: block.cpp:426
static Component fromByteOffset(uint64_t offset)
Create 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.
Block makeBinaryBlock(uint32_t type, const uint8_t *value, size_t length)
Create a TLV block copying TLV-VALUE from raw buffer.
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.
Buffer::const_iterator value_end() const
Get end iterator of TLV-VALUE.
Definition: block.hpp:292
#define NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(ClassName)
std::string unescape(const std::string &str)
Decode a percent-encoded string.
bool isImplicitSha256Digest() const
Check if the component is 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.
uint64_t toNumber() const
Interpret this name component as nonNegativeInteger.
time_point TimePoint
Definition: time.hpp:195
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:302
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.
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)
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 version component using NDN naming conventions.
uint64_t toNumberWithMarker(uint8_t marker) const
Interpret this name component as NameComponentWithMarker.
bool isGeneric() const
Check if the component is GenericComponent.
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.
time::system_clock::TimePoint toTimestamp() const
Interpret as timestamp component using NDN naming conventions.
a concept check for TLV abstraction with .wireEncode method
Definition: concepts.hpp:44
constexpr std::underlying_type_t< T > to_underlying(T val) noexcept
Definition: backports.hpp:140
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
uint32_t type() const
Return the TLV-TYPE of the Block.
Definition: block.hpp:261
const system_clock::TimePoint & getUnixEpoch()
Get system_clock::TimePoint representing UNIX time epoch (00:00:00 on Jan 1, 1970) ...
Definition: time.cpp:106
size_t prependNonNegativeInteger(uint64_t integer) const noexcept
Prepend non-negative integer integer of NDN TLV encoding.
Definition: estimator.cpp:51
EncodingImpl< EstimatorTag > EncodingEstimator
shared_ptr< const Buffer > ConstBufferPtr
Definition: buffer.hpp:126