| /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */ |
| /* |
| * Copyright (c) 2013, Regents of the University of California |
| * Alexander Afanasyev |
| * Zhenkai Zhu |
| * |
| * BSD license, See the LICENSE file for more information |
| * |
| * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu> |
| * Zhenkai Zhu <zhenkai@cs.ucla.edu> |
| */ |
| |
| #include "name.h" |
| |
| #include "detail/error.h" |
| #include <boost/algorithm/string.hpp> |
| |
| #include <ctype.h> |
| |
| using namespace std; |
| |
| NDN_NAMESPACE_BEGIN |
| |
| ATTRIBUTE_HELPER_CPP (Name); |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // CONSTRUCTORS // |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| Name::Name () |
| { |
| } |
| |
| Name::Name (const string &uri) |
| { |
| string::const_iterator i = uri.begin (); |
| string::const_iterator end = uri.end (); |
| |
| string::const_iterator firstSlash = std::find (i, end, '/'); |
| if (firstSlash == end) |
| { |
| BOOST_THROW_EXCEPTION (error::Name () |
| << error::msg ("Name should include at least one slash (did you forget to specify initial /?)")); |
| } |
| |
| if (firstSlash != i) |
| { |
| string schema (i, firstSlash); |
| if (*schema.rbegin () != ':') |
| { |
| BOOST_THROW_EXCEPTION (error::Name () |
| << error::msg ("First component of the name does not start with a slash (did you forget to specify initial /?)")); |
| } |
| |
| i = firstSlash; |
| |
| if (!boost::iequals (schema, "ccnx:") && |
| !boost::iequals (schema, "ndn:")) |
| { |
| BOOST_THROW_EXCEPTION (error::Name () |
| << error::msg ("URI schema is not supported (only ccnx: or ndn: is allowed)") |
| << error::msg (schema)); |
| } |
| } |
| |
| string::const_iterator secondSlash = i; |
| secondSlash ++; |
| if (secondSlash != end && *secondSlash == '/') |
| { |
| // The authority component (the part after the initial "//" in the familiar http and ftp URI schemes) is present, |
| // but it is not relevant to NDN name. |
| // skipping it |
| secondSlash ++; |
| i = std::find (secondSlash, end, '/'); |
| } |
| |
| if (i == end) |
| { |
| BOOST_THROW_EXCEPTION (error::Name () |
| << error::msg ("Invalid URI") |
| << error::msg (uri)); |
| } |
| |
| while (i != end) |
| { |
| // skip any extra slashes |
| while (i != end && *i == '/') |
| { |
| i ++; |
| } |
| if (i == end) |
| break; |
| |
| string::const_iterator endOfComponent = std::find (i, end, '/'); |
| append (name::Component (i, endOfComponent)); |
| |
| i = endOfComponent; |
| } |
| } |
| |
| Name::Name (const Name &other) |
| { |
| m_comps = other.m_comps; |
| } |
| |
| Name & |
| Name::operator= (const Name &other) |
| { |
| m_comps = other.m_comps; |
| return *this; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // SETTERS // |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| Name & |
| Name::appendVersion (uint64_t version/* = Name::nversion*/) |
| { |
| if (version != Name::nversion) |
| return appendNumberWithMarker (version, 0xFD); |
| else |
| { |
| TimeInterval now = time::NowUnixTimestamp (); |
| #ifdef NDNSIM_MODE |
| int64_t seconds = now.GetSeconds (); |
| int64_t microseconds = now.GetMicroSeconds () - seconds * 1000000; |
| |
| version = (seconds << 12) | (0xFFF & (microseconds / 244 /*( 1000,000 microseconds / 4096.0 resolution = last 12 bits)*/)); |
| #else |
| version = (now.total_seconds () << 12) | (0xFFF & (now.fractional_seconds () / 244 /*( 1000,000 microseconds / 4096.0 resolution = last 12 bits)*/)); |
| #endif |
| return appendNumberWithMarker (version, 0xFD); |
| } |
| } |
| |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // GETTERS // |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| const name::Component & |
| Name::get (int index) const |
| { |
| if (index < 0) |
| { |
| index = size () - (-index); |
| } |
| |
| if (static_cast<unsigned int> (index) >= size ()) |
| { |
| BOOST_THROW_EXCEPTION (error::Name () |
| << error::msg ("Index out of range") |
| << error::pos (index)); |
| } |
| return m_comps [index]; |
| } |
| |
| name::Component & |
| Name::get (int index) |
| { |
| if (index < 0) |
| { |
| index = size () - (-index); |
| } |
| |
| if (static_cast<unsigned int> (index) >= size()) |
| { |
| BOOST_THROW_EXCEPTION (error::Name () |
| << error::msg ("Index out of range") |
| << error::pos (index)); |
| } |
| return m_comps [index]; |
| } |
| |
| |
| ///// |
| ///// Static helpers to convert name component to appropriate value |
| ///// |
| |
| |
| Name |
| Name::getSubName (size_t pos/* = 0*/, size_t len/* = Name::npos*/) const |
| { |
| Name retval; |
| |
| if (len == npos) |
| { |
| len = size () - pos; |
| } |
| |
| if (pos + len > size ()) |
| { |
| BOOST_THROW_EXCEPTION (error::Name () |
| << error::msg ("getSubName parameter out of range") |
| << error::pos (pos) |
| << error::pos (len)); |
| } |
| |
| for (size_t i = pos; i < pos + len; i++) |
| { |
| retval.append (get (i)); |
| } |
| |
| return retval; |
| } |
| |
| Name |
| Name::operator+ (const Name &name) const |
| { |
| Name newName; |
| newName |
| .append (*this) |
| .append (name); |
| |
| return newName; |
| } |
| |
| std::string |
| Name::toUri () const |
| { |
| ostringstream os; |
| toUri (os); |
| return os.str (); |
| } |
| |
| void |
| Name::toUri (std::ostream &os) const |
| { |
| for (Name::const_iterator comp = begin (); comp != end (); comp++) |
| { |
| os << "/"; |
| comp->toUri (os); |
| } |
| if (size () == 0) |
| os << "/"; |
| } |
| |
| // ostream & |
| // operator << (ostream &os, const Name &name) |
| // { |
| // for (Name::const_iterator comp = name.begin (); comp != name.end (); comp++) |
| // { |
| // os << "/" << *comp; |
| // } |
| // if (name.size () == 0) |
| // os << "/"; |
| // return os; |
| // } |
| |
| int |
| Name::compare (const Name &name) const |
| { |
| Name::const_iterator i = this->begin (); |
| Name::const_iterator j = name.begin (); |
| |
| for (; i != this->end () && j != name.end (); i++, j++) |
| { |
| int res = i->compare (*j); |
| if (res == 0) |
| continue; |
| else |
| return res; |
| } |
| |
| if (i == this->end () && j == name.end ()) |
| return 0; // prefixes are equal |
| |
| return (i == this->end ()) ? -1 : +1; |
| } |
| |
| NDN_NAMESPACE_END |