blob: 9c97773218a652ca51d9606196acb20b05731bdd [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"
31
32namespace ndn {
33namespace name {
34
35Component::Component()
36 : Block(tlv::NameComponent)
37{
38}
39
40Component::Component(const Block& wire)
41 : Block(wire)
42{
43 if (type() != tlv::NameComponent)
44 throw Error("Cannot construct name::Component from not a NameComponent TLV wire block");
45}
46
47Component::Component(const ConstBufferPtr& buffer)
48 : Block(tlv::NameComponent, buffer)
49{
50}
51
52Component::Component(const Buffer& value)
53 : Block(dataBlock(tlv::NameComponent, value.buf(), value.size()))
54{
55}
56
57Component::Component(const uint8_t* value, size_t valueLen)
58 : Block(dataBlock(tlv::NameComponent, value, valueLen))
59{
60}
61
62Component::Component(const char* str)
Davide Pesaventodfe9c6b2014-08-25 21:17:10 +020063 : Block(dataBlock(tlv::NameComponent, str, std::char_traits<char>::length(str)))
Alexander Afanasyev15f67312014-07-22 15:11:09 -070064{
65}
66
67Component::Component(const std::string& str)
68 : Block(dataBlock(tlv::NameComponent, str.c_str(), str.size()))
69{
70}
71
72
73Component
74Component::fromEscapedString(const char* escapedString, size_t beginOffset, size_t endOffset)
75{
76 std::string trimmedString(escapedString + beginOffset, escapedString + endOffset);
77 trim(trimmedString);
78 std::string value = unescape(trimmedString);
79
80 if (value.find_first_not_of(".") == std::string::npos) {
81 // Special case for component of only periods.
82 if (value.size() <= 2)
83 // Zero, one or two periods is illegal. Ignore this component.
84 throw Error("Illegal URI (name component cannot be . or ..)");
85 else
86 // Remove 3 periods.
87 return Component(reinterpret_cast<const uint8_t*>(&value[3]), value.size() - 3);
88 }
89 else
90 return Component(reinterpret_cast<const uint8_t*>(&value[0]), value.size());
91}
92
93
94void
95Component::toUri(std::ostream& result) const
96{
97 const uint8_t* value = this->value();
98 size_t valueSize = value_size();
99
100 bool gotNonDot = false;
101 for (size_t i = 0; i < valueSize; ++i) {
102 if (value[i] != 0x2e) {
103 gotNonDot = true;
104 break;
105 }
106 }
107 if (!gotNonDot) {
108 // Special case for component of zero or more periods. Add 3 periods.
109 result << "...";
110 for (size_t i = 0; i < valueSize; ++i)
111 result << '.';
112 }
113 else {
114 // In case we need to escape, set to upper case hex and save the previous flags.
115 std::ios::fmtflags saveFlags = result.flags(std::ios::hex | std::ios::uppercase);
116
117 for (size_t i = 0; i < valueSize; ++i) {
118 uint8_t x = value[i];
119 // Check for 0-9, A-Z, a-z, (+), (-), (.), (_)
120 if ((x >= 0x30 && x <= 0x39) || (x >= 0x41 && x <= 0x5a) ||
121 (x >= 0x61 && x <= 0x7a) || x == 0x2b || x == 0x2d ||
122 x == 0x2e || x == 0x5f)
123 result << x;
124 else {
125 result << '%';
126 if (x < 16)
127 result << '0';
128 result << static_cast<uint32_t>(x);
129 }
130 }
131
132 // Restore.
133 result.flags(saveFlags);
134 }
135}
136
137std::string
138Component::toUri() const
139{
140 std::ostringstream os;
141 toUri(os);
142 return os.str();
143}
144
Alexander Afanasyev0f232c52014-10-23 13:07:31 -0700145
146bool
147Component::isNumber() const
148{
149 return (value_size() == 1 || value_size() == 2 ||
150 value_size() == 4 || value_size() == 8);
151}
152
153bool
154Component::isNumberWithMarker(uint8_t marker) const
155{
156 return (!empty() && value()[0] == marker &&
157 (value_size() == 2 || value_size() == 3 ||
158 value_size() == 5 || value_size() == 9));
159}
160
161bool
162Component::isVersion() const
163{
164 return isNumberWithMarker(VERSION_MARKER);
165}
166
167bool
168Component::isSegment() const
169{
170 return isNumberWithMarker(SEGMENT_MARKER);
171}
172
173bool
174Component::isSegmentOffset() const
175{
176 return isNumberWithMarker(SEGMENT_OFFSET_MARKER);
177}
178
179bool
180Component::isTimestamp() const
181{
182 return isNumberWithMarker(TIMESTAMP_MARKER);
183}
184
185bool
186Component::isSequenceNumber() const
187{
188 return isNumberWithMarker(SEQUENCE_NUMBER_MARKER);
189}
190
191
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700192uint64_t
193Component::toNumber() const
194{
Alexander Afanasyev0f232c52014-10-23 13:07:31 -0700195 if (!isNumber())
196 throw Error("Name component does not have nonNegativeInteger value");
197
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700198 return readNonNegativeInteger(*this);
199}
200
201uint64_t
202Component::toNumberWithMarker(uint8_t marker) const
203{
Alexander Afanasyev0f232c52014-10-23 13:07:31 -0700204 if (!isNumberWithMarker(marker))
205 throw Error("Name component does not have the requested marker "
206 "or the value is not a nonNegativeInteger");
Alexander Afanasyev15f67312014-07-22 15:11:09 -0700207
208 Buffer::const_iterator valueBegin = value_begin() + 1;
209 return tlv::readNonNegativeInteger(value_size() - 1, valueBegin, value_end());
210}
211
212uint64_t
213Component::toVersion() const
214{
215 return toNumberWithMarker(VERSION_MARKER);
216}
217
218uint64_t
219Component::toSegment() const
220{
221 return toNumberWithMarker(SEGMENT_MARKER);
222}
223
224uint64_t
225Component::toSegmentOffset() const
226{
227 return toNumberWithMarker(SEGMENT_OFFSET_MARKER);
228}
229
230time::system_clock::TimePoint
231Component::toTimestamp() const
232{
233 uint64_t value = toNumberWithMarker(TIMESTAMP_MARKER);
234 return time::getUnixEpoch() + time::microseconds(value);
235}
236
237uint64_t
238Component::toSequenceNumber() const
239{
240 return toNumberWithMarker(SEQUENCE_NUMBER_MARKER);
241}
242
243
244Component
245Component::fromNumber(uint64_t number)
246{
247 /// \todo Change to tlv::NumberComponent
248 return nonNegativeIntegerBlock(tlv::NameComponent, number);
249}
250
251Component
252Component::fromNumberWithMarker(uint8_t marker, uint64_t number)
253{
254 EncodingEstimator estimator;
255
256 size_t valueLength = estimator.prependNonNegativeInteger(number);
257 valueLength += estimator.prependByteArray(&marker, 1);
258 size_t totalLength = valueLength;
259 totalLength += estimator.prependVarNumber(valueLength);
260 totalLength += estimator.prependVarNumber(tlv::NameComponent);
261
262 EncodingBuffer encoder(totalLength, 0);
263 encoder.prependNonNegativeInteger(number);
264 encoder.prependByteArray(&marker, 1);
265 encoder.prependVarNumber(valueLength);
266 encoder.prependVarNumber(tlv::NameComponent);
267
268 return encoder.block();
269}
270
271Component
272Component::fromVersion(uint64_t version)
273{
274 return fromNumberWithMarker(VERSION_MARKER, version);
275}
276
277Component
278Component::fromSegment(uint64_t segmentNo)
279{
280 return fromNumberWithMarker(SEGMENT_MARKER, segmentNo);
281}
282
283Component
284Component::fromSegmentOffset(uint64_t offset)
285{
286 return fromNumberWithMarker(SEGMENT_OFFSET_MARKER, offset);
287}
288
289Component
290Component::fromTimestamp(const time::system_clock::TimePoint& timePoint)
291{
292 using namespace time;
293 uint64_t value = duration_cast<microseconds>(timePoint - getUnixEpoch()).count();
294 return fromNumberWithMarker(TIMESTAMP_MARKER, value);
295}
296
297Component
298Component::fromSequenceNumber(uint64_t seqNo)
299{
300 return fromNumberWithMarker(SEQUENCE_NUMBER_MARKER, seqNo);
301}
302
303int
304Component::compare(const Component& other) const
305{
306 // Imitate ndn_Exclude_compareComponents.
307 if (value_size() < other.value_size())
308 return -1;
309 if (value_size() > other.value_size())
310 return 1;
311
312 if (value_size() == 0)
313 return 0;
314
315 // The components are equal length. Just do a byte compare.
316 return std::memcmp(value(), other.value(), value_size());
317}
318
319Component
320Component::getSuccessor() const
321{
322 size_t totalLength = 0;
323 EncodingBuffer encoder(size() + 1, 1); // + 1 in case there is an overflow
324 // in unlikely case TLV length increases,
325 // EncodingBuffer will take care of that
326
327 bool isOverflow = true;
328 size_t i = value_size();
329 for (; isOverflow && i > 0; i--) {
330 uint8_t newValue = static_cast<uint8_t>((value()[i - 1] + 1) & 0xFF);
331 totalLength += encoder.prependByte(newValue);
332 isOverflow = (newValue == 0);
333 }
334 totalLength += encoder.prependByteArray(value(), i);
335
336 if (isOverflow) {
337 // new name components has to be extended
338 totalLength += encoder.appendByte(0);
339 }
340
341 totalLength += encoder.prependVarNumber(totalLength);
342 totalLength += encoder.prependVarNumber(tlv::NameComponent);
343
344 return encoder.block();
345}
346
347
348template<bool T>
349size_t
350Component::wireEncode(EncodingImpl<T>& block) const
351{
352 size_t totalLength = 0;
353 if (value_size() > 0)
354 totalLength += block.prependByteArray(value(), value_size());
355 totalLength += block.prependVarNumber(value_size());
356 totalLength += block.prependVarNumber(tlv::NameComponent);
357 return totalLength;
358}
359
360template size_t
361Component::wireEncode<true>(EncodingImpl<true>& block) const;
362
363template size_t
364Component::wireEncode<false>(EncodingImpl<false>& block) const;
365
366const Block&
367Component::wireEncode() const
368{
369 if (this->hasWire())
370 return *this;
371
372 EncodingEstimator estimator;
373 size_t estimatedSize = wireEncode(estimator);
374
375 EncodingBuffer buffer(estimatedSize, 0);
376 wireEncode(buffer);
377
378 const_cast<Component&>(*this) = buffer.block();
379 return *this;
380}
381
382void
383Component::wireDecode(const Block& wire)
384{
385 if (wire.type() != tlv::NameComponent)
386 throw Error("name::Component::wireDecode called on not a NameComponent TLV wire block");
387
388 *this = wire;
389}
390
391} // namespace name
392} // namespace ndn