blob: 0f9892010f6fd56d432653ddff67afd38e7b036b [file] [log] [blame]
/* -*- 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