/*] Copyright (c) 2009-2010, Charles McGarvey [************************** **] All rights reserved. * * vi:ts=4 sw=4 tw=75 * * Distributable under the terms and conditions of the 2-clause BSD license; * see the file COPYING for a complete text of the license. * **************************************************************************/ #include "../config.h" #include #if HAVE_BYTESWAP_H #include #endif #include #if HAVE_ARPA_INET_H #include #endif #include #include "Packet.hh" #ifndef bswap_16 #define bswap_16(x) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8)) #endif #ifndef bswap_32 #define bswap_32(x) ((((x) & 0xff000000) >> 24) | \ (((x) & 0x00ff0000) >> 8) | \ (((x) & 0x0000ff00) << 8) | \ (((x) & 0x000000ff) << 24)) #endif #ifndef bswap_64 #define bswap_64(x) (((x) << 56) | \ (((x) << 40) & 0xff000000000000ULL) | \ (((x) << 24) & 0xff0000000000ULL) | \ (((x) << 8) & 0xff00000000ULL) | \ (((x) >> 8) & 0xff000000ULL) | \ (((x) >> 24) & 0xff0000ULL) | \ (((x) >> 40) & 0xff00ULL) | \ ((x) >> 56)) #endif #if !HAVE_ARPA_INET_H static uint16_t htons(uint16_t x) { #if SDL_BYTEORDER == SDL_LIL_ENDIAN return bswap_16(x); #else return x; #endif } static uint16_t ntohs(uint16_t x) { return htons(x); } static uint32_t htonl(uint32_t x) { #if SDL_BYTEORDER == SDL_LIL_ENDIAN return bswap_32(x); #else return x; #endif } static uint32_t ntohl(uint32_t x) { return htonl(x); } #endif static uint64_t htonll(uint64_t x) { #if SDL_BYTEORDER == SDL_LIL_ENDIAN return bswap_64(x); #else return x; #endif } static uint64_t ntohll(uint64_t x) { return htonll(x); } namespace Mf { Packet::Packet(size_t size) : mBuffer((char*)malloc(size)), mSize(size), mR(0), mW(0), mOriginalW(0), mBoolR(0), mBoolW(0), mBoolNumR(0), mBoolNumW(0) {} Packet::Packet(const char* data, size_t size) : mBuffer((char*)malloc(size)), mSize(size), mR(0), mW(size), mOriginalW(size), mBoolR(0), mBoolW(0), mBoolNumR(0), mBoolNumW(0) { if (mBuffer) memcpy(mBuffer, data, size); else throw std::length_error("out of memory"); } Packet::Packet(const Packet& copy) : mBuffer((char*)malloc(copy.mSize)), mSize(copy.mSize), mR(copy.mR), mW(copy.mW), mOriginalW(copy.mOriginalW), mBoolR(copy.mBoolR), mBoolW(copy.mBoolW), mBoolNumR(copy.mBoolNumR), mBoolNumW(copy.mBoolNumW) { if (mBuffer) memcpy(mBuffer, copy.mBuffer, mSize); else throw std::length_error("out of memory"); } Packet& Packet::operator=(const Packet& copy) { free(mBuffer); mBuffer = (char*)malloc(copy.mSize); mSize = copy.mSize; mR = copy.mR; mW = copy.mW; mOriginalW = copy.mOriginalW; mBoolR = copy.mBoolR; mBoolW = copy.mBoolW; mBoolNumR = copy.mBoolNumR; mBoolNumW = copy.mBoolNumW; if (mBuffer) memcpy(mBuffer, copy.mBuffer, mSize); else throw std::length_error("out of memory"); return *this; } Packet::~Packet() { free(mBuffer); } Packet& Packet::operator<<(bool value) { int bit = mBoolNumW % 8; if (bit == 0) { mBoolW = mW; unsigned char byte = 0; if (write(&byte, 1) == 0) throw std::length_error("out of memory"); } if (value) mBuffer[mBoolW] |= (1 << bit); ++mBoolNumW; return *this; } Packet& Packet::operator<<(int8_t value) { return *this << (uint8_t)value; } Packet& Packet::operator<<(int16_t value) { return *this << (uint16_t)value; } Packet& Packet::operator<<(int32_t value) { return *this << (uint32_t)value; } Packet& Packet::operator<<(int64_t value) { return *this << (uint64_t)value; } Packet& Packet::operator<<(uint8_t value) { if (write(&value, sizeof(value)) != sizeof(value)) { throw std::length_error("out of memory"); } return *this; } Packet& Packet::operator<<(uint16_t value) { value = htons(value); if (write(&value, sizeof(value)) != sizeof(value)) { throw std::length_error("out of memory"); } return *this; } Packet& Packet::operator<<(uint32_t value) { value = htonl(value); if (write(&value, sizeof(value)) != sizeof(value)) { throw std::length_error("out of memory"); } return *this; } Packet& Packet::operator<<(uint64_t value) { value = htonll(value); if (write(&value, sizeof(value)) != sizeof(value)) { throw std::length_error("out of memory"); } return *this; } Packet& Packet::operator<<(float value) { // XXX: assumes the ieee-754 uint32_t* integer = reinterpret_cast(&value); *integer = htonl(*integer); if (write(integer, sizeof(value)) != sizeof(value)) { throw std::length_error("out of memory"); } return *this; } Packet& Packet::operator<<(double value) { // XXX: assumes the ieee-754 uint64_t* integer = reinterpret_cast(&value); *integer = htonll(*integer); if (write(integer, sizeof(value)) != sizeof(value)) { throw std::length_error("out of memory"); } return *this; } size_t Packet::write(const void* bytes, size_t size) { size_t nBytes = std::min(size, mSize - mW); if (!mBuffer || nBytes < size) { int nPages = 1 + size / PAGE_SIZE; int newSize = mSize + nPages * PAGE_SIZE; char* newBuffer = (char*)realloc(mBuffer, newSize); if (newBuffer) { mBuffer = newBuffer; mSize = newSize; nBytes = size; } if (!mBuffer) return 0; } memcpy(mBuffer + mW, bytes, nBytes); mW += nBytes; return nBytes; } Packet& Packet::operator>>(bool& value) { int bit = mBoolNumR % 8; if (bit == 0) { mBoolR = mR; unsigned char byte = 0; if (read(&byte, 1) == 0) throw std::out_of_range("end of packet"); } value = 1 & (mBuffer[mBoolR] >> bit); ++mBoolNumR; return *this; } Packet& Packet::operator>>(int8_t& value) { return *this >> (uint8_t&)value; } Packet& Packet::operator>>(int16_t& value) { return *this >> (uint16_t&)value; } Packet& Packet::operator>>(int32_t& value) { return *this >> (uint32_t&)value; } Packet& Packet::operator>>(int64_t& value) { return *this >> (uint64_t&)value; } Packet& Packet::operator>>(uint8_t& value) { if (read(&value, sizeof(value)) != sizeof(value)) { throw std::out_of_range("end of packet"); } return *this; } Packet& Packet::operator>>(uint16_t& value) { if (read(&value, sizeof(value)) != sizeof(value)) { throw std::out_of_range("end of packet"); } value = ntohs(value); return *this; } Packet& Packet::operator>>(uint32_t& value) { if (read(&value, sizeof(value)) != sizeof(value)) { throw std::out_of_range("end of packet"); } value = ntohl(value); return *this; } Packet& Packet::operator>>(uint64_t& value) { if (read(&value, sizeof(value)) != sizeof(value)) { throw std::out_of_range("end of packet"); } value = ntohll(value); return *this; } Packet& Packet::operator>>(float& value) { // XXX: assumes the ieee-754 uint32_t* integer = reinterpret_cast(&value); if (read(integer, sizeof(value)) != sizeof(value)) { throw std::out_of_range("end of packet"); } *integer = htonl(*integer); return *this; } Packet& Packet::operator>>(double& value) { // XXX: assumes the ieee-754 uint64_t* integer = reinterpret_cast(&value); if (read(integer, sizeof(value)) != sizeof(value)) { throw std::out_of_range("end of packet"); } *integer = htonll(*integer); return *this; } size_t Packet::read(void* bytes, size_t size) { size_t nBytes = std::min(size, mW - mR); memcpy(bytes, mBuffer + mR, nBytes); mR += nBytes; return nBytes; } void Packet::clear() { mR = 0; mW = 0; mBoolR = 0; mBoolW = 0; mBoolNumR = 0; mBoolNumW = 0; } void Packet::reset() { mR = 0; mW = mOriginalW; mBoolR = 0; mBoolW = 0; mBoolNumR = 0; mBoolNumW = 0; } } // namespace Mf