name.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 
26 #include "ndn-cxx/name.hpp"
29 #include "ndn-cxx/util/time.hpp"
30 
31 #include <sstream>
32 #include <boost/functional/hash.hpp>
33 #include <boost/range/adaptor/reversed.hpp>
34 #include <boost/range/concepts.hpp>
35 
36 namespace ndn {
37 
38 BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Name>));
39 BOOST_CONCEPT_ASSERT((WireEncodable<Name>));
40 BOOST_CONCEPT_ASSERT((WireEncodableWithEncodingBuffer<Name>));
41 BOOST_CONCEPT_ASSERT((WireDecodable<Name>));
42 BOOST_CONCEPT_ASSERT((boost::RandomAccessIterator<Name::iterator>));
43 BOOST_CONCEPT_ASSERT((boost::RandomAccessIterator<Name::const_iterator>));
44 BOOST_CONCEPT_ASSERT((boost::RandomAccessIterator<Name::reverse_iterator>));
45 BOOST_CONCEPT_ASSERT((boost::RandomAccessIterator<Name::const_reverse_iterator>));
46 BOOST_CONCEPT_ASSERT((boost::RandomAccessRangeConcept<Name>));
47 static_assert(std::is_base_of<tlv::Error, Name::Error>::value,
48  "Name::Error must inherit from tlv::Error");
49 
50 const size_t Name::npos = std::numeric_limits<size_t>::max();
51 
52 // ---- constructors, encoding, decoding ----
53 
55  : m_wire(tlv::Name)
56 {
57 }
58 
59 Name::Name(const Block& wire)
60  : m_wire(wire)
61 {
62  m_wire.parse();
63 }
64 
65 Name::Name(const char* uri)
66  : Name(std::string(uri))
67 {
68 }
69 
70 Name::Name(std::string uri)
71 {
72  if (uri.empty())
73  return;
74 
75  size_t iColon = uri.find(':');
76  if (iColon != std::string::npos) {
77  // Make sure the colon came before a '/'.
78  size_t iFirstSlash = uri.find('/');
79  if (iFirstSlash == std::string::npos || iColon < iFirstSlash) {
80  // Omit the leading protocol such as ndn:
81  uri.erase(0, iColon + 1);
82  }
83  }
84 
85  // Trim the leading slash and possibly the authority.
86  if (uri[0] == '/') {
87  if (uri.size() >= 2 && uri[1] == '/') {
88  // Strip the authority following "//".
89  size_t iAfterAuthority = uri.find('/', 2);
90  if (iAfterAuthority == std::string::npos)
91  // Unusual case: there was only an authority.
92  return;
93  else {
94  uri.erase(0, iAfterAuthority + 1);
95  }
96  }
97  else {
98  uri.erase(0, 1);
99  }
100  }
101 
102  size_t iComponentStart = 0;
103 
104  // Unescape the components.
105  while (iComponentStart < uri.size()) {
106  size_t iComponentEnd = uri.find('/', iComponentStart);
107  if (iComponentEnd == std::string::npos)
108  iComponentEnd = uri.size();
109 
110  append(Component::fromEscapedString(&uri[0], iComponentStart, iComponentEnd));
111  iComponentStart = iComponentEnd + 1;
112  }
113 }
114 
115 template<encoding::Tag TAG>
116 size_t
118 {
119  size_t totalLength = 0;
120  for (const Component& comp : *this | boost::adaptors::reversed) {
121  totalLength += comp.wireEncode(encoder);
122  }
123 
124  totalLength += encoder.prependVarNumber(totalLength);
125  totalLength += encoder.prependVarNumber(tlv::Name);
126  return totalLength;
127 }
128 
130 
131 const Block&
133 {
134  if (m_wire.hasWire())
135  return m_wire;
136 
137  EncodingEstimator estimator;
138  size_t estimatedSize = wireEncode(estimator);
139 
140  EncodingBuffer buffer(estimatedSize, 0);
141  wireEncode(buffer);
142 
143  m_wire = buffer.block();
144  m_wire.parse();
145 
146  return m_wire;
147 }
148 
149 void
151 {
152  if (wire.type() != tlv::Name)
153  NDN_THROW(tlv::Error("Name", wire.type()));
154 
155  m_wire = wire;
156  m_wire.parse();
157 }
158 
159 Name
161 {
162  Name copiedName(*this);
163  copiedName.m_wire.resetWire();
164  copiedName.wireEncode(); // "compress" the underlying buffer
165  return copiedName;
166 }
167 
168 // ---- accessors ----
169 
170 const name::Component&
171 Name::at(ssize_t i) const
172 {
173  auto ssize = static_cast<ssize_t>(size());
174  if (i < -ssize || i >= ssize) {
175  NDN_THROW(Error("Component at offset " + to_string(i) + " does not exist (out of bounds)"));
176  }
177 
178  if (i < 0) {
179  i += ssize;
180  }
181  return static_cast<const Component&>(m_wire.elements()[static_cast<size_t>(i)]);
182 }
183 
185 Name::getSubName(ssize_t iStartComponent, size_t nComponents) const
186 {
187  PartialName result;
188 
189  if (iStartComponent < 0)
190  iStartComponent += static_cast<ssize_t>(size());
191  size_t iStart = iStartComponent < 0 ? 0 : static_cast<size_t>(iStartComponent);
192 
193  size_t iEnd = size();
194  if (nComponents != npos)
195  iEnd = std::min(size(), iStart + nComponents);
196 
197  for (size_t i = iStart; i < iEnd; ++i)
198  result.append(at(i));
199 
200  return result;
201 }
202 
203 // ---- modifiers ----
204 
205 Name&
206 Name::set(ssize_t i, const Component& component)
207 {
208  if (i < 0) {
209  i += static_cast<ssize_t>(size());
210  }
211 
212  const_cast<Block::element_container&>(m_wire.elements())[i] = component;
213  m_wire.resetWire();
214  return *this;
215 }
216 
217 Name&
218 Name::set(ssize_t i, Component&& component)
219 {
220  if (i < 0) {
221  i += static_cast<ssize_t>(size());
222  }
223 
224  const_cast<Block::element_container&>(m_wire.elements())[i] = std::move(component);
225  m_wire.resetWire();
226  return *this;
227 }
228 
229 Name&
230 Name::appendVersion(const optional<uint64_t>& version)
231 {
232  return append(Component::fromVersion(version.value_or(time::toUnixTimestamp(time::system_clock::now()).count())));
233 }
234 
235 Name&
236 Name::appendTimestamp(const optional<time::system_clock::time_point>& timestamp)
237 {
238  return append(Component::fromTimestamp(timestamp.value_or(time::system_clock::now())));
239 }
240 
241 Name&
243 {
244  if (&name == this) {
245  // Copying from this name, so need to make a copy first.
246  return append(PartialName(name));
247  }
248 
249  for (const auto& c : name) {
250  append(c);
251  }
252  return *this;
253 }
254 
255 static constexpr uint8_t SHA256_OF_EMPTY_STRING[] = {
256  0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14,
257  0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
258  0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c,
259  0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
260 };
261 
262 Name&
264 {
265  static const Component placeholder(tlv::ParametersSha256DigestComponent, SHA256_OF_EMPTY_STRING);
266  return append(placeholder);
267 }
268 
269 void
270 Name::erase(ssize_t i)
271 {
272  if (i >= 0) {
273  m_wire.erase(std::next(m_wire.elements_begin(), i));
274  }
275  else {
276  m_wire.erase(std::prev(m_wire.elements_end(), -i));
277  }
278 }
279 
280 void
282 {
283  m_wire = Block(tlv::Name);
284 }
285 
286 // ---- algorithms ----
287 
288 Name
290 {
291  if (empty()) {
292  static const Name n("/sha256digest=0000000000000000000000000000000000000000000000000000000000000000");
293  return n;
294  }
295 
296  return getPrefix(-1).append(get(-1).getSuccessor());
297 }
298 
299 bool
300 Name::isPrefixOf(const Name& other) const noexcept
301 {
302  // This name is longer than the name we are checking against.
303  if (size() > other.size())
304  return false;
305 
306  // Check if at least one of given components doesn't match.
307  for (size_t i = 0; i < size(); ++i) {
308  if (get(i) != other.get(i))
309  return false;
310  }
311 
312  return true;
313 }
314 
315 bool
316 Name::equals(const Name& other) const noexcept
317 {
318  if (size() != other.size())
319  return false;
320 
321  for (size_t i = 0; i < size(); ++i) {
322  if (get(i) != other.get(i))
323  return false;
324  }
325 
326  return true;
327 }
328 
329 int
330 Name::compare(size_t pos1, size_t count1, const Name& other, size_t pos2, size_t count2) const
331 {
332  count1 = std::min(count1, this->size() - pos1);
333  count2 = std::min(count2, other.size() - pos2);
334  size_t count = std::min(count1, count2);
335 
336  for (size_t i = 0; i < count; ++i) {
337  int comp = get(pos1 + i).compare(other.get(pos2 + i));
338  if (comp != 0) { // i-th component differs
339  return comp;
340  }
341  }
342  // [pos1, pos1+count) of this Name equals [pos2, pos2+count) of other Name
343  return count1 - count2;
344 }
345 
346 // ---- URI representation ----
347 
348 void
349 Name::toUri(std::ostream& os, name::UriFormat format) const
350 {
351  if (empty()) {
352  os << "/";
353  return;
354  }
355 
356  for (const auto& component : *this) {
357  os << "/";
358  component.toUri(os, format);
359  }
360 }
361 
362 std::string
364 {
365  std::ostringstream os;
366  toUri(os, format);
367  return os.str();
368 }
369 
370 std::istream&
371 operator>>(std::istream& is, Name& name)
372 {
373  std::string inputString;
374  is >> inputString;
375  name = Name(inputString);
376 
377  return is;
378 }
379 
380 } // namespace ndn
381 
382 namespace std {
383 
384 size_t
386 {
387  return boost::hash_range(name.wireEncode().begin(), name.wireEncode().end());
388 }
389 
390 } // namespace std
Represents a TLV element of the NDN packet format.
Definition: block.hpp:45
element_const_iterator elements_begin() const noexcept
Equivalent to elements().begin().
Definition: block.hpp:435
element_iterator erase(element_const_iterator position)
Erase a sub-element.
Definition: block.cpp:441
const element_container & elements() const noexcept
Get container of sub-elements.
Definition: block.hpp:426
element_const_iterator elements_end() const noexcept
Equivalent to elements().end().
Definition: block.hpp:444
bool hasWire() const noexcept
Check if the Block contains a fully encoded wire representation.
Definition: block.hpp:221
void resetWire() noexcept
Reset wire buffer but keep TLV-TYPE and sub-elements (if any)
Definition: block.cpp:260
uint32_t type() const noexcept
Return the TLV-TYPE of the Block.
Definition: block.hpp:277
std::vector< Block > element_container
Definition: block.hpp:49
void parse() const
Parse TLV-VALUE into sub-elements.
Definition: block.cpp:324
Represents an absolute name.
Definition: name.hpp:44
bool equals(const Name &other) const noexcept
Check if this name equals another name.
Definition: name.cpp:316
name::Component::Error Error
Definition: name.hpp:46
Name & set(ssize_t i, const Component &component)
Replace the component at the specified index.
Definition: name.cpp:206
Name getSuccessor() const
Get the successor of a name.
Definition: name.cpp:289
PartialName getPrefix(ssize_t nComponents) const
Returns a prefix of the name.
Definition: name.hpp:216
Name & appendTimestamp(const optional< time::system_clock::time_point > &timestamp=nullopt)
Append a timestamp component.
Definition: name.cpp:236
int compare(const Name &other) const
Compare this to the other Name using NDN canonical ordering.
Definition: name.hpp:638
Name & appendParametersSha256DigestPlaceholder()
Append a placeholder for a ParametersSha256Digest component.
Definition: name.cpp:263
size_t size() const noexcept
Returns the number of components.
Definition: name.hpp:155
Name & appendVersion(const optional< uint64_t > &version=nullopt)
Append a version component.
Definition: name.cpp:230
bool empty() const noexcept
Checks if the name is empty, i.e., has no components.
Definition: name.hpp:146
void clear()
Remove all components.
Definition: name.cpp:281
Name & append(const Component &component)
Append a name component.
Definition: name.hpp:283
Name()
Create an empty name.
Definition: name.cpp:54
const Component & at(ssize_t i) const
Returns an immutable reference to the component at the specified index, with bounds checking.
Definition: name.cpp:171
static const size_t npos
Indicates "until the end" in getSubName() and compare().
Definition: name.hpp:707
size_t wireEncode(EncodingImpl< TAG > &encoder) const
Fast encoding or block size estimation.
Definition: name.cpp:117
Name deepCopy() const
Make a deep copy of the name, reallocating the underlying memory buffer.
Definition: name.cpp:160
const Block & wireEncode() const
Perform wire encoding, or return existing wire encoding.
Definition: name.cpp:132
PartialName getSubName(ssize_t iStartComponent, size_t nComponents=npos) const
Extracts some components as a sub-name (PartialName).
Definition: name.cpp:185
void erase(ssize_t i)
Erase the component at the specified index.
Definition: name.cpp:270
void toUri(std::ostream &os, name::UriFormat format=name::UriFormat::DEFAULT) const
Write URI representation of the name to the output stream.
Definition: name.cpp:349
bool isPrefixOf(const Name &other) const noexcept
Check if this name is a prefix of another name.
Definition: name.cpp:300
void wireDecode(const Block &wire)
Decode name from wire encoding.
Definition: name.cpp:150
const Component & get(ssize_t i) const noexcept
Returns an immutable reference to the component at the specified index.
Definition: name.hpp:167
Represents a name component.
static Component fromEscapedString(const char *input, size_t beginOffset, size_t endOffset)
Decode NameComponent from a URI component.
static Component fromTimestamp(const time::system_clock::time_point &timePoint)
Create a timestamp component using NDN naming conventions.
static Component fromVersion(uint64_t version)
Create a version component using NDN naming conventions.
int compare(const Component &other) const
Compare this to the other Component using NDN canonical ordering.
static time_point now() noexcept
Definition: time.cpp:46
Represents an error in TLV encoding or decoding.
Definition: tlv.hpp:54
#define NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(ClassName)
#define NDN_THROW(e)
Definition: exception.hpp:61
EncodingImpl< EstimatorTag > EncodingEstimator
EncodingImpl< EncoderTag > EncodingBuffer
std::string to_string(const errinfo_stacktrace &x)
Definition: exception.cpp:31
UriFormat
Format used for the URI representation of a name.
milliseconds toUnixTimestamp(const system_clock::time_point &point)
Convert system_clock::time_point to UNIX timestamp.
Definition: time.cpp:113
@ Name
Definition: tlv.hpp:71
@ ParametersSha256DigestComponent
Definition: tlv.hpp:74
Definition: data.cpp:25
Name PartialName
Represents an arbitrary sequence of name components.
Definition: name.hpp:37
std::istream & operator>>(std::istream &is, Name &name)
Parse URI from stream as Name.
Definition: name.cpp:371
size_t operator()(const ndn::Name &name) const
Definition: name.cpp:385