sources/network/bytestream.cpp

Thu, 11 Dec 2014 05:58:55 +0200

author
Teemu Piippo <crimsondusk64@gmail.com>
date
Thu, 11 Dec 2014 05:58:55 +0200
changeset 5
146825d63b9a
child 9
e7a09ceb4505
permissions
-rw-r--r--

- code cleanup
- added network-related classes (bytestream, ipaddress, udp socket)

#include "bytestream.h"
#include <string.h>

bool Bytestream::sink;

// -------------------------------------------------------------------------------------------------
//
Bytestream::Bytestream (unsigned long length) :
	m_data (nullptr)
{
	resize (length);
	clear();
}

// -------------------------------------------------------------------------------------------------
//
Bytestream::Bytestream (const unsigned char* data, unsigned long length) :
	m_data (nullptr)
{
	m_data = nullptr;
	init (data, length);
}

// -------------------------------------------------------------------------------------------------
//
Bytestream::Bytestream (const Vector<unsigned char>& bytes) :
	m_data (nullptr)
{
	init (bytes.data(), bytes.size());
}

// -------------------------------------------------------------------------------------------------
//
Bytestream::~Bytestream()
{
	delete m_data;
}

// -------------------------------------------------------------------------------------------------
//
void Bytestream::resize (unsigned long newsize)
{
	Vector<unsigned char> olddata;
	unsigned long oldsize = 0L;

	if (m_data != nullptr)
	{
		oldsize = allocated_size();
		olddata.resize (oldsize);
		memcpy (olddata.data(), m_data, oldsize);
	}

	delete[] m_data;
	m_allocatedSize = newsize;
	m_data = new unsigned char[newsize];

	if (olddata > 0L)
		memcpy (m_data, olddata, min (oldsize, newsize));
}

// -------------------------------------------------------------------------------------------------
//
void Bytestream::init (const unsigned char* data, unsigned long length)
{
	resize (length);
	memcpy (m_data, data, length);
	m_cursor = &m_data[0];
	m_writtenLength = length;
}

// -------------------------------------------------------------------------------------------------
//
void Bytestream::clear()
{
	m_cursor = &m_data[0];
	m_writtenLength = 0;
}

// -------------------------------------------------------------------------------------------------
//
char Bytestream::read_byte (bool* ok)
{
	*ok = bytes_left() > 0;
	return *ok ? *m_cursor++ : -1;
}

// -------------------------------------------------------------------------------------------------
//
short int Bytestream::read_short (bool* ok)
{
	if (bytes_left() < 2)
	{
		*ok = false;
		return false;
	}

	short int val = 0;

	for (int i = 0; i < 2; ++i)
		val |= *m_cursor++ << (i * 8);

	*ok = true;
	return true;
}

// -------------------------------------------------------------------------------------------------
//
long int Bytestream::read_long (bool* ok)
{
	if (bytes_left() < 4)
	{
		*ok = false;
		return -1;
	}

	long int val = 0;

	for (int i = 0; i < 4; ++i)
		val |= *m_cursor++ << (i * 8);

	*ok = true;
	return val;
}

// -------------------------------------------------------------------------------------------------
//
float Bytestream::read_float (bool* ok)
{
	int value = read_long (ok);

	if (*ok == false)
		return -1.0f;

	return reinterpret_cast<float&> (value);
}

// -------------------------------------------------------------------------------------------------
//
String Bytestream::read_string (bool* ok)
{
	// Zandronum sends strings of maximum 2048 characters, though it only
	// reads 2047-character long ones so I guess we can follow up and do
	// the same :-)
	static char buffer[MAX_NETWORK_STRING];
	unsigned char* stringEnd;
	unsigned char* stringBegin = m_cursor;
	unsigned char* end = m_data + allocated_size();

	// where's the end of the string?
	for (stringEnd = m_cursor; *stringEnd != '\0'; ++stringEnd)
	{
		if (stringEnd == end)
		{
			// past the end of the buffer! Argh!
			*ok = false;
			return "";
		}
	}

	m_cursor = stringEnd + 1;
	*ok = true;
	unsigned int length = stringEnd - m_cursor;

	// ensure we won't write past the buffer (note: we still moved
	// past the excess bytes in the above statement, those are ignored)
	if (length >= MAX_NETWORK_STRING)
		length = MAX_NETWORK_STRING - 1;

	memcpy (buffer, stringBegin, length);
	buffer[length] = '\0';
	return String (buffer);
}

// -------------------------------------------------------------------------------------------------
//
METHOD
Bytestream::read (unsigned char* buffer, unsigned long length, bool* ok) -> void
{
	if (bytes_left() < length)
	{
		*ok = false;
		return;
	}

	memcpy (buffer, m_cursor, length);
	m_cursor += length;
	*ok = true;
}

// -------------------------------------------------------------------------------------------------
//
void Bytestream::write (unsigned char val)
{
	*m_cursor++ = val;
	m_writtenLength++;
}

// -------------------------------------------------------------------------------------------------
//
void Bytestream::write (const unsigned char* val, unsigned int length)
{
	grow_to_fit (length);
	memcpy (m_cursor, val, length);
	m_cursor += length;
	m_writtenLength += length;
}

// -------------------------------------------------------------------------------------------------
//
void Bytestream::grow_to_fit (unsigned long bytes)
{
	if (space_left() < bytes)
		resize (allocated_size() + bytes + 128);
}

// -------------------------------------------------------------------------------------------------
//
void Bytestream::write_byte (char val)
{
	grow_to_fit (1);
	write (val);
}

// -------------------------------------------------------------------------------------------------
//
void Bytestream::write_short (short int val)
{
	grow_to_fit (2);

	for (int i = 0; i < 2; ++i)
		write ((val >> (i * 8)) & 0xFF);
}

// -------------------------------------------------------------------------------------------------
//
void Bytestream::write_long (long int val)
{
	grow_to_fit (4);

	for (int i = 0; i < 4; ++i)
		write ((val >> (i * 8)) & 0xFF);
}

// -------------------------------------------------------------------------------------------------
//
void Bytestream::write_float (float val)
{
	// I know this is probably dangerous but this is what Zandronum does so yeah
	write_long (reinterpret_cast<int&> (val));
}

// -------------------------------------------------------------------------------------------------
//
void Bytestream::write_string (const String& val)
{
	grow_to_fit (val.length() + 1);
	write (reinterpret_cast<const unsigned char*> (val.chars()), val.length());
	write (0);
}

// -------------------------------------------------------------------------------------------------
//
void Bytestream::write_buffer (const Bytestream& other)
{
	write (other.data(), other.written_length());
}

mercurial