support for building without Network/Graphics, although the disable-graphics case is kind of hackish still
#include "Buffer.hh"
#include "../Config.hh"
#include <ClanLib/core.h>
#include <cstdlib>
/*
* NetworkBufferBase
*/
NetworkBufferBase::NetworkBufferBase (NetworkSocket *socket, size_t size_hint) :
socket(socket), buf(0), size(0), offset(0) {
// allocate initial buffer
if ((buf = (char *) malloc(size_hint)) == NULL)
throw NetworkBufferError("malloc failed");
// remember size
size = size_hint;
}
NetworkBufferBase::~NetworkBufferBase (void) {
free(buf);
}
void NetworkBufferBase::resize (size_t item_size) {
size_t new_size = size;
// make sure that new_size isn't zero, because zero times two is zero, even if you try and calculate that in an
// infinite loop :)
if (new_size == 0)
new_size = 1;
// grow new_size until item_size fits
while (offset + item_size > new_size)
new_size *= 2;
// grow if needed
if (new_size != size) {
char *temp = buf;
// realloc buffer
if ((buf = (char *) realloc((void *) buf, new_size)) == NULL) {
// restore temp, but the buffer may be corrupted now
buf = temp;
// raise error
throw NetworkBufferError("realloc failed");
}
// update size
size = new_size;
} else if (size > (offset + item_size) * 4) {
// XXX: shrink?
}
}
void NetworkBufferBase::trim (size_t prefix_size) {
// update offset
offset -= prefix_size;
// shift the buffer forwards from (buf + prefix) -> (buf), copying (old_offset - prefix) bytes
memmove(buf, buf + prefix_size, offset);
}
/*
* NetworkBufferInput
*/
NetworkBufferInput::NetworkBufferInput (NetworkSocket *socket, size_t size_hint) :
NetworkBufferBase(socket, size_hint)
{
}
bool NetworkBufferInput::try_read (size_t item_size) {
size_t ret, to_read = item_size;
// keept reads at at least NETWORK_BUFFER_CHUNK_SIZE bytes
if (to_read < NETWORK_BUFFER_CHUNK_SIZE)
to_read = NETWORK_BUFFER_CHUNK_SIZE;
// resize buffer if needed
resize(to_read);
// read once
ret = socket->recv(buf + offset, to_read);
// nothing left?
if (ret == 0)
return false;
// update offset
offset += ret;
// did we get enough?
if ((unsigned int) ret < item_size)
return false;
else
return true;
}
bool NetworkBufferInput::have_data (size_t data_size) {
return (offset >= data_size);
}
bool NetworkBufferInput::peek_prefix (uint16_t &val_ref) {
if (!have_data(sizeof(uint16_t)))
return false;
val_ref = ntohs(*((uint16_t *) (buf)));
return true;
}
bool NetworkBufferInput::peek_prefix (uint32_t &val_ref) {
if (!have_data(sizeof(uint32_t)))
return false;
val_ref = ntohl(*((uint32_t *) (buf)));
return true;
}
/*
* NetworkBufferOutput
*/
NetworkBufferOutput::NetworkBufferOutput (NetworkSocket *socket, size_t size_hint) :
NetworkBufferBase(socket, size_hint)
{
}
void NetworkBufferOutput::push_write (char *buf_ptr, size_t buf_size) {
size_t ret;
// try and short-circuit writes unless we have already buffered data
if (offset == 0) {
// attempt to send something
ret = socket->send(buf_ptr, buf_size);
// if we managed to send something, adjust buf/size and buffer
if (ret > 0) {
// sanity-check
assert(buf_size >= (unsigned int) ret);
buf_ptr += ret;
buf_size -= ret;
// if that was all, we're done
if (buf_size == 0)
return;
}
}
// resize to fit buf_size more bytes
resize(buf_size);
// copy into our internal buffer
memcpy(buf + offset, buf_ptr, buf_size);
}
bool NetworkBufferOutput::flush_write (void) {
size_t ret;
// ignore if we don't have any data buffered
if (offset == 0)
return false;
// attempt to write as much as possible
ret = socket->send(buf, offset);
// busy?
if (ret == 0)
return true;
// trim the buffer
trim(ret);
// anything left?
return (offset > 0);
}
bool NetworkBufferOutput::write_prefix (char *buf, uint16_t prefix) {
uint16_t nval = htons(prefix);
// XXX: not exception-safe
push_write((char*) &nval, sizeof(uint16_t));
push_write(buf, prefix);
// anything in the buffer?
return (offset > 0);
}
bool NetworkBufferOutput::write_prefix (char *buf, uint32_t prefix) {
uint32_t nval = htonl(prefix);
// XXX: not exception-safe
push_write((char*) &nval, sizeof(uint32_t));
push_write(buf, prefix);
// anything in the buffer?
return (offset > 0);
}