blob: 8aad977ee92c19310eb15558859c15cb8084cc0a [file] [log] [blame]
Alexander Afanasyev15f67312014-07-22 15:11:09 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2013-2014 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 "name-component.hpp"
27
28#include "encoding/block-helpers.hpp"
29#include "encoding/encoding-buffer.hpp"
30#include "util/string-helper.hpp"
Alexander Afanasyev6486d522014-10-23 14:14:11 -070031#include "security/cryptopp.hpp"
32#include "util/crypto.hpp"
Junxiao Shic2b8d242014-11-04 08:35:29 -070033#include "util/concepts.hpp"
Alexander Afanasyev15f67312014-07-22 15:11:09 -070034
Alexander Afanasyev6486d522014-10-23 14:14:11 -070035#include <boost/lexical_cast.hpp>
36
Alexander Afanasyev15f67312014-07-22 15:11:09 -070037namespace ndn {
38namespace name {
39
Junxiao Shic2b8d242014-11-04 08:35:29 -070040BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Component>));
41BOOST_CONCEPT_ASSERT((WireEncodable<Component>));
42BOOST_CONCEPT_ASSERT((WireDecodable<Component>));
43static_assert(std::is_base_of<tlv::Error, Component::Error>::value,
44 "name::Component::Error must inherit from tlv::Error");
45
Alexander Afanasyev6486d522014-10-23 14:14:11 -070046static const std::string&
47getSha256DigestUriPrefix()
48{
49 static const std::string prefix { "sha256digest=" };
50 return prefix;
51}
52
Alexander Afanasyev15f67312014-07-22 15:11:09 -070053Component::Component()
54 : Block(tlv::NameComponent)
55{
56}
57
58Component::Component(const Block& wire)
59 : Block(wire)
60{
Alexander Afanasyev6486d522014-10-23 14:14:11 -070061 if (type() != tlv::NameComponent && type() != tlv::ImplicitSha256DigestComponent)
62 throw Error("Cannot construct name::Component from not a NameComponent "
63 "or ImplicitSha256DigestComponent TLV wire block");
Alexander Afanasyev15f67312014-07-22 15:11:09 -070064}
65
66Component::Component(const ConstBufferPtr& buffer)
67 : Block(tlv::NameComponent, buffer)
68{
69}
70
71Component::Component(const Buffer& value)
72 : Block(dataBlock(tlv::NameComponent, value.buf(), value.size()))
73{
74}
75
76Component::Component(const uint8_t* value, size_t valueLen)
77 : Block(dataBlock(tlv::NameComponent, value, valueLen))
78{
79}
80
81Component::Component(const char* str)
Davide Pesaventodfe9c6b2014-08-25 21:17:10 +020082 : Block(dataBlock(tlv::NameComponent, str, std::char_traits<char>::length(str)))
Alexander Afanasyev15f67312014-07-22 15:11:09 -070083{
84}
85
86Component::Component(const std::string& str)
87 : Block(dataBlock(tlv::NameComponent, str.c_str(), str.size()))
88{
89}
90
91
92Component
93Component::fromEscapedString(const char* escapedString, size_t beginOffset, size_t endOffset)
94{
95 std::string trimmedString(escapedString + beginOffset, escapedString + endOffset);
96 trim(trimmedString);
Alexander Afanasyev15f67312014-07-22 15:11:09 -070097
Alexander Afanasyev6486d522014-10-23 14:14:11 -070098 if (trimmedString.compare(0, getSha256DigestUriPrefix().size(),
99 getSha256DigestUriPrefix()) == 0) {
100 if (trimmedString.size() != getSha256DigestUriPrefix().size() + crypto::SHA256_DIGEST_SIZE * 2)
101 throw Error("Cannot convert to ImplicitSha256DigestComponent"
102 "(expected sha256 in hex encoding)");
103
104 try {
105 std::string value;
106 CryptoPP::StringSource(reinterpret_cast<const uint8_t*>(trimmedString.c_str()) +
107 getSha256DigestUriPrefix().size(),
108 trimmedString.size () - getSha256DigestUriPrefix().size(), true,
109 new CryptoPP::HexDecoder(new CryptoPP::StringSink(value)));
110
111 return fromImplicitSha256Digest(reinterpret_cast<const uint8_t*>(value.c_str()),
112 value.size());
113 }
114 catch (CryptoPP::Exception& e) {
115 throw Error("Cannot convert to a ImplicitSha256DigestComponent (invalid hex encoding)");
116 }
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700117 }
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700118 else {
119 std::string value = unescape(trimmedString);
120
121 if (value.find_first_not_of(".") == std::string::npos) {
122 // Special case for component of only periods.
123 if (value.size() <= 2)
124 // Zero, one or two periods is illegal. Ignore this component.
125 throw Error("Illegal URI (name component cannot be . or ..)");
126 else
127 // Remove 3 periods.
128 return Component(reinterpret_cast<const uint8_t*>(&value[3]), value.size() - 3);
129 }
130 else
131 return Component(reinterpret_cast<const uint8_t*>(&value[0]), value.size());
132 }
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700133}
134
135
136void
137Component::toUri(std::ostream& result) const
138{
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700139 if (type() == tlv::ImplicitSha256DigestComponent) {
140 result << getSha256DigestUriPrefix();
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700141
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700142 CryptoPP::StringSource(value(), value_size(), true,
143 new CryptoPP::HexEncoder(new CryptoPP::FileSink(result), false));
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700144 }
145 else {
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700146 const uint8_t* value = this->value();
147 size_t valueSize = value_size();
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700148
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700149 bool gotNonDot = false;
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700150 for (size_t i = 0; i < valueSize; ++i) {
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700151 if (value[i] != 0x2e) {
152 gotNonDot = true;
153 break;
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700154 }
155 }
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700156 if (!gotNonDot) {
157 // Special case for component of zero or more periods. Add 3 periods.
158 result << "...";
159 for (size_t i = 0; i < valueSize; ++i)
160 result << '.';
161 }
162 else {
163 // In case we need to escape, set to upper case hex and save the previous flags.
164 std::ios::fmtflags saveFlags = result.flags(std::ios::hex | std::ios::uppercase);
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700165
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700166 for (size_t i = 0; i < valueSize; ++i) {
167 uint8_t x = value[i];
168 // Check for 0-9, A-Z, a-z, (+), (-), (.), (_)
169 if ((x >= 0x30 && x <= 0x39) || (x >= 0x41 && x <= 0x5a) ||
170 (x >= 0x61 && x <= 0x7a) || x == 0x2b || x == 0x2d ||
171 x == 0x2e || x == 0x5f)
172 result << x;
173 else {
174 result << '%';
175 if (x < 16)
176 result << '0';
177 result << static_cast<uint32_t>(x);
178 }
179 }
180
181 // Restore.
182 result.flags(saveFlags);
183 }
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700184 }
185}
186
187std::string
188Component::toUri() const
189{
190 std::ostringstream os;
191 toUri(os);
192 return os.str();
193}
194
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700195////////////////////////////////////////////////////////////////////////////////
Alexander Afanasyev0f232c52014-10-23 13:07:31 -0700196
197bool
198Component::isNumber() const
199{
200 return (value_size() == 1 || value_size() == 2 ||
201 value_size() == 4 || value_size() == 8);
202}
203
204bool
205Component::isNumberWithMarker(uint8_t marker) const
206{
207 return (!empty() && value()[0] == marker &&
208 (value_size() == 2 || value_size() == 3 ||
209 value_size() == 5 || value_size() == 9));
210}
211
212bool
213Component::isVersion() const
214{
215 return isNumberWithMarker(VERSION_MARKER);
216}
217
218bool
219Component::isSegment() const
220{
221 return isNumberWithMarker(SEGMENT_MARKER);
222}
223
224bool
225Component::isSegmentOffset() const
226{
227 return isNumberWithMarker(SEGMENT_OFFSET_MARKER);
228}
229
230bool
231Component::isTimestamp() const
232{
233 return isNumberWithMarker(TIMESTAMP_MARKER);
234}
235
236bool
237Component::isSequenceNumber() const
238{
239 return isNumberWithMarker(SEQUENCE_NUMBER_MARKER);
240}
241
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700242////////////////////////////////////////////////////////////////////////////////
Alexander Afanasyev0f232c52014-10-23 13:07:31 -0700243
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700244uint64_t
245Component::toNumber() const
246{
Alexander Afanasyev0f232c52014-10-23 13:07:31 -0700247 if (!isNumber())
248 throw Error("Name component does not have nonNegativeInteger value");
249
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700250 return readNonNegativeInteger(*this);
251}
252
253uint64_t
254Component::toNumberWithMarker(uint8_t marker) const
255{
Alexander Afanasyev0f232c52014-10-23 13:07:31 -0700256 if (!isNumberWithMarker(marker))
257 throw Error("Name component does not have the requested marker "
258 "or the value is not a nonNegativeInteger");
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700259
260 Buffer::const_iterator valueBegin = value_begin() + 1;
261 return tlv::readNonNegativeInteger(value_size() - 1, valueBegin, value_end());
262}
263
264uint64_t
265Component::toVersion() const
266{
267 return toNumberWithMarker(VERSION_MARKER);
268}
269
270uint64_t
271Component::toSegment() const
272{
273 return toNumberWithMarker(SEGMENT_MARKER);
274}
275
276uint64_t
277Component::toSegmentOffset() const
278{
279 return toNumberWithMarker(SEGMENT_OFFSET_MARKER);
280}
281
282time::system_clock::TimePoint
283Component::toTimestamp() const
284{
285 uint64_t value = toNumberWithMarker(TIMESTAMP_MARKER);
286 return time::getUnixEpoch() + time::microseconds(value);
287}
288
289uint64_t
290Component::toSequenceNumber() const
291{
292 return toNumberWithMarker(SEQUENCE_NUMBER_MARKER);
293}
294
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700295////////////////////////////////////////////////////////////////////////////////
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700296
297Component
298Component::fromNumber(uint64_t number)
299{
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700300 return nonNegativeIntegerBlock(tlv::NameComponent, number);
301}
302
303Component
304Component::fromNumberWithMarker(uint8_t marker, uint64_t number)
305{
306 EncodingEstimator estimator;
307
308 size_t valueLength = estimator.prependNonNegativeInteger(number);
309 valueLength += estimator.prependByteArray(&marker, 1);
310 size_t totalLength = valueLength;
311 totalLength += estimator.prependVarNumber(valueLength);
312 totalLength += estimator.prependVarNumber(tlv::NameComponent);
313
314 EncodingBuffer encoder(totalLength, 0);
315 encoder.prependNonNegativeInteger(number);
316 encoder.prependByteArray(&marker, 1);
317 encoder.prependVarNumber(valueLength);
318 encoder.prependVarNumber(tlv::NameComponent);
319
320 return encoder.block();
321}
322
323Component
324Component::fromVersion(uint64_t version)
325{
326 return fromNumberWithMarker(VERSION_MARKER, version);
327}
328
329Component
330Component::fromSegment(uint64_t segmentNo)
331{
332 return fromNumberWithMarker(SEGMENT_MARKER, segmentNo);
333}
334
335Component
336Component::fromSegmentOffset(uint64_t offset)
337{
338 return fromNumberWithMarker(SEGMENT_OFFSET_MARKER, offset);
339}
340
341Component
342Component::fromTimestamp(const time::system_clock::TimePoint& timePoint)
343{
344 using namespace time;
345 uint64_t value = duration_cast<microseconds>(timePoint - getUnixEpoch()).count();
346 return fromNumberWithMarker(TIMESTAMP_MARKER, value);
347}
348
349Component
350Component::fromSequenceNumber(uint64_t seqNo)
351{
352 return fromNumberWithMarker(SEQUENCE_NUMBER_MARKER, seqNo);
353}
354
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700355////////////////////////////////////////////////////////////////////////////////
356
357bool
358Component::isGeneric() const
359{
360 return (type() == tlv::NameComponent);
361}
362
363bool
364Component::isImplicitSha256Digest() const
365{
366 return (type() == tlv::ImplicitSha256DigestComponent &&
367 value_size() == crypto::SHA256_DIGEST_SIZE);
368}
369
370Component
371Component::fromImplicitSha256Digest(const ConstBufferPtr& digest)
372{
373 if (digest->size() != crypto::SHA256_DIGEST_SIZE)
374 throw Error("Cannot create ImplicitSha256DigestComponent (input digest must be " +
375 boost::lexical_cast<std::string>(crypto::SHA256_DIGEST_SIZE) + " octets)");
376
377 return Block(tlv::ImplicitSha256DigestComponent, digest);
378}
379
380Component
381Component::fromImplicitSha256Digest(const uint8_t* digest, size_t digestSize)
382{
383 if (digestSize != crypto::SHA256_DIGEST_SIZE)
384 throw Error("Cannot create ImplicitSha256DigestComponent (input digest must be " +
385 boost::lexical_cast<std::string>(crypto::SHA256_DIGEST_SIZE) + " octets)");
386
387 return dataBlock(tlv::ImplicitSha256DigestComponent, digest, digestSize);
388}
389
390////////////////////////////////////////////////////////////////////////////////
391
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700392int
393Component::compare(const Component& other) const
394{
395 // Imitate ndn_Exclude_compareComponents.
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700396 if (type() < other.type())
397 return -1;
398 else if (type() > other.type())
399 return 1;
400 else if (value_size() < other.value_size())
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700401 return -1;
402 if (value_size() > other.value_size())
403 return 1;
404
405 if (value_size() == 0)
406 return 0;
407
408 // The components are equal length. Just do a byte compare.
409 return std::memcmp(value(), other.value(), value_size());
410}
411
412Component
413Component::getSuccessor() const
414{
415 size_t totalLength = 0;
416 EncodingBuffer encoder(size() + 1, 1); // + 1 in case there is an overflow
417 // in unlikely case TLV length increases,
418 // EncodingBuffer will take care of that
419
420 bool isOverflow = true;
421 size_t i = value_size();
422 for (; isOverflow && i > 0; i--) {
423 uint8_t newValue = static_cast<uint8_t>((value()[i - 1] + 1) & 0xFF);
424 totalLength += encoder.prependByte(newValue);
425 isOverflow = (newValue == 0);
426 }
427 totalLength += encoder.prependByteArray(value(), i);
428
429 if (isOverflow) {
430 // new name components has to be extended
431 totalLength += encoder.appendByte(0);
432 }
433
434 totalLength += encoder.prependVarNumber(totalLength);
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700435 totalLength += encoder.prependVarNumber(type());
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700436
437 return encoder.block();
438}
439
440
441template<bool T>
442size_t
443Component::wireEncode(EncodingImpl<T>& block) const
444{
445 size_t totalLength = 0;
446 if (value_size() > 0)
447 totalLength += block.prependByteArray(value(), value_size());
448 totalLength += block.prependVarNumber(value_size());
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700449 totalLength += block.prependVarNumber(type());
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700450 return totalLength;
451}
452
453template size_t
454Component::wireEncode<true>(EncodingImpl<true>& block) const;
455
456template size_t
457Component::wireEncode<false>(EncodingImpl<false>& block) const;
458
459const Block&
460Component::wireEncode() const
461{
462 if (this->hasWire())
463 return *this;
464
465 EncodingEstimator estimator;
466 size_t estimatedSize = wireEncode(estimator);
467
468 EncodingBuffer buffer(estimatedSize, 0);
469 wireEncode(buffer);
470
471 const_cast<Component&>(*this) = buffer.block();
472 return *this;
473}
474
475void
476Component::wireDecode(const Block& wire)
477{
Alexander Afanasyev6486d522014-10-23 14:14:11 -0700478 if (wire.type() != tlv::NameComponent || wire.type() != tlv::ImplicitSha256DigestComponent)
479 throw Error("name::Component::wireDecode called on not a NameComponent "
480 "or ImplicitSha256DigestComponent TLV wire block");
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700481
482 *this = wire;
483}
484
485} // namespace name
486} // namespace ndn