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-2021 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  if (i < 0) {
174  i += static_cast<ssize_t>(size());
175  }
176 
177  if (i < 0 || static_cast<size_t>(i) >= size()) {
178  NDN_THROW(Error("Requested component does not exist (out of bounds)"));
179  }
180 
181  return reinterpret_cast<const Component&>(m_wire.elements()[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  for (size_t i = 0; i < name.size(); ++i)
249  append(name.at(i));
250 
251  return *this;
252 }
253 
254 static constexpr uint8_t SHA256_OF_EMPTY_STRING[] = {
255  0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14,
256  0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
257  0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c,
258  0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
259 };
260 
261 Name&
263 {
264  static const Component placeholder(tlv::ParametersSha256DigestComponent,
265  SHA256_OF_EMPTY_STRING, sizeof(SHA256_OF_EMPTY_STRING));
266  return append(placeholder);
267 }
268 
269 void
270 Name::erase(ssize_t i)
271 {
272  if (i < 0) {
273  i += static_cast<ssize_t>(size());
274  }
275 
276  m_wire.erase(m_wire.elements_begin() + i);
277 }
278 
279 void
281 {
282  m_wire = Block(tlv::Name);
283 }
284 
285 // ---- algorithms ----
286 
287 Name
289 {
290  if (empty()) {
291  static const Name n("/sha256digest=0000000000000000000000000000000000000000000000000000000000000000");
292  return n;
293  }
294 
295  return getPrefix(-1).append(get(-1).getSuccessor());
296 }
297 
298 bool
299 Name::isPrefixOf(const Name& other) const
300 {
301  // This name is longer than the name we are checking against.
302  if (size() > other.size())
303  return false;
304 
305  // Check if at least one of given components doesn't match.
306  for (size_t i = 0; i < size(); ++i) {
307  if (get(i) != other.get(i))
308  return false;
309  }
310 
311  return true;
312 }
313 
314 bool
315 Name::equals(const Name& other) const
316 {
317  if (size() != other.size())
318  return false;
319 
320  for (size_t i = 0; i < size(); ++i) {
321  if (get(i) != other.get(i))
322  return false;
323  }
324 
325  return true;
326 }
327 
328 int
329 Name::compare(size_t pos1, size_t count1, const Name& other, size_t pos2, size_t count2) const
330 {
331  count1 = std::min(count1, this->size() - pos1);
332  count2 = std::min(count2, other.size() - pos2);
333  size_t count = std::min(count1, count2);
334 
335  for (size_t i = 0; i < count; ++i) {
336  int comp = get(pos1 + i).compare(other.get(pos2 + i));
337  if (comp != 0) { // i-th component differs
338  return comp;
339  }
340  }
341  // [pos1, pos1+count) of this Name equals [pos2, pos2+count) of other Name
342  return count1 - count2;
343 }
344 
345 // ---- URI representation ----
346 
347 void
348 Name::toUri(std::ostream& os, name::UriFormat format) const
349 {
350  if (empty()) {
351  os << "/";
352  return;
353  }
354 
355  for (const auto& component : *this) {
356  os << "/";
357  component.toUri(os, format);
358  }
359 }
360 
361 std::string
363 {
364  std::ostringstream os;
365  toUri(os, format);
366  return os.str();
367 }
368 
369 std::istream&
370 operator>>(std::istream& is, Name& name)
371 {
372  std::string inputString;
373  is >> inputString;
374  name = Name(inputString);
375 
376  return is;
377 }
378 
379 } // namespace ndn
380 
381 namespace std {
382 
383 size_t
385 {
386  return boost::hash_range(name.wireEncode().wire(),
387  name.wireEncode().wire() + name.wireEncode().size());
388 }
389 
390 } // namespace std
Represents a TLV element of the NDN packet format.
Definition: block.hpp:45
uint32_t type() const
Return the TLV-TYPE of the Block.
Definition: block.hpp:285
element_iterator erase(element_const_iterator position)
Erase a sub-element.
Definition: block.cpp:458
bool hasWire() const noexcept
Check if the Block contains a fully encoded wire representation.
Definition: block.hpp:241
void resetWire() noexcept
Reset wire buffer but keep TLV-TYPE and sub-elements (if any)
Definition: block.cpp:271
element_const_iterator elements_begin() const
Equivalent to elements().begin()
Definition: block.hpp:410
std::vector< Block > element_container
Definition: block.hpp:47
const element_container & elements() const
Get container of sub-elements.
Definition: block.hpp:402
void parse() const
Parse TLV-VALUE into sub-elements.
Definition: block.cpp:341
Represents an absolute name.
Definition: name.hpp:46
bool empty() const
Checks if the name is empty, i.e.
Definition: name.hpp:147
name::Component::Error Error
Definition: name.hpp:48
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:288
PartialName getPrefix(ssize_t nComponents) const
Returns a prefix of the name.
Definition: name.hpp:213
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:603
Name & appendParametersSha256DigestPlaceholder()
Append a placeholder for a ParametersSha256Digest component.
Definition: name.cpp:262
Name & appendVersion(const optional< uint64_t > &version=nullopt)
Append a version component.
Definition: name.cpp:230
void clear()
Remove all components.
Definition: name.cpp:280
Name & append(const Component &component)
Append a component.
Definition: name.hpp:279
Name()
Create an empty name.
Definition: name.cpp:54
bool equals(const Name &other) const
Check if this name equals another name.
Definition: name.cpp:315
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:670
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
bool isPrefixOf(const Name &other) const
Check if this name is a prefix of another name.
Definition: name.cpp:299
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
size_t size() const
Returns the number of components.
Definition: name.hpp:155
const Component & get(ssize_t i) const
Returns an immutable reference to the component at the specified index.
Definition: name.hpp:166
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:348
void wireDecode(const Block &wire)
Decode name from wire encoding.
Definition: name.cpp:150
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:53
#define NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(ClassName)
#define NDN_THROW(e)
Definition: exception.hpp:61
EncodingImpl< EstimatorTag > EncodingEstimator
EncodingImpl< EncoderTag > EncodingBuffer
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:67
@ ParametersSha256DigestComponent
Definition: tlv.hpp:70
Definition: data.cpp:25
Name PartialName
Represents an arbitrary sequence of name components.
Definition: name.hpp:40
std::istream & operator>>(std::istream &is, Name &name)
Parse URI from stream as Name.
Definition: name.cpp:370
size_t operator()(const ndn::Name &name) const
Definition: name.cpp:384