forked from speed-dreams/speed-dreams-code
add pack.cpp & pack.h
git-svn-id: https://svn.code.sf.net/p/speed-dreams/code/trunk@4974 30fe4595-0a0c-4342-8851-515496e4dcbd Former-commit-id: 9a602efee2ab073ea5fb218c17d8c7c91405e676 Former-commit-id: 05b4fc2de34208e3c896c8204e91fbdb62d110ef
This commit is contained in:
parent
7c71b19968
commit
db11f66865
2 changed files with 591 additions and 0 deletions
513
src/modules/networking/pack.cpp
Normal file
513
src/modules/networking/pack.cpp
Normal file
|
@ -0,0 +1,513 @@
|
|||
/* pack.cpp - convert to (pack) and from (unpack) network data format
|
||||
*
|
||||
* Created: 2012-09-28
|
||||
* Author: Tom Low-Shang
|
||||
*
|
||||
* Original: http://bzflag.svn.sourceforge.net/viewvc/bzflag/trunk/bzflag/src/net/Pack.cxx?view=markup
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the license found in the file named COPYING that should
|
||||
* have accompanied this file.
|
||||
*
|
||||
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifdef _WIN32
|
||||
# if defined(_MSC_VER)
|
||||
# pragma warning(disable: 4786)
|
||||
# endif
|
||||
# include <winsock2.h>
|
||||
# include <ws2tcpip.h>
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32)
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
/* SDL data types */
|
||||
#include <SDL_stdinc.h>
|
||||
|
||||
/* SDL endian swap functions */
|
||||
#include <SDL_endian.h>
|
||||
|
||||
#include <tgf.h>
|
||||
#include "pack.h"
|
||||
|
||||
union float_uint32 {
|
||||
float floatval;
|
||||
Uint32 intval;
|
||||
};
|
||||
|
||||
union double_uint64 {
|
||||
double d;
|
||||
Uint64 i;
|
||||
};
|
||||
|
||||
// Initialize for packing
|
||||
PackedBuffer::PackedBuffer(size_t size)
|
||||
{
|
||||
buf_start = new Uint8[size];
|
||||
buf_data = buf_start;
|
||||
buf_size = size;
|
||||
buf_is_ours = true;
|
||||
data_length = 0;
|
||||
}
|
||||
|
||||
// Initialize of unpacking
|
||||
PackedBuffer::PackedBuffer(unsigned char *buf, size_t len)
|
||||
{
|
||||
buf_start = buf_data = buf;
|
||||
buf_size = len;
|
||||
buf_is_ours = false;
|
||||
data_length = 0;
|
||||
}
|
||||
|
||||
PackedBuffer::~PackedBuffer()
|
||||
{
|
||||
if (buf_is_ours)
|
||||
{
|
||||
delete [] buf_start;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char *PackedBuffer::buffer()
|
||||
{
|
||||
return buf_start;
|
||||
}
|
||||
|
||||
size_t PackedBuffer::length()
|
||||
{
|
||||
return buf_is_ours ? data_length : buf_size;
|
||||
}
|
||||
|
||||
void PackedBuffer::next_data(size_t data_size)
|
||||
{
|
||||
buf_data = buf_data + data_size;
|
||||
data_length += data_size;
|
||||
}
|
||||
|
||||
bool PackedBuffer::bounds_error(size_t item_size)
|
||||
{
|
||||
return data_length + item_size > buf_size;
|
||||
}
|
||||
|
||||
void PackedBuffer::pack_ubyte(unsigned char v)
|
||||
{
|
||||
const size_t size = sizeof(Uint8);
|
||||
|
||||
if (bounds_error(size))
|
||||
{
|
||||
GfLogError("pack_ubyte: buffer overflow: buf_size=%d "
|
||||
"data_length=%d\n", buf_size, data_length);
|
||||
throw PackedBufferException();
|
||||
}
|
||||
|
||||
Uint8 w = (Uint8)v;
|
||||
|
||||
::memcpy(buf_data, &w, size);
|
||||
next_data(size);
|
||||
}
|
||||
|
||||
void PackedBuffer::pack_short(short v)
|
||||
{
|
||||
const size_t size = sizeof(Sint16);
|
||||
|
||||
if (bounds_error(size))
|
||||
{
|
||||
GfLogError("pack_short: buffer overflow: buf_size=%d "
|
||||
"data_length=%d\n", buf_size, data_length);
|
||||
throw PackedBufferException();
|
||||
}
|
||||
|
||||
const Uint16 x = (Uint16)htons((Uint16)v);
|
||||
|
||||
::memcpy(buf_data, &x, size);
|
||||
next_data(size);
|
||||
}
|
||||
|
||||
void PackedBuffer::pack_int(int v)
|
||||
{
|
||||
const size_t size = sizeof(Sint32);
|
||||
|
||||
if (bounds_error(size))
|
||||
{
|
||||
GfLogError("pack_int: buffer overflow: buf_size=%d "
|
||||
"data_length=%d\n", buf_size, data_length);
|
||||
throw PackedBufferException();
|
||||
}
|
||||
|
||||
const Uint32 x = (Uint32)htonl((Uint32)v);
|
||||
|
||||
::memcpy(buf_data, &x, size);
|
||||
next_data(size);
|
||||
}
|
||||
|
||||
void PackedBuffer::pack_ushort(unsigned short v)
|
||||
{
|
||||
const size_t size = sizeof(Uint16);
|
||||
|
||||
if (bounds_error(size))
|
||||
{
|
||||
GfLogError("pack_ushort: buffer overflow: buf_size=%d "
|
||||
"data_length=%d\n", buf_size, data_length);
|
||||
throw PackedBufferException();
|
||||
}
|
||||
|
||||
const Uint16 x = (Uint16)htons((Uint16)v);
|
||||
|
||||
::memcpy(buf_data, &x, size);
|
||||
next_data(size);
|
||||
}
|
||||
|
||||
void PackedBuffer::pack_uint(unsigned int v)
|
||||
{
|
||||
const size_t size = sizeof(Uint32);
|
||||
|
||||
if (bounds_error(size))
|
||||
{
|
||||
GfLogError("pack_uint: buffer overflow: buf_size=%d "
|
||||
"data_length=%d\n", buf_size, data_length);
|
||||
throw PackedBufferException();
|
||||
}
|
||||
|
||||
const Uint32 x = (Uint32)htonl((Uint32)v);
|
||||
|
||||
::memcpy(buf_data, &x, size);
|
||||
next_data(size);
|
||||
}
|
||||
|
||||
|
||||
void PackedBuffer::pack_float(float v)
|
||||
{
|
||||
const size_t size = sizeof(Uint32);
|
||||
|
||||
if (bounds_error(size))
|
||||
{
|
||||
GfLogError("pack_float: buffer overflow: buf_size=%d "
|
||||
"data_length=%d\n", buf_size, data_length);
|
||||
throw PackedBufferException();
|
||||
}
|
||||
|
||||
// assume that float is a 4 byte IEEE 754 standard encoding
|
||||
float_uint32 u;
|
||||
u.floatval = v;
|
||||
|
||||
const Uint32 x = (Uint32)htonl(u.intval);
|
||||
|
||||
::memcpy(buf_data, &x, size);
|
||||
next_data(size);
|
||||
}
|
||||
|
||||
/* There are no standard 64bit network endian swap functions. SDL has two types
|
||||
* of endian swap functions that either always swaps, or only swaps to native
|
||||
* endianness. For packing use a function from the first group on little endian
|
||||
* systems. On big endian systems, use direct copy. Functions from the second
|
||||
* group are good for unpacking.
|
||||
*/
|
||||
void PackedBuffer::pack_double(double v) { const size_t size = sizeof(Uint64);
|
||||
|
||||
if (bounds_error(size))
|
||||
{
|
||||
GfLogError("pack_double: buffer overflow: buf_size=%d "
|
||||
"data_length=%d\n", buf_size, data_length);
|
||||
throw PackedBufferException();
|
||||
}
|
||||
|
||||
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
|
||||
// assume that double is a 8 byte IEEE 754 standard encoding
|
||||
double_uint64 u;
|
||||
u.d = v;
|
||||
|
||||
const Uint64 x = SDL_Swap64(u.i);
|
||||
|
||||
::memcpy(buf_data, &x, size);
|
||||
next_data(size);
|
||||
#else
|
||||
const Uint64 x = v;
|
||||
|
||||
::memcpy(buf_data, &x, size);
|
||||
next_data(size);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* How does SD store vectors? This method should modified accordingly or
|
||||
* if it is unnecesary.
|
||||
*/
|
||||
void PackedBuffer::pack_vector(const float *v)
|
||||
{
|
||||
const size_t size = 3 * sizeof(Uint32);
|
||||
|
||||
if (bounds_error(size))
|
||||
{
|
||||
GfLogError("pack_vector: buffer overflow: buf_size=%d "
|
||||
"data_length=%d\n", buf_size, data_length);
|
||||
throw PackedBufferException();
|
||||
}
|
||||
|
||||
// assume that float is a 4 byte IEEE 754 standard encoding
|
||||
float_uint32 u;
|
||||
Uint32 data[3];
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
u.floatval = v[i];
|
||||
data[i] = (Uint32)htonl(u.intval);
|
||||
}
|
||||
|
||||
::memcpy(buf_data, data, size);
|
||||
next_data(size);
|
||||
}
|
||||
|
||||
/* "String" means "a buffer of known length" in a network message context.
|
||||
* "Known length" could mean fixed length or variable length if the length is
|
||||
* included in the message
|
||||
*/
|
||||
void PackedBuffer::pack_string(const void *m, int len)
|
||||
{
|
||||
if (bounds_error(len))
|
||||
{
|
||||
GfLogError("pack_string: buffer overflow: buf_size=%d "
|
||||
"data_length=%d\n", buf_size, data_length);
|
||||
throw PackedBufferException();
|
||||
}
|
||||
|
||||
if (!m || len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
::memcpy(buf_data, m, len);
|
||||
next_data(len);
|
||||
}
|
||||
|
||||
void PackedBuffer::pack_stdstring(const std::string& str)
|
||||
{
|
||||
const size_t size = str.size();
|
||||
|
||||
if (bounds_error(size))
|
||||
{
|
||||
GfLogError("pack_stdstring: buffer overflow: buf_size=%d "
|
||||
"data_length=%d\n", buf_size, data_length);
|
||||
throw PackedBufferException();
|
||||
}
|
||||
|
||||
pack_uint(size);
|
||||
pack_string(str.c_str(), size);
|
||||
}
|
||||
|
||||
unsigned char PackedBuffer::unpack_ubyte()
|
||||
{
|
||||
const size_t size = sizeof(Uint8);
|
||||
|
||||
if (bounds_error(size))
|
||||
{
|
||||
GfLogError("unpack_ubyte: buffer overrun: buf_size=%d "
|
||||
"data_length=%d\n", buf_size, data_length);
|
||||
throw PackedBufferException();
|
||||
}
|
||||
|
||||
Uint8 v;
|
||||
|
||||
::memcpy(&v, buf_data, size);
|
||||
next_data(size);
|
||||
|
||||
return (unsigned char)v;
|
||||
}
|
||||
|
||||
short PackedBuffer::unpack_short()
|
||||
{
|
||||
const size_t size = sizeof(Sint16);
|
||||
|
||||
if (bounds_error(size))
|
||||
{
|
||||
GfLogError("unpack_short: buffer overrun: buf_size=%d "
|
||||
"data_length=%d\n", buf_size, data_length);
|
||||
throw PackedBufferException();
|
||||
}
|
||||
|
||||
Sint16 x;
|
||||
|
||||
::memcpy(&x, buf_data, size);
|
||||
next_data(size);
|
||||
|
||||
return (short)ntohs(x);
|
||||
}
|
||||
|
||||
int PackedBuffer::unpack_int()
|
||||
{
|
||||
const size_t size = sizeof(Sint32);
|
||||
|
||||
if (bounds_error(size))
|
||||
{
|
||||
GfLogError("unpack_int: buffer overrun: buf_size=%d "
|
||||
"data_length=%d\n", buf_size, data_length);
|
||||
throw PackedBufferException();
|
||||
}
|
||||
|
||||
Sint32 x;
|
||||
|
||||
::memcpy(&x, buf_data, size);
|
||||
next_data(size);
|
||||
|
||||
return (int)ntohl(x);
|
||||
}
|
||||
|
||||
unsigned short PackedBuffer::unpack_ushort()
|
||||
{
|
||||
const size_t size = sizeof(Uint16);
|
||||
|
||||
if (bounds_error(size))
|
||||
{
|
||||
GfLogError("unpack_ushort: buffer overrun: buf_size=%d "
|
||||
"data_length=%d\n", buf_size, data_length);
|
||||
throw PackedBufferException();
|
||||
}
|
||||
|
||||
Uint16 x;
|
||||
|
||||
::memcpy(&x, buf_data, size);
|
||||
next_data(size);
|
||||
|
||||
return (unsigned short)ntohs(x);
|
||||
}
|
||||
|
||||
unsigned int PackedBuffer::unpack_uint()
|
||||
{
|
||||
const size_t size = sizeof(Uint32);
|
||||
|
||||
if (bounds_error(size))
|
||||
{
|
||||
GfLogError("unpack_uint: buffer overrun: buf_size=%d "
|
||||
"data_length=%d\n", buf_size, data_length);
|
||||
throw PackedBufferException();
|
||||
}
|
||||
|
||||
Uint32 x;
|
||||
|
||||
::memcpy(&x, buf_data, size);
|
||||
next_data(size);
|
||||
|
||||
return (unsigned int)ntohl(x);
|
||||
}
|
||||
|
||||
float PackedBuffer::unpack_float()
|
||||
{
|
||||
const size_t size = sizeof(Uint32);
|
||||
|
||||
if (bounds_error(size))
|
||||
{
|
||||
GfLogError("unpack_float: buffer overrun: buf_size=%d "
|
||||
"data_length=%d\n", buf_size, data_length);
|
||||
throw PackedBufferException();
|
||||
}
|
||||
|
||||
// assume that float is a 4 byte IEEE 754 standard encoding
|
||||
Uint32 x;
|
||||
float_uint32 u;
|
||||
|
||||
::memcpy(&x, buf_data, size);
|
||||
next_data(size);
|
||||
u.intval = (Uint32)ntohl(x);
|
||||
|
||||
return u.floatval;
|
||||
}
|
||||
|
||||
/* The SDL_Swap{BE,LE} functions swap from the specified endianness (BE or LE)
|
||||
* to native and are no-operations if the endianness is the same.
|
||||
*/
|
||||
double PackedBuffer::unpack_double()
|
||||
{
|
||||
const size_t size = sizeof(Uint64);
|
||||
|
||||
if (bounds_error(size))
|
||||
{
|
||||
GfLogError("unpack_double: buffer overrun: buf_size=%d "
|
||||
"data_length=%d\n", buf_size, data_length);
|
||||
throw PackedBufferException();
|
||||
}
|
||||
|
||||
// assume that double is a 8 byte IEEE 754 standard encoding
|
||||
Uint64 x;
|
||||
double_uint64 u;
|
||||
|
||||
::memcpy(&x, buf_data, size);
|
||||
next_data(size);
|
||||
u.i = SDL_SwapBE64(x);
|
||||
|
||||
return u.d;
|
||||
}
|
||||
|
||||
float *PackedBuffer::unpack_vector(float *v)
|
||||
{
|
||||
const size_t size = 3 * sizeof(Uint32);
|
||||
|
||||
if (bounds_error(size))
|
||||
{
|
||||
GfLogError("unpack_vector: buffer overrun: buf_size=%d "
|
||||
"data_length=%d\n", buf_size, data_length);
|
||||
throw PackedBufferException();
|
||||
}
|
||||
|
||||
// assume that float is a 4 byte IEEE 754 standard encoding
|
||||
Uint32 data[3];
|
||||
float_uint32 u;
|
||||
|
||||
::memcpy(data, buf_data, size);
|
||||
next_data(size);
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
u.intval = (Uint32)ntohl(data[i]);
|
||||
v[i] = u.floatval;
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
void *PackedBuffer::unpack_string(void *m, int len)
|
||||
{
|
||||
if (bounds_error(len))
|
||||
{
|
||||
GfLogError("unpack_string: buffer overrun: buf_size=%d "
|
||||
"data_length=%d\n", buf_size, data_length);
|
||||
throw PackedBufferException();
|
||||
}
|
||||
|
||||
::memcpy(m, buf_data, len);
|
||||
next_data(len);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
std::string &PackedBuffer::unpack_stdstring(std::string& str)
|
||||
{
|
||||
const Uint32 size = unpack_uint();
|
||||
|
||||
if (bounds_error(size))
|
||||
{
|
||||
GfLogError("unpack_stdstring: packed overrun: buf_size=%d "
|
||||
"data_length=%d\n", buf_size, data_length);
|
||||
throw PackedBufferException();
|
||||
}
|
||||
|
||||
char *buffer = new char[size + 1];
|
||||
|
||||
unpack_string(buffer, size);
|
||||
buffer[size] = 0;
|
||||
str = buffer;
|
||||
|
||||
delete [] buffer;
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
// Local Variables: ***
|
||||
// mode:C++ ***
|
||||
// tab-width: 8 ***
|
||||
// c-basic-offset: 2 ***
|
||||
// indent-tabs-mode: t ***
|
||||
// End: ***
|
||||
// ex: shiftwidth=4 tabstop=8
|
||||
|
78
src/modules/networking/pack.h
Normal file
78
src/modules/networking/pack.h
Normal file
|
@ -0,0 +1,78 @@
|
|||
/* pack.h - convert to (pack) and from (unpack) network data format
|
||||
*
|
||||
* Created: 2012-09-28
|
||||
* Author: Tom Low-Shang
|
||||
*
|
||||
* Original: http://bzflag.svn.sourceforge.net/viewvc/bzflag/trunk/bzflag/include/Pack.h?view=markup
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the license found in the file named COPYING that should
|
||||
* have accompanied this file.
|
||||
*
|
||||
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
#ifndef SD_PACK_H
|
||||
#define SD_PACK_H
|
||||
|
||||
#include <string>
|
||||
/* SDL data types */
|
||||
#include <SDL_stdinc.h>
|
||||
|
||||
class PackedBuffer
|
||||
{
|
||||
public:
|
||||
PackedBuffer(size_t size=1024);
|
||||
PackedBuffer(unsigned char *, size_t);
|
||||
~PackedBuffer();
|
||||
|
||||
unsigned char *buffer();
|
||||
size_t length();
|
||||
|
||||
void pack_ubyte(unsigned char);
|
||||
void pack_short(short);
|
||||
void pack_int(int);
|
||||
void pack_ushort(unsigned short);
|
||||
void pack_uint(unsigned int);
|
||||
void pack_float(float);
|
||||
void pack_double(double);
|
||||
void pack_vector(const float*);
|
||||
void pack_string(const void*, int);
|
||||
void pack_stdstring(const std::string& str);
|
||||
|
||||
unsigned char unpack_ubyte();
|
||||
short unpack_short();
|
||||
int unpack_int();
|
||||
unsigned short unpack_ushort();
|
||||
unsigned int unpack_uint();
|
||||
float unpack_float();
|
||||
double unpack_double();
|
||||
float* unpack_vector(float*);
|
||||
void* unpack_string(void*, int len);
|
||||
std::string& unpack_stdstring(std::string& str);
|
||||
|
||||
private:
|
||||
size_t buf_size;
|
||||
Uint8 *buf_start;
|
||||
Uint8 *buf_data;
|
||||
bool buf_is_ours;
|
||||
size_t data_length;
|
||||
|
||||
void next_data(size_t);
|
||||
bool bounds_error(size_t);
|
||||
};
|
||||
|
||||
class PackedBufferException : public std::exception
|
||||
{
|
||||
};
|
||||
|
||||
#endif // SD_PACK_H
|
||||
|
||||
// Local Variables: ***
|
||||
// mode:C++ ***
|
||||
// tab-width: 8 ***
|
||||
// c-basic-offset: 2 ***
|
||||
// indent-tabs-mode: t ***
|
||||
// End: ***
|
||||
// ex: shiftwidth=4 tabstop=8
|
Loading…
Reference in a new issue