// $Id: BRbOutputBuffer.cpp,v 1.8 2003/02/21 02:00:02 yuya Exp $

#include "BRbOutputBuffer.h"

////////////////////////////////////////////////////////////////////////////////

const long BRbOutputBuffer::LENGTH_FIRST = 1024;
const long BRbOutputBuffer::LENGTH_UNIT  = 512;

////////////////////////////////////////////////////////////////////////////////

BRbOutputBuffer::BRbOutputBuffer()
{
	m_position = 0;
	m_length   = LENGTH_FIRST;
	m_buffer   = new char[m_length];
	::memset(m_buffer, 0, m_length);
}

BRbOutputBuffer::~BRbOutputBuffer()
{
	if ( m_buffer ) {
		delete[] m_buffer;
	}

	m_position = 0;
	m_length   = 0;
	m_buffer   = 0;
}

////////////////////////////////////////////////////////////////////////////////

inline VALUE
BRbOutputBuffer::to_string()
{
	return ::rb_str_new(m_buffer, m_position);
}

inline void
BRbOutputBuffer::write_byte(byte value)
{
	const int size = sizeof(value);
	reserve(size);
	*((byte*)(m_buffer + m_position)) = value;
	m_position += size;
}

inline void
BRbOutputBuffer::write_word(word value)
{
	const int size = sizeof(value);
	reserve(size);
	*((word*)(m_buffer + m_position)) = value;
	m_position += size;
}

inline void
BRbOutputBuffer::write_dword(dword value)
{
	const int size = sizeof(value);
	reserve(size);
	*((dword*)(m_buffer + m_position)) = value;
	m_position += size;
}

inline void
BRbOutputBuffer::write_bytes(void* value, int size)
{
	reserve(size);
	::memcpy(m_buffer + m_position, value, size);
	m_position += size;
}

inline void
BRbOutputBuffer::write_buffer(BRbOutputBuffer& buffer)
{
	reserve(buffer.m_position);
	::memcpy(m_buffer + m_position, buffer.m_buffer, buffer.m_position);
	m_position += buffer.m_position;
}

////////////////////////////////////////////////////////////////////////////////

inline void
BRbOutputBuffer::resize(long new_length)
{
	long  old_length = m_length;
	char* old_buffer = m_buffer;

	m_length = new_length;
	m_buffer = new char[m_length];

	if ( new_length >= old_length ) {
		::memcpy(m_buffer, old_buffer, old_length);
		::memset(m_buffer + old_length, 0, m_length - old_length);
	} else {
		::memcpy(m_buffer, old_buffer, new_length);
		m_position = new_length - 1;
	}

	delete[] old_buffer;
}

inline void
BRbOutputBuffer::reserve(long size)
{
	if ( m_position + size > m_length ) {
		const long addition = (long)ceil(size / (double)LENGTH_UNIT) * LENGTH_UNIT;
		resize(m_length + addition);
	}
}

////////////////////////////////////////////////////////////////////////////////
