| /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ |
| /* |
| * Copyright (c) 2013-2018 Regents of the University of California. |
| * |
| * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions). |
| * |
| * ndn-cxx library is free software: you can redistribute it and/or modify it under the |
| * terms of the GNU Lesser General Public License as published by the Free Software |
| * Foundation, either version 3 of the License, or (at your option) any later version. |
| * |
| * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY |
| * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A |
| * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. |
| * |
| * You should have received copies of the GNU General Public License and GNU Lesser |
| * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see |
| * <http://www.gnu.org/licenses/>. |
| * |
| * See AUTHORS.md for complete list of ndn-cxx authors and contributors. |
| */ |
| |
| #ifndef NDN_DETAIL_NAME_COMPONENT_TYPES_HPP |
| #define NDN_DETAIL_NAME_COMPONENT_TYPES_HPP |
| |
| #include "../name-component.hpp" |
| |
| #include "../util/sha256.hpp" |
| #include "../util/string-helper.hpp" |
| |
| #include <array> |
| #include <unordered_map> |
| |
| namespace ndn { |
| namespace name { |
| namespace detail { |
| |
| /** \brief Declare rules regarding a NameComponent type. |
| */ |
| class ComponentType : noncopyable |
| { |
| public: |
| using Error = Component::Error; |
| |
| virtual |
| ~ComponentType() = default; |
| |
| /** \brief Throw Component::Error if \p comp is invalid. |
| */ |
| virtual void |
| check(const Component& comp) const |
| { |
| } |
| |
| /** \brief Calculate the successor of \p comp. |
| * |
| * If \p comp is the maximum possible value of this component type, return true to indicate |
| * that the successor should have a greater TLV-TYPE. |
| */ |
| virtual std::pair<bool, Component> |
| getSuccessor(const Component& comp) const |
| { |
| return {false, getSuccessorImpl(comp).second}; |
| } |
| |
| /** \brief Return the minimum allowable TLV-VALUE of this component type. |
| */ |
| virtual const std::vector<uint8_t>& |
| getMinValue() const |
| { |
| static std::vector<uint8_t> value; |
| return value; |
| } |
| |
| /** \brief Return the prefix of the alternate URI representation. |
| * |
| * NDN URI specification allows a name component type to declare an alternate URI representation |
| * in the form of `<prefix>=<value>`, in addition to the plain `<type-number>=<escaped-value>` |
| * syntax. |
| * |
| * \return the `<prefix>` portion of the alternate URI representation. |
| * \retval nullptr this component does not have an alternate URI representation. |
| */ |
| virtual const char* |
| getAltUriPrefix() const |
| { |
| return nullptr; |
| } |
| |
| /** \brief Parse component from alternate URI representation. |
| * \param input the `<value>` portion of the alternate URI representation. |
| * \throw Component::Error |
| * \pre getAltUriPrefix() != nullptr |
| */ |
| virtual Component |
| parseAltUriValue(const std::string& input) const |
| { |
| BOOST_ASSERT(false); |
| return Component(); |
| } |
| |
| /** \brief Write URI representation of \p comp to \p os. |
| * |
| * This base class implementation encodes the component in the plain |
| * `<type-number>=<escaped-value>` syntax. |
| */ |
| virtual void |
| writeUri(std::ostream& os, const Component& comp) const |
| { |
| os << comp.type() << '='; |
| writeUriEscapedValue(os, comp); |
| } |
| |
| protected: |
| /** \brief Calculate the successor of \p comp, extending TLV-LENGTH if value overflows. |
| * \return whether TLV-LENGTH was extended, and the successor |
| */ |
| std::pair<bool, Block> |
| getSuccessorImpl(const Component& comp) const |
| { |
| EncodingBuffer encoder(comp.size() + 9, 9); |
| // leave room for additional byte when TLV-VALUE overflows, and for TLV-LENGTH size increase |
| |
| bool isOverflow = true; |
| size_t i = comp.value_size(); |
| for (; isOverflow && i > 0; i--) { |
| uint8_t newValue = static_cast<uint8_t>((comp.value()[i - 1] + 1) & 0xFF); |
| encoder.prependByte(newValue); |
| isOverflow = (newValue == 0); |
| } |
| encoder.prependByteArray(comp.value(), i); |
| |
| if (isOverflow) { |
| // new name component has to be extended |
| encoder.appendByte(0); |
| } |
| |
| encoder.prependVarNumber(encoder.size()); |
| encoder.prependVarNumber(comp.type()); |
| return {isOverflow, encoder.block()}; |
| } |
| |
| /** \brief Write TLV-VALUE as `<escaped-value>` of NDN URI syntax. |
| */ |
| void |
| writeUriEscapedValue(std::ostream& os, const Component& comp) const |
| { |
| bool isAllPeriods = std::all_of(comp.value_begin(), comp.value_end(), |
| [] (uint8_t x) { return x == '.'; }); |
| if (isAllPeriods) { |
| os << "..."; |
| } |
| escape(os, reinterpret_cast<const char*>(comp.value()), comp.value_size()); |
| } |
| }; |
| |
| /** \brief Rules regarding GenericNameComponent. |
| * |
| * GenericNameComponent has an alternate URI representation that omits the `<type-number>` prefix. |
| * This must be special-cased in the caller, and is not handled by this class. |
| */ |
| class GenericNameComponentType final : public ComponentType |
| { |
| public: |
| void |
| writeUri(std::ostream& os, const Component& comp) const final |
| { |
| writeUriEscapedValue(os, comp); |
| } |
| }; |
| |
| /** \brief Rules regarding a component type holding a SHA256 digest value. |
| */ |
| class Sha256ComponentType final : public ComponentType |
| { |
| public: |
| Sha256ComponentType(uint32_t type, const std::string& typeName, const std::string& uriPrefix) |
| : m_type(type) |
| , m_typeName(typeName) |
| , m_uriPrefix(uriPrefix) |
| { |
| } |
| |
| bool |
| match(const Component& comp) const |
| { |
| return comp.type() == m_type && comp.value_size() == util::Sha256::DIGEST_SIZE; |
| } |
| |
| void |
| check(const Component& comp) const final |
| { |
| if (!match(comp)) { |
| BOOST_THROW_EXCEPTION(Error(m_typeName + " TLV-LENGTH must be " + |
| to_string(util::Sha256::DIGEST_SIZE))); |
| } |
| } |
| |
| Component |
| create(ConstBufferPtr value) const |
| { |
| return Component(Block(m_type, std::move(value))); |
| } |
| |
| Component |
| create(const uint8_t* value, size_t valueSize) const |
| { |
| return Component(makeBinaryBlock(m_type, value, valueSize)); |
| } |
| |
| std::pair<bool, Component> |
| getSuccessor(const Component& comp) const final |
| { |
| bool isExtended = false; |
| Block successor; |
| std::tie(isExtended, successor) = getSuccessorImpl(comp); |
| if (isExtended) { |
| return {true, comp}; |
| } |
| return {false, Component(successor)}; |
| } |
| |
| const std::vector<uint8_t>& |
| getMinValue() const final |
| { |
| static std::vector<uint8_t> value(util::Sha256::DIGEST_SIZE); |
| return value; |
| } |
| |
| const char* |
| getAltUriPrefix() const final |
| { |
| return m_uriPrefix.data(); |
| } |
| |
| Component |
| parseAltUriValue(const std::string& input) const final |
| { |
| shared_ptr<Buffer> value; |
| try { |
| value = fromHex(input); |
| } |
| catch (const StringHelperError&) { |
| BOOST_THROW_EXCEPTION(Error("Cannot convert to " + m_typeName + " (invalid hex encoding)")); |
| } |
| return Component(m_type, std::move(value)); |
| } |
| |
| void |
| writeUri(std::ostream& os, const Component& comp) const final |
| { |
| os << m_uriPrefix << '='; |
| printHex(os, comp.value(), comp.value_size(), false); |
| } |
| |
| private: |
| uint32_t m_type; |
| std::string m_typeName; |
| std::string m_uriPrefix; |
| }; |
| |
| inline const Sha256ComponentType& |
| getComponentType1() |
| { |
| static Sha256ComponentType ct1(tlv::ImplicitSha256DigestComponent, |
| "ImplicitSha256DigestComponent", "sha256digest"); |
| return ct1; |
| } |
| |
| inline const Sha256ComponentType& |
| getComponentType2() |
| { |
| static Sha256ComponentType ct2(tlv::ParametersSha256DigestComponent, |
| "ParametersSha256DigestComponent", "params-sha256"); |
| return ct2; |
| } |
| |
| /** \brief Rules regarding NameComponent types. |
| */ |
| class ComponentTypeTable : noncopyable |
| { |
| public: |
| ComponentTypeTable(); |
| |
| /** \brief Retrieve ComponentType by TLV-TYPE. |
| */ |
| const ComponentType& |
| get(uint32_t type) const |
| { |
| if (type >= m_table.size() || m_table[type] == nullptr) { |
| return m_baseType; |
| } |
| return *m_table[type]; |
| } |
| |
| /** \brief Retrieve ComponentType by alternate URI prefix. |
| */ |
| const ComponentType* |
| findByUriPrefix(const std::string& prefix) const |
| { |
| auto it = m_uriPrefixes.find(prefix); |
| if (it == m_uriPrefixes.end()) { |
| return nullptr; |
| } |
| return it->second; |
| } |
| |
| private: |
| void |
| set(uint32_t type, const ComponentType& ct) |
| { |
| m_table.at(type) = &ct; |
| if (ct.getAltUriPrefix() != nullptr) { |
| m_uriPrefixes[ct.getAltUriPrefix()] = &ct; |
| } |
| } |
| |
| private: |
| ComponentType m_baseType; |
| std::array<const ComponentType*, 32> m_table; |
| std::unordered_map<std::string, const ComponentType*> m_uriPrefixes; |
| }; |
| |
| inline |
| ComponentTypeTable::ComponentTypeTable() |
| { |
| m_table.fill(nullptr); |
| |
| static GenericNameComponentType ct8; |
| set(tlv::GenericNameComponent, ct8); |
| |
| set(tlv::ImplicitSha256DigestComponent, getComponentType1()); |
| set(tlv::ParametersSha256DigestComponent, getComponentType2()); |
| } |
| |
| /** \brief Get the global ComponentTypeTable. |
| */ |
| inline const ComponentTypeTable& |
| getComponentTypeTable() |
| { |
| static ComponentTypeTable ctt; |
| return ctt; |
| } |
| |
| } // namespace detail |
| } // namespace name |
| } // namespace ndn |
| |
| #endif // NDN_DETAIL_NAME_COMPONENT_TYPES_HPP |