blob: a045766c446b30b2cc1abad2f855e1dd774ecbcd [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)
63 : Block(dataBlock(tlv::NameComponent, str, ::strlen(str)))
64{
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
145uint64_t
146Component::toNumber() const
147{
148 /// \todo Check if Component is of tlv::NumberComponent type
149 return readNonNegativeInteger(*this);
150}
151
152uint64_t
153Component::toNumberWithMarker(uint8_t marker) const
154{
155 if (empty() || value()[0] != marker)
156 throw Error("Name component does not have the requested marker");
157
158 Buffer::const_iterator valueBegin = value_begin() + 1;
159 return tlv::readNonNegativeInteger(value_size() - 1, valueBegin, value_end());
160}
161
162uint64_t
163Component::toVersion() const
164{
165 return toNumberWithMarker(VERSION_MARKER);
166}
167
168uint64_t
169Component::toSegment() const
170{
171 return toNumberWithMarker(SEGMENT_MARKER);
172}
173
174uint64_t
175Component::toSegmentOffset() const
176{
177 return toNumberWithMarker(SEGMENT_OFFSET_MARKER);
178}
179
180time::system_clock::TimePoint
181Component::toTimestamp() const
182{
183 uint64_t value = toNumberWithMarker(TIMESTAMP_MARKER);
184 return time::getUnixEpoch() + time::microseconds(value);
185}
186
187uint64_t
188Component::toSequenceNumber() const
189{
190 return toNumberWithMarker(SEQUENCE_NUMBER_MARKER);
191}
192
193
194Component
195Component::fromNumber(uint64_t number)
196{
197 /// \todo Change to tlv::NumberComponent
198 return nonNegativeIntegerBlock(tlv::NameComponent, number);
199}
200
201Component
202Component::fromNumberWithMarker(uint8_t marker, uint64_t number)
203{
204 EncodingEstimator estimator;
205
206 size_t valueLength = estimator.prependNonNegativeInteger(number);
207 valueLength += estimator.prependByteArray(&marker, 1);
208 size_t totalLength = valueLength;
209 totalLength += estimator.prependVarNumber(valueLength);
210 totalLength += estimator.prependVarNumber(tlv::NameComponent);
211
212 EncodingBuffer encoder(totalLength, 0);
213 encoder.prependNonNegativeInteger(number);
214 encoder.prependByteArray(&marker, 1);
215 encoder.prependVarNumber(valueLength);
216 encoder.prependVarNumber(tlv::NameComponent);
217
218 return encoder.block();
219}
220
221Component
222Component::fromVersion(uint64_t version)
223{
224 return fromNumberWithMarker(VERSION_MARKER, version);
225}
226
227Component
228Component::fromSegment(uint64_t segmentNo)
229{
230 return fromNumberWithMarker(SEGMENT_MARKER, segmentNo);
231}
232
233Component
234Component::fromSegmentOffset(uint64_t offset)
235{
236 return fromNumberWithMarker(SEGMENT_OFFSET_MARKER, offset);
237}
238
239Component
240Component::fromTimestamp(const time::system_clock::TimePoint& timePoint)
241{
242 using namespace time;
243 uint64_t value = duration_cast<microseconds>(timePoint - getUnixEpoch()).count();
244 return fromNumberWithMarker(TIMESTAMP_MARKER, value);
245}
246
247Component
248Component::fromSequenceNumber(uint64_t seqNo)
249{
250 return fromNumberWithMarker(SEQUENCE_NUMBER_MARKER, seqNo);
251}
252
253int
254Component::compare(const Component& other) const
255{
256 // Imitate ndn_Exclude_compareComponents.
257 if (value_size() < other.value_size())
258 return -1;
259 if (value_size() > other.value_size())
260 return 1;
261
262 if (value_size() == 0)
263 return 0;
264
265 // The components are equal length. Just do a byte compare.
266 return std::memcmp(value(), other.value(), value_size());
267}
268
269Component
270Component::getSuccessor() const
271{
272 size_t totalLength = 0;
273 EncodingBuffer encoder(size() + 1, 1); // + 1 in case there is an overflow
274 // in unlikely case TLV length increases,
275 // EncodingBuffer will take care of that
276
277 bool isOverflow = true;
278 size_t i = value_size();
279 for (; isOverflow && i > 0; i--) {
280 uint8_t newValue = static_cast<uint8_t>((value()[i - 1] + 1) & 0xFF);
281 totalLength += encoder.prependByte(newValue);
282 isOverflow = (newValue == 0);
283 }
284 totalLength += encoder.prependByteArray(value(), i);
285
286 if (isOverflow) {
287 // new name components has to be extended
288 totalLength += encoder.appendByte(0);
289 }
290
291 totalLength += encoder.prependVarNumber(totalLength);
292 totalLength += encoder.prependVarNumber(tlv::NameComponent);
293
294 return encoder.block();
295}
296
297
298template<bool T>
299size_t
300Component::wireEncode(EncodingImpl<T>& block) const
301{
302 size_t totalLength = 0;
303 if (value_size() > 0)
304 totalLength += block.prependByteArray(value(), value_size());
305 totalLength += block.prependVarNumber(value_size());
306 totalLength += block.prependVarNumber(tlv::NameComponent);
307 return totalLength;
308}
309
310template size_t
311Component::wireEncode<true>(EncodingImpl<true>& block) const;
312
313template size_t
314Component::wireEncode<false>(EncodingImpl<false>& block) const;
315
316const Block&
317Component::wireEncode() const
318{
319 if (this->hasWire())
320 return *this;
321
322 EncodingEstimator estimator;
323 size_t estimatedSize = wireEncode(estimator);
324
325 EncodingBuffer buffer(estimatedSize, 0);
326 wireEncode(buffer);
327
328 const_cast<Component&>(*this) = buffer.block();
329 return *this;
330}
331
332void
333Component::wireDecode(const Block& wire)
334{
335 if (wire.type() != tlv::NameComponent)
336 throw Error("name::Component::wireDecode called on not a NameComponent TLV wire block");
337
338 *this = wire;
339}
340
341} // namespace name
342} // namespace ndn