blob: b3f891617081f5ebcbdb5e98219df2f9aa4a15a1 [file] [log] [blame]
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2013-2014 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 Wentao Shang <http://irl.cs.ucla.edu/~wentao/>
* @author Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
*/
#ifndef NDN_ENCODING_ENCODING_BUFFER_HPP
#define NDN_ENCODING_ENCODING_BUFFER_HPP
#include "../common.hpp"
#include "buffer.hpp"
#include "block.hpp"
namespace ndn {
namespace encoding {
static const bool Buffer = true;
static const bool Estimator = false;
} // encoding
template<bool isRealEncoderNotEstimator>
class EncodingImpl;
typedef EncodingImpl<encoding::Buffer> EncodingBuffer;
typedef EncodingImpl<encoding::Estimator> EncodingEstimator;
/**
* @brief Class representing wire element of the NDN packet
*/
template<>
class EncodingImpl<encoding::Buffer>
{
public:
/**
* @brief Constructor to create a EncodingImpl with specified reserved sizes
*
* The caller should make sure that that reserveFromBack does not exceed totalReserve,
* otherwise behavior is undefined.
*/
EncodingImpl(size_t totalReserve = 8800,
size_t reserveFromBack = 400)
: m_buffer(new Buffer(totalReserve))
{
m_begin = m_end = m_buffer->end() - (reserveFromBack < totalReserve ? reserveFromBack : 0);
}
/**
* @brief Create EncodingBlock from existing block
*
* This is a dangerous constructor and should be used with caution.
* It will modify contents of the buffer that is used by block and may
* impact data in other blocks.
*
* The primary purpose for this method is to be used to extend Block
* after sign operation.
*/
explicit
EncodingImpl(const Block& block)
: m_buffer(const_pointer_cast<Buffer>(block.m_buffer))
, m_begin(m_buffer->begin() + (block.begin() - m_buffer->begin()))
, m_end(m_buffer->begin() + (block.end() - m_buffer->begin()))
{
}
inline size_t
size() const;
inline size_t
capacity() const;
inline uint8_t*
buf();
inline const uint8_t*
buf() const;
/**
* @brief Create Block from the underlying EncodingBuffer
*
* @param verifyLength If this parameter set to true, Block's constructor
* will be requested to verify consistency of the encoded
* length in the Block, otherwise ignored
*/
inline Block
block(bool verifyLength = true) const;
inline void
resize(size_t size, bool addInFront);
inline Buffer::iterator
begin();
inline Buffer::iterator
end();
inline Buffer::const_iterator
begin() const;
inline Buffer::const_iterator
end() const;
inline size_t
prependByte(uint8_t value);
inline size_t
prependByteArray(const uint8_t* array, size_t length);
inline size_t
prependNonNegativeInteger(uint64_t varNumber);
inline size_t
prependVarNumber(uint64_t varNumber);
inline size_t
appendByte(uint8_t value);
inline size_t
appendByteArray(const uint8_t* array, size_t length);
inline size_t
appendNonNegativeInteger(uint64_t varNumber);
inline size_t
appendVarNumber(uint64_t varNumber);
// inline void
// removeByteFromFront();
// inline void
// removeByteFromEnd();
// inline void
// removeVarNumberFromFront(uint64_t varNumber);
// inline void
// removeVarNumberFromBack(uint64_t varNumber);
private:
BufferPtr m_buffer;
// invariant: m_begin always points to the position of last-written byte (if prepending data)
Buffer::iterator m_begin;
// invariant: m_end always points to the position of next unwritten byte (if appending data)
Buffer::iterator m_end;
friend class Block;
};
/**
* @brief Class representing wire element of the NDN packet
*/
template<>
class EncodingImpl<encoding::Estimator>
{
public:
EncodingImpl(size_t totalReserve = 8800,
size_t reserveFromBack = 400)
{
}
inline size_t
prependByte(uint8_t value);
inline size_t
prependByteArray(const uint8_t* array, size_t length);
inline size_t
prependNonNegativeInteger(uint64_t varNumber);
inline size_t
prependVarNumber(uint64_t varNumber);
inline size_t
appendByte(uint8_t value);
inline size_t
appendByteArray(const uint8_t* array, size_t length);
inline size_t
appendNonNegativeInteger(uint64_t varNumber);
inline size_t
appendVarNumber(uint64_t varNumber);
};
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
inline size_t
EncodingImpl<encoding::Buffer>::size() const
{
return m_end - m_begin;
}
inline size_t
EncodingImpl<encoding::Buffer>::capacity() const
{
return m_buffer->size();
}
inline uint8_t*
EncodingImpl<encoding::Buffer>::buf()
{
return &(*m_begin);
}
inline const uint8_t*
EncodingImpl<encoding::Buffer>::buf() const
{
return &(*m_begin);
}
inline Block
EncodingImpl<encoding::Buffer>::block(bool verifyLength/* = true*/) const
{
return Block(m_buffer,
m_begin, m_end,
verifyLength);
}
inline void
EncodingImpl<encoding::Buffer>::resize(size_t size, bool addInFront)
{
if (addInFront)
{
size_t diff_end = m_buffer->end() - m_end;
size_t diff_begin = m_buffer->end() - m_begin;
Buffer* buf = new Buffer(size);
std::copy_backward(m_buffer->begin(), m_buffer->end(), buf->end());
m_buffer.reset(buf);
m_end = m_buffer->end() - diff_end;
m_begin = m_buffer->end() - diff_begin;
}
else
{
size_t diff_end = m_end - m_buffer->begin();
size_t diff_begin = m_begin - m_buffer->begin();
Buffer* buf = new Buffer(size);
std::copy(m_buffer->begin(), m_buffer->end(), buf->begin());
m_buffer.reset(buf);
m_end = m_buffer->begin() + diff_end;
m_begin = m_buffer->begin() + diff_begin;
}
}
inline Buffer::iterator
EncodingImpl<encoding::Buffer>::begin()
{
return m_begin;
}
inline Buffer::iterator
EncodingImpl<encoding::Buffer>::end()
{
return m_end;
}
inline Buffer::const_iterator
EncodingImpl<encoding::Buffer>::begin() const
{
return m_begin;
}
inline Buffer::const_iterator
EncodingImpl<encoding::Buffer>::end() const
{
return m_end;
}
//////////////////////////////////////////////////////////
// Prepend to the back of the buffer. Resize if needed. //
//////////////////////////////////////////////////////////
inline size_t
EncodingImpl<encoding::Buffer>::prependByte(uint8_t value)
{
if (m_begin == m_buffer->begin())
resize(m_buffer->size() * 2, true);
m_begin--;
*m_begin = value;
return 1;
}
inline size_t
EncodingImpl<encoding::Estimator>::prependByte(uint8_t value)
{
return 1;
}
inline size_t
EncodingImpl<encoding::Buffer>::prependByteArray(const uint8_t* array, size_t length)
{
if ((m_buffer->begin() + length) > m_begin)
resize(m_buffer->size() * 2 + length, true);
m_begin -= length;
std::copy(array, array + length, m_begin);
return length;
}
inline size_t
EncodingImpl<encoding::Estimator>::prependByteArray(const uint8_t* array, size_t length)
{
return length;
}
inline size_t
EncodingImpl<encoding::Buffer>::prependNonNegativeInteger(uint64_t varNumber)
{
if (varNumber <= std::numeric_limits<uint8_t>::max()) {
return prependByte(static_cast<uint8_t>(varNumber));
}
else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
uint16_t value = htobe16(static_cast<uint16_t>(varNumber));
return prependByteArray(reinterpret_cast<const uint8_t*>(&value), 2);
}
else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
uint32_t value = htobe32(static_cast<uint32_t>(varNumber));
return prependByteArray(reinterpret_cast<const uint8_t*>(&value), 4);
}
else {
uint64_t value = htobe64(varNumber);
return prependByteArray(reinterpret_cast<const uint8_t*>(&value), 8);
}
}
inline size_t
EncodingImpl<encoding::Estimator>::prependNonNegativeInteger(uint64_t varNumber)
{
if (varNumber <= std::numeric_limits<uint8_t>::max()) {
return 1;
}
else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
return 2;
}
else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
return 4;
}
else {
return 8;
}
}
inline size_t
EncodingImpl<encoding::Buffer>::prependVarNumber(uint64_t varNumber)
{
if (varNumber < 253) {
prependByte(static_cast<uint8_t>(varNumber));
return 1;
}
else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
uint16_t value = htobe16(static_cast<uint16_t>(varNumber));
prependByteArray(reinterpret_cast<const uint8_t*>(&value), 2);
prependByte(253);
return 3;
}
else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
uint32_t value = htobe32(static_cast<uint32_t>(varNumber));
prependByteArray(reinterpret_cast<const uint8_t*>(&value), 4);
prependByte(254);
return 5;
}
else {
uint64_t value = htobe64(varNumber);
prependByteArray(reinterpret_cast<const uint8_t*>(&value), 8);
prependByte(255);
return 9;
}
}
inline size_t
EncodingImpl<encoding::Estimator>::prependVarNumber(uint64_t varNumber)
{
if (varNumber < 253) {
return 1;
}
else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
return 3;
}
else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
return 5;
}
else {
return 9;
}
}
/////////////////////////////////////////////////////////
// Append to the back of the buffer. Resize if needed. //
/////////////////////////////////////////////////////////
inline size_t
EncodingImpl<encoding::Buffer>::appendByte(uint8_t value)
{
if (m_end == m_buffer->end())
resize(m_buffer->size() * 2, false);
*m_end = value;
m_end++;
return 1;
}
inline size_t
EncodingImpl<encoding::Estimator>::appendByte(uint8_t value)
{
return 1;
}
inline size_t
EncodingImpl<encoding::Buffer>::appendByteArray(const uint8_t* array, size_t length)
{
if ((m_end + length) > m_buffer->end())
resize(m_buffer->size() * 2 + length, false);
std::copy(array, array + length, m_end);
m_end += length;
return length;
}
inline size_t
EncodingImpl<encoding::Estimator>::appendByteArray(const uint8_t* array, size_t length)
{
return prependByteArray(array, length);
}
inline size_t
EncodingImpl<encoding::Buffer>::appendNonNegativeInteger(uint64_t varNumber)
{
if (varNumber <= std::numeric_limits<uint8_t>::max()) {
return appendByte(static_cast<uint8_t>(varNumber));
}
else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
uint16_t value = htobe16(static_cast<uint16_t>(varNumber));
return appendByteArray(reinterpret_cast<const uint8_t*>(&value), 2);
}
else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
uint32_t value = htobe32(static_cast<uint32_t>(varNumber));
return appendByteArray(reinterpret_cast<const uint8_t*>(&value), 4);
}
else {
uint64_t value = htobe64(varNumber);
return appendByteArray(reinterpret_cast<const uint8_t*>(&value), 8);
}
}
inline size_t
EncodingImpl<encoding::Estimator>::appendNonNegativeInteger(uint64_t varNumber)
{
return prependNonNegativeInteger(varNumber);
}
inline size_t
EncodingImpl<encoding::Buffer>::appendVarNumber(uint64_t varNumber)
{
if (varNumber < 253) {
appendByte(static_cast<uint8_t>(varNumber));
return 1;
}
else if (varNumber <= std::numeric_limits<uint16_t>::max()) {
appendByte(253);
uint16_t value = htobe16(static_cast<uint16_t>(varNumber));
appendByteArray(reinterpret_cast<const uint8_t*>(&value), 2);
return 3;
}
else if (varNumber <= std::numeric_limits<uint32_t>::max()) {
appendByte(254);
uint32_t value = htobe32(static_cast<uint32_t>(varNumber));
appendByteArray(reinterpret_cast<const uint8_t*>(&value), 4);
return 5;
}
else {
appendByte(255);
uint64_t value = htobe64(varNumber);
appendByteArray(reinterpret_cast<const uint8_t*>(&value), 8);
return 9;
}
}
inline size_t
EncodingImpl<encoding::Estimator>::appendVarNumber(uint64_t varNumber)
{
return prependVarNumber(varNumber);
}
/// helper methods
template<bool P>
inline size_t
prependNonNegativeIntegerBlock(EncodingImpl<P>& encoder, uint32_t type, uint64_t number)
{
size_t valueLength = encoder.prependNonNegativeInteger(number);
size_t totalLength = valueLength;
totalLength += encoder.prependVarNumber(valueLength);
totalLength += encoder.prependVarNumber(type);
return totalLength;
}
template<bool P>
inline size_t
prependByteArrayBlock(EncodingImpl<P>& encoder, uint32_t type,
const uint8_t* array, size_t arraySize)
{
size_t valueLength = encoder.prependByteArray(array, arraySize);
size_t totalLength = valueLength;
totalLength += encoder.prependVarNumber(valueLength);
totalLength += encoder.prependVarNumber(type);
return totalLength;
}
template<bool P>
inline size_t
prependBooleanBlock(EncodingImpl<P>& encoder, uint32_t type)
{
size_t totalLength = encoder.prependVarNumber(0);
totalLength += encoder.prependVarNumber(type);
return totalLength;
}
template<bool P, class U>
inline size_t
prependNestedBlock(EncodingImpl<P>& encoder, uint32_t type, const U& nestedBlock)
{
size_t valueLength = nestedBlock.wireEncode(encoder);
size_t totalLength = valueLength;
totalLength += encoder.prependVarNumber(valueLength);
totalLength += encoder.prependVarNumber(type);
return totalLength;
}
template<bool P>
inline size_t
prependBlock(EncodingImpl<P>& encoder, const Block& block)
{
return encoder.prependByteArray(block.wire(), block.size());
}
} // ndn
#endif // NDN_ENCODING_ENCODING_BUFFER_HPP