blob: 4251fa96bfd15af4c078b0c1a03302f3e16e128a [file] [log] [blame]
/* -*- 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: Wentao Shang <wentao@cs.ucla.edu>
*/
#ifndef NDN_ENCODING_BUFFER_HPP
#define NDN_ENCODING_BUFFER_HPP
#include "../common.hpp"
#include <list>
#include <exception>
#include <algorithm>
#include "buffer.hpp"
#include "tlv.hpp"
#include "block.hpp"
#include <boost/lexical_cast.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 sz, 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 val);
inline size_t
prependByteArray (const uint8_t *arr, size_t len);
inline size_t
prependNonNegativeInteger (uint64_t varNumber);
inline size_t
prependVarNumber (uint64_t varNumber);
inline size_t
appendByte (uint8_t val);
inline size_t
appendByteArray (const uint8_t *arr, size_t len);
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 val);
inline size_t
prependByteArray (const uint8_t *arr, size_t len);
inline size_t
prependNonNegativeInteger (uint64_t varNumber);
inline size_t
prependVarNumber (uint64_t varNumber);
inline size_t
appendByte (uint8_t val);
inline size_t
appendByteArray (const uint8_t *arr, size_t len);
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 sz, 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 (sz);
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 (sz);
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 val)
{
if (m_begin == m_buffer->begin ())
resize (m_buffer->size () * 2, true);
m_begin--;
*m_begin = val;
return 1;
}
inline size_t
EncodingImpl<encoding::Estimator>::prependByte (uint8_t val)
{
return 1;
}
inline size_t
EncodingImpl<encoding::Buffer>::prependByteArray (const uint8_t *arr, size_t len)
{
if ((m_buffer->begin () + len) > m_begin)
resize (m_buffer->size () * 2 + len, true);
m_begin -= len;
std::copy (arr, arr + len, m_begin);
return len;
}
inline size_t
EncodingImpl<encoding::Estimator>::prependByteArray (const uint8_t *arr, size_t len)
{
return len;
}
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 val)
{
if (m_end == m_buffer->end ())
resize (m_buffer->size () * 2, false);
*m_end = val;
m_end++;
return 1;
}
inline size_t
EncodingImpl<encoding::Estimator>::appendByte (uint8_t val)
{
return 1;
}
inline size_t
EncodingImpl<encoding::Buffer>::appendByteArray (const uint8_t *arr, size_t len)
{
if ((m_end + len) > m_buffer->end ())
resize (m_buffer->size () * 2 + len, false);
std::copy (arr, arr + len, m_end);
m_end += len;
return len;
}
inline size_t
EncodingImpl<encoding::Estimator>::appendByteArray (const uint8_t *arr, size_t len)
{
return prependByteArray(arr, len);
}
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>& blk, uint32_t type, uint64_t number)
{
size_t var_len = blk.prependNonNegativeInteger(number);
size_t total_len = var_len;
total_len += blk.prependVarNumber(var_len);
total_len += blk.prependVarNumber(type);
return total_len;
}
template<bool P>
inline size_t
prependByteArrayBlock(EncodingImpl<P>& blk, uint32_t type, const uint8_t* array, size_t arraySize)
{
size_t var_len = blk.prependByteArray(array, arraySize);
size_t total_len = var_len;
total_len += blk.prependVarNumber(var_len);
total_len += blk.prependVarNumber(type);
return total_len;
}
template<bool P>
inline size_t
prependBooleanBlock(EncodingImpl<P>& blk, uint32_t type)
{
size_t total_len = blk.prependVarNumber(0);
total_len += blk.prependVarNumber(type);
return total_len;
}
template<bool P, class U>
inline size_t
prependNestedBlock(EncodingImpl<P>& blk, uint32_t type, const U& nestedBlock)
{
size_t var_len = nestedBlock.wireEncode(blk);
size_t total_len = var_len;
total_len += blk.prependVarNumber(var_len);
total_len += blk.prependVarNumber(type);
return total_len;
}
template<bool P>
inline size_t
prependBlock(EncodingImpl<P>& blk, const Block& block)
{
return blk.prependByteArray(block.wire(), block.size());
}
} // ndn
#endif // NDN_ENCODING_BUFFER_HPP