| /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */ |
| /* |
| * Copyright (c) 2013, Regents of the University of California |
| * |
| * BSD license, See the LICENSE file for more information |
| * |
| * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu> |
| */ |
| |
| #ifndef NDN_BLOCK_HPP |
| #define NDN_BLOCK_HPP |
| |
| #include "../common.hpp" |
| |
| #include "buffer.hpp" |
| #include "tlv.hpp" |
| |
| namespace ndn { |
| |
| template<bool> class EncodingImpl; |
| typedef EncodingImpl<true> EncodingBuffer; |
| |
| /** |
| * @brief Class representing wire element of the NDN packet |
| */ |
| class Block |
| { |
| public: |
| typedef std::vector<Block> element_container; |
| typedef element_container::iterator element_iterator; |
| typedef element_container::const_iterator element_const_iterator; |
| |
| /// @brief Error that can be thrown from the block |
| class Error : public Tlv::Error |
| { |
| public: |
| explicit |
| Error(const std::string& what) |
| : Tlv::Error(what) |
| { |
| } |
| }; |
| |
| /** |
| * @brief Default constructor to create an empty Block |
| */ |
| Block(); |
| |
| /** |
| * @brief Create block based on EncodingBuffer object |
| */ |
| explicit |
| Block(const EncodingBuffer& buffer); |
| |
| /** |
| * @brief A helper version of a constructor to create Block from the raw buffer (type and value-length parsing) |
| * |
| * This constructor provides ability of implicit conversion from ConstBufferPtr to Block |
| */ |
| Block(const ConstBufferPtr& buffer); |
| |
| /** |
| * @brief Another helper to create block from a buffer, directly specifying boundaries |
| * of the block within the buffer |
| * |
| * This version will automatically detect type and position of the value within the block |
| */ |
| Block(const ConstBufferPtr& buffer, |
| const Buffer::const_iterator& begin, const Buffer::const_iterator& end, |
| bool verifyLength = true); |
| |
| /** |
| * @brief A helper version of a constructor to create Block from the raw buffer (type and value-length parsing) |
| */ |
| Block(const uint8_t* buffer, size_t maxlength); |
| |
| Block(const void* buffer, size_t maxlength); |
| |
| /* |
| * @brief A helper version of a constructor to create Block from the stream. |
| */ |
| explicit |
| Block(std::istream& is); |
| |
| /** |
| * @brief Create Block from the wire buffer (no parsing) |
| * |
| * This version of the constructor does not do any parsing |
| */ |
| Block(const ConstBufferPtr& wire, |
| uint32_t type, |
| const Buffer::const_iterator& begin, const Buffer::const_iterator& end, |
| const Buffer::const_iterator& valueBegin, const Buffer::const_iterator& valueEnd); |
| |
| /** |
| * @brief Create Block of a specific type with empty wire buffer |
| */ |
| explicit |
| Block(uint32_t type); |
| |
| /** |
| * @brief Create Block of a specific type with the specified value |
| * |
| * The underlying buffer hold only value, additional operations are needed |
| * to construct wire encoding, one need to prepend the wire buffer with type |
| * and value-length VAR-NUMBERs |
| */ |
| Block(uint32_t type, const ConstBufferPtr& value); |
| |
| /** |
| * @brief Create nested Block of a specific type with the specified value |
| * |
| * The underlying buffer hold only value, additional operations are needed |
| * to construct wire encoding, one need to prepend the wire buffer with type |
| * and value-length VAR-NUMBERs |
| */ |
| explicit |
| Block(uint32_t type, const Block& value); |
| |
| /** |
| * @brief Try to construct block from Buffer, referencing data block pointed by wire |
| * |
| * @throws This method never throws an exception |
| * |
| * @returns true if Block successfully created, false if block cannot be created |
| */ |
| static bool |
| fromBuffer(const ConstBufferPtr& wire, size_t offset, Block& block); |
| |
| /** |
| * @brief Try to construct block from Buffer, referencing data block pointed by wire |
| * |
| * @throws This method never throws an exception |
| * |
| * @returns true if Block successfully created, false if block cannot be created |
| */ |
| static bool |
| fromBuffer(const uint8_t* buffer, size_t maxSize, Block& block); |
| |
| /** |
| * @brief Check if the Block is empty |
| */ |
| bool |
| empty() const; |
| |
| /** |
| * @brief Check if the Block has fully encoded wire |
| */ |
| bool |
| hasWire() const; |
| |
| /** |
| * @brief Check if the Block has value block (no type and length are encoded) |
| */ |
| bool |
| hasValue() const; |
| |
| /** |
| * @brief Reset wire buffer of the element |
| */ |
| void |
| reset(); |
| |
| /** |
| * @brief Reset wire buffer but keep sub elements (if any) |
| */ |
| void |
| resetWire(); |
| |
| /** |
| * @brief Parse wire buffer into subblocks |
| * |
| * This method is not really const, but it does not modify any data. It simply |
| * parses contents of the buffer into subblocks |
| */ |
| void |
| parse() const; |
| |
| /** |
| * @brief Encode subblocks into wire buffer |
| */ |
| void |
| encode(); |
| |
| uint32_t |
| type() const; |
| |
| /** |
| * @brief Get the first subelement of the requested type |
| */ |
| const Block& |
| get(uint32_t type) const; |
| |
| element_const_iterator |
| find(uint32_t type) const; |
| |
| void |
| remove(uint32_t type); |
| |
| element_iterator |
| erase(element_iterator position); |
| |
| element_iterator |
| erase(element_iterator first, element_iterator last); |
| |
| void |
| push_back(const Block& element); |
| |
| Buffer::const_iterator |
| begin() const; |
| |
| Buffer::const_iterator |
| end() const; |
| |
| const uint8_t* |
| wire() const; |
| |
| size_t |
| size() const; |
| |
| Buffer::const_iterator |
| value_begin() const; |
| |
| Buffer::const_iterator |
| value_end() const; |
| |
| const uint8_t* |
| value() const; |
| |
| size_t |
| value_size() const; |
| |
| /** |
| * @brief Get all subelements |
| */ |
| const element_container& |
| elements() const; |
| |
| element_const_iterator |
| elements_begin() const; |
| |
| element_const_iterator |
| elements_end() const; |
| |
| size_t |
| elements_size() const; |
| |
| Block |
| blockFromValue() const; |
| |
| public: // EqualityComparable concept |
| bool |
| operator==(const Block& other) const; |
| |
| bool |
| operator!=(const Block& other) const; |
| |
| protected: |
| ConstBufferPtr m_buffer; |
| |
| uint32_t m_type; |
| |
| Buffer::const_iterator m_begin; |
| Buffer::const_iterator m_end; |
| uint32_t m_size; |
| |
| Buffer::const_iterator m_value_begin; |
| Buffer::const_iterator m_value_end; |
| |
| mutable element_container m_subBlocks; |
| friend class EncodingImpl<true>; |
| }; |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| //////////////////////////////////////////////////////////////////////////////// |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| inline bool |
| Block::empty() const |
| { |
| return m_type == std::numeric_limits<uint32_t>::max(); |
| } |
| |
| |
| inline bool |
| Block::hasWire() const |
| { |
| return m_buffer && (m_begin != m_end); |
| } |
| |
| inline bool |
| Block::hasValue() const |
| { |
| return static_cast<bool>(m_buffer); |
| } |
| |
| inline void |
| Block::reset() |
| { |
| m_buffer.reset(); // reset of the shared_ptr |
| m_subBlocks.clear(); // remove all parsed subelements |
| |
| m_type = std::numeric_limits<uint32_t>::max(); |
| m_begin = m_end = m_value_begin = m_value_end = Buffer::const_iterator(); |
| } |
| |
| inline void |
| Block::resetWire() |
| { |
| m_buffer.reset(); // reset of the shared_ptr |
| // keep subblocks |
| |
| // keep type |
| m_begin = m_end = m_value_begin = m_value_end = Buffer::const_iterator(); |
| } |
| |
| inline uint32_t |
| Block::type() const |
| { |
| return m_type; |
| } |
| |
| inline const Block& |
| Block::get(uint32_t type) const |
| { |
| for (element_const_iterator i = m_subBlocks.begin(); |
| i != m_subBlocks.end(); |
| i++) |
| { |
| if (i->type() == type) |
| { |
| return *i; |
| } |
| } |
| |
| throw Error("(Block::get) Requested a non-existed type [" + |
| boost::lexical_cast<std::string>(type) + "] from Block"); |
| } |
| |
| inline Block::element_const_iterator |
| Block::find(uint32_t type) const |
| { |
| for (element_const_iterator i = m_subBlocks.begin(); |
| i != m_subBlocks.end(); |
| i++) |
| { |
| if (i->type() == type) |
| { |
| return i; |
| } |
| } |
| return m_subBlocks.end(); |
| } |
| |
| inline void |
| Block::remove(uint32_t type) |
| { |
| resetWire(); |
| |
| element_container newContainer; |
| newContainer.reserve(m_subBlocks.size()); |
| for (element_iterator i = m_subBlocks.begin(); |
| i != m_subBlocks.end(); |
| ++i) |
| { |
| if (i->type() != type) |
| newContainer.push_back(*i); |
| } |
| m_subBlocks.swap(newContainer); |
| } |
| |
| inline Block::element_iterator |
| Block::erase(Block::element_iterator position) |
| { |
| resetWire(); |
| return m_subBlocks.erase(position); |
| } |
| |
| inline Block::element_iterator |
| Block::erase(Block::element_iterator first, Block::element_iterator last) |
| { |
| resetWire(); |
| return m_subBlocks.erase(first, last); |
| } |
| |
| |
| inline void |
| Block::push_back(const Block& element) |
| { |
| resetWire(); |
| m_subBlocks.push_back(element); |
| } |
| |
| inline Buffer::const_iterator |
| Block::begin() const |
| { |
| if (!hasWire()) |
| throw Error("Underlying wire buffer is empty"); |
| |
| return m_begin; |
| } |
| |
| inline Buffer::const_iterator |
| Block::end() const |
| { |
| if (!hasWire()) |
| throw Error("Underlying wire buffer is empty"); |
| |
| return m_end; |
| } |
| |
| inline size_t |
| Block::size() const |
| { |
| if (hasWire() || hasValue()) { |
| return m_size; |
| } |
| else |
| throw Error("Block size cannot be determined (undefined block size)"); |
| } |
| |
| inline Buffer::const_iterator |
| Block::value_begin() const |
| { |
| return m_value_begin; |
| } |
| |
| inline Buffer::const_iterator |
| Block::value_end() const |
| { |
| return m_value_end; |
| } |
| |
| inline const uint8_t* |
| Block::wire() const |
| { |
| if (!hasWire()) |
| throw Error("(Block::wire) Underlying wire buffer is empty"); |
| |
| return &*m_begin; |
| } |
| |
| inline const uint8_t* |
| Block::value() const |
| { |
| if (!hasValue()) |
| return 0; |
| |
| return &*m_value_begin; |
| } |
| |
| inline size_t |
| Block::value_size() const |
| { |
| if (!hasValue()) |
| return 0; |
| |
| return m_value_end - m_value_begin; |
| } |
| |
| inline const Block::element_container& |
| Block::elements() const |
| { |
| return m_subBlocks; |
| } |
| |
| inline Block::element_const_iterator |
| Block::elements_begin() const |
| { |
| return m_subBlocks.begin(); |
| } |
| |
| inline Block::element_const_iterator |
| Block::elements_end() const |
| { |
| return m_subBlocks.end(); |
| } |
| |
| inline size_t |
| Block::elements_size() const |
| { |
| return m_subBlocks.size(); |
| } |
| |
| inline bool |
| Block::operator==(const Block& other) const |
| { |
| return (this->size() == other.size()) && |
| std::equal(this->begin(), this->end(), other.begin()); |
| } |
| |
| inline bool |
| Block::operator!=(const Block& other) const |
| { |
| return !this->operator==(other); |
| } |
| |
| } // ndn |
| |
| #include "block-helpers.hpp" |
| |
| #endif // NDN_BLOCK_HPP |