/* [<][>][^][v][top][bottom][index][help] */
//
// Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010,
// 2011 Free Software Foundation, Inc
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#ifndef GNASH_SIMPLEBUFFER_H
#define GNASH_SIMPLEBUFFER_H
#include <boost/cstdint.hpp> // for boost::uint8_t
#include <algorithm> // for std::copy
#include <boost/scoped_array.hpp>
#include <cassert>
namespace gnash {
/// A simple buffer of bytes
//
/// This class is fully inlined and just aiming to provide RIIA
/// and unified view of memory buffers.
/// It is a kind of a std::vector with a reduced interface
/// in the intentions of the author.
///
class SimpleBuffer {
public:
/// Construct a SimpleBuffer with an optional initial capacity
//
/// @param capacity
/// The initial buffer capacity. This is the amount of
/// bytes you can append to the buffer before a new reallocation
/// will occur.
///
SimpleBuffer(size_t capacity=0)
:
_size(0),
_capacity(capacity)
{
if ( _capacity )
{
_data.reset(new boost::uint8_t[_capacity]);
}
}
/// Copy constructor
//
/// The copy ctor will set capacity to be
/// as small as required to hold the size of the
/// model buffer.
///
SimpleBuffer(const SimpleBuffer& b)
:
_size(b._size),
_capacity(b._size)
{
if ( _size )
{
_data.reset(new boost::uint8_t[_size]);
std::copy(b.data(), b.data()+b.size(), _data.get());
}
}
/// Assignment operator
//
/// The assignment op will not reset capacity
///
SimpleBuffer& operator= (const SimpleBuffer& b)
{
if ( this != &b ) // don't waste time on self-assignment
{
resize(0); // shouldn't deallocate memory
append(b);
}
return *this;
}
/// Return true if buffer is empty
bool empty() const { return _size==0; }
/// Return size of the buffer
size_t size() const { return _size; }
/// Return capacity of the buffer
size_t capacity() const { return _capacity; }
/// Get a pointer to start of data. May be NULL if size==0.
boost::uint8_t* data() { return _data.get(); }
/// Get a pointer to start of data. May be NULL if size==0.
const boost::uint8_t* data() const { return _data.get(); }
/// Resize the buffer
void resize(size_t newSize)
{
reserve(newSize); // will set capacity
_size = newSize;
}
/// Ensure at least 'newCapacity' bytes are allocated for this buffer
void reserve(size_t newCapacity)
{
if ( _capacity >= newCapacity ) return;
// TODO: use smalles power of 2 bigger then newCapacity
_capacity = std::max(newCapacity, _capacity*2);
boost::scoped_array<boost::uint8_t> tmp;
tmp.swap(_data);
_data.reset(new boost::uint8_t[_capacity]);
if ( tmp.get() )
{
if ( _size ) std::copy(tmp.get(), tmp.get()+_size, _data.get());
}
}
/// Append data to the buffer
//
/// The buffer will be appropriately resized to have space for
/// the incoming data. The data will be copied.
///
/// @param inData
/// Data to append. Will be copied.
///
/// @param size
/// Size of data to append
///
void append(const void* inData, size_t size)
{
const boost::uint8_t* newData =
reinterpret_cast<const boost::uint8_t*>(inData);
size_t curSize = _size;
resize(curSize+size);
std::copy(newData, newData+size, _data.get()+curSize);
assert(_size == curSize+size);
}
/// Append a byte to the buffer
//
/// The buffer will be appropriately resized to have space.
///
/// @param b
/// Byte to append.
///
void appendByte(const boost::uint8_t b)
{
resize(_size + 1);
_data[_size - 1] = b;
}
/// Append 2 bytes to the buffer
//
/// The buffer will be appropriately resized to have space.
///
/// @param s
/// Short to append. Will be appended in network order. ie
/// with high order byte first.
///
void appendNetworkShort(const boost::uint16_t s)
{
resize(_size + 2);
_data[_size - 2] = s >> 8;
_data[_size - 1] = s & 0xff;
}
/// Append 4 bytes to the buffer
//
/// The buffer will be appropriately resized to have space.
///
/// @param l
/// Long to append. Will be appended in network order. ie
/// with high order bytes first.
///
void appendNetworkLong(const boost::uint32_t l)
{
resize(_size + 4);
_data[_size - 4] = l >> 24;
_data[_size - 3] = (l >> 16) & 0xff;
_data[_size - 2] = (l >> 8) & 0xff;
_data[_size - 1] = l & 0xff;
}
/// Append data to the buffer
//
/// The buffer will be appropriately resized to have space for
/// the incoming data. The data will be copied.
///
/// @param buf
/// SimpleBuffer containing data to append
///
void append(const SimpleBuffer& buf)
{
size_t incomingDataSize = buf.size();
const boost::uint8_t* incomingData = buf.data();
append(incomingData, incomingDataSize);
}
private:
size_t _size;
size_t _capacity;
boost::scoped_array<boost::uint8_t> _data;
};
} // namespace gnash
#endif // GNASH_SIMPLEBUFFER_H