blob: 3691ed9fc0cb50bd8ce6ae83818b34f3eb7393f8 [file] [log] [blame]
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2013-2015 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.
*
* @author Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
*/
#ifndef NDN_ENCODING_BLOCK_HPP
#define NDN_ENCODING_BLOCK_HPP
#include "../common.hpp"
#include "buffer.hpp"
#include "tlv.hpp"
namespace boost {
namespace asio {
class const_buffer;
} // namespace asio
} // namespace boost
namespace ndn {
template<bool> class EncodingImpl;
typedef EncodingImpl<true> EncodingBuffer;
/** @brief Class representing a wire element of NDN-TLV packet format
*/
class Block
{
public:
typedef std::vector<Block> element_container;
typedef element_container::iterator element_iterator;
typedef element_container::const_iterator element_const_iterator;
class Error : public tlv::Error
{
public:
explicit
Error(const std::string& what)
: tlv::Error(what)
{
}
};
public: // constructor, creation, assignment
/** @brief Create an empty Block
*/
Block();
/** @brief Create a Block based on EncodingBuffer object
*/
explicit
Block(const EncodingBuffer& buffer);
/** @brief Create a Block from the raw buffer with Type-Length parsing
*/
explicit
Block(const ConstBufferPtr& buffer);
/** @brief Create a Block from a buffer, directly specifying boundaries
* of the block within the buffer
*
* This overload 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 Create a Block from the raw buffer with Type-Length parsing
*/
Block(const uint8_t* buffer, size_t maxlength);
/** @brief Create a Block from the raw buffer with Type-Length parsing
*/
Block(const void* buffer, size_t maxlength);
/** @brief Create a Block from the wire buffer (no parsing)
*
* This overload 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 a Block of a specific type with the specified value
*
* The underlying buffer holds 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 a nested Block of a specific type with the specified value
*
* The underlying buffer holds 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 Block& value);
/** @brief Create a Block from an input stream
* @deprecated Use Block::fromStream instead
*/
explicit
DEPRECATED(Block(std::istream& is))
{
*this = std::move(Block::fromStream(is));
}
/** @brief Create a Block from an input stream
*/
static Block
fromStream(std::istream& is);
/** @brief Try to construct block from Buffer, referencing data block pointed by wire
*
* This method does not throw upon decoding error.
* @return 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
*
* This method does not throw upon decoding error.
* @return true if Block successfully created, false if block cannot be created
*/
static bool
fromBuffer(const uint8_t* buffer, size_t maxSize, Block& block);
public: // wire format
/** @brief Check if the Block is empty
*/
bool
empty() const;
/** @brief Check if the Block has fully encoded wire
*/
bool
hasWire() const;
/** @brief Reset wire buffer of the element
*/
void
reset();
/** @brief Reset wire buffer but keep sub elements (if any)
*/
void
resetWire();
Buffer::const_iterator
begin() const;
Buffer::const_iterator
end() const;
const uint8_t*
wire() const;
size_t
size() const;
public: // type and value
uint32_t
type() const;
/** @brief Check if the Block has value block (no type and length are encoded)
*/
bool
hasValue() const;
Buffer::const_iterator
value_begin() const;
Buffer::const_iterator
value_end() const;
const uint8_t*
value() const;
size_t
value_size() const;
public: // sub elements
/** @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();
/** @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);
/** @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;
public: // ConvertibleToConstBuffer
operator boost::asio::const_buffer() 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 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 const uint8_t*
Block::wire() const
{
if (!hasWire())
throw Error("(Block::wire) Underlying wire buffer is empty");
return &*m_begin;
}
inline size_t
Block::size() const
{
if (hasWire() || hasValue()) {
return m_size;
}
else
throw Error("Block size cannot be determined (undefined block size)");
}
inline uint32_t
Block::type() const
{
return m_type;
}
inline bool
Block::hasValue() const
{
return static_cast<bool>(m_buffer);
}
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::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 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 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->operator==(other);
}
} // namespace ndn
#endif // NDN_ENCODING_BLOCK_HPP