openmohaa/code/gamespy/gt2/gt2Encode.c

649 lines
14 KiB
C
Raw Permalink Normal View History

2023-02-04 21:00:01 +01:00
#include <stdarg.h>
#include <string.h>
#include "gt2Encode.h"
#include "gt2Main.h"
// This handles alignment issues and endianess
void gt2MemCopy16(char *out, char const *in)
{
#ifdef _GT2_ENDIAN_CONVERT
*out = in[1];
out[1] = *in;
#else
// straight copy
*out = *in;
out[1] = in[1];
#endif
}
// This handles alignment issues and endianess
void gt2MemCopy32(char *out, char const *in)
{
#ifdef _GT2_ENDIAN_CONVERT
out[0] = in[3];
out[1] = in[2];
out[2] = in[1];
out[3] = in[0];
#else
// straight copy
*out = *in;
out[1] = in[1];
out[2] = in[2];
out[3] = in[3];
#endif
}
// This handles alignment issues and endianess
void gt2MemCopy64(char *out, char const *in)
{
#ifdef _GT2_ENDIAN_CONVERT
out[0] = in[7];
out[1] = in[6];
out[2] = in[5];
out[3] = in[4];
out[4] = in[3];
out[5] = in[2];
out[6] = in[1];
out[7] = in[0];
#else
// straight copy
memcpy(out, in, 8);
#endif
}
void gt2MemCopy(char *out, char const *in, int size)
{
if (size == 2)
{
gt2MemCopy16(out, in);
}
else
if (size == 4)
{
gt2MemCopy32(out, in);
}
else
if (size == 8)
{
gt2MemCopy64(out, in);
}
else
{
// warning... no endianess decode.
memcpy(out,in,(size_t)size);
}
}
#if defined(_PS2) || defined(_UNIX) || defined(_PS3) || defined(_WIN64) || defined(_X360)
#define GT_ENCODE_ELEM(TYPE,b,l,args) \
{ \
TYPE v; \
if (l < sizeof(TYPE)) \
return -1; \
v = (TYPE)va_arg(*args, int); \
gt2MemCopy(b, (const char *)&v, sizeof(TYPE)); \
return (int)sizeof(TYPE); \
}
#define GT_DECODE_ELEM(TYPE,b,l,args) \
{ \
TYPE* v; \
if (l < sizeof(TYPE)) \
return -1; \
v = va_arg(*args, TYPE*); \
gt2MemCopy((char *)v, b, sizeof(TYPE)); \
return (int)sizeof(TYPE); \
}
#define GT_ENCODE_ELEM_NC(TYPE,b,l,args) \
{ \
TYPE v; \
if (l < sizeof(TYPE)) \
return -1; \
v = (TYPE)va_arg(*args, int); \
memcpy(b, &v, sizeof(TYPE)); \
return (int)sizeof(TYPE); \
}
#define GT_DECODE_ELEM_NC(TYPE,b,l,args) \
{ \
TYPE* v; \
if (l < sizeof(TYPE)) \
return -1; \
v = va_arg(*args, TYPE*); \
memcpy(v, b, sizeof(TYPE)); \
return (int)sizeof(TYPE); \
}
#else
#define GT_ENCODE_ELEM(TYPE,b,l,args) {if (l < sizeof(TYPE)) return -1; gt2MemCopy(b,(const char *)&va_arg(*args,TYPE),sizeof(TYPE)); return sizeof(TYPE);}
#define GT_DECODE_ELEM(TYPE,b,l,args) {if (l < sizeof(TYPE)) return -1; gt2MemCopy((char *)va_arg(*args,TYPE*),b,sizeof(TYPE)); return sizeof(TYPE);}
// nc = no endian convert
#define GT_ENCODE_ELEM_NC(TYPE,b,l,args) {if (l < sizeof(TYPE)) return -1; memcpy(b,&va_arg(*args,TYPE),sizeof(TYPE)); return sizeof(TYPE);}
#define GT_DECODE_ELEM_NC(TYPE,b,l,args) {if (l < sizeof(TYPE)) return -1; memcpy(va_arg(*args,TYPE*),b,sizeof(TYPE)); return sizeof(TYPE);}
#endif /* _PS || _UNIX */
static int dbstrlen(GT_DBSTR_TYPE dbstr)
{
int len = 0;
#ifdef ALIGNED_COPY
short achar;
do
{
memcpy(&achar, dbstr, sizeof(achar));
dbstr++;
len++;
} while (achar != 0);
len--;
#else
while (*dbstr++)
len++;
#endif
return len;
}
static short *dbstrcpy(GT_DBSTR_TYPE dest, GT_DBSTR_TYPE src)
{
GT_DBSTR_TYPE hold = dest;
#ifdef ALIGNED_COPY
int len = dbstrlen(src);
memcpy(dest, src, (unsigned int)(len + 1) * 2);
#else
while ((*dest++ = *src++) != 0) ;
#endif
return hold;
}
static int gtiDecodeBits(int bitcount, char *inBuffer, int inLength, va_list *args)
{
char bucket;
int i;
if (inLength < 1)
return -1;
bucket = *inBuffer;
for (i = 0 ; i < bitcount ; i++)
{
*va_arg(*args,char*) = (char)((bucket & (1 << i)) ? 1 : 0);
}
return 1;
}
static int gtiEncodeBits(int bitcount, char *outBuffer, int outLength, va_list *args)
{
char bucket = 0;
int i;
if (outLength < 1)
return -1;
for (i = 0 ; i < bitcount ; i++)
{
bucket |= (char)((va_arg(*args,int) ? 1 : 0) << i);
//bucket |= ((va_arg(*args,char) ? 1 : 0) << i);
}
*outBuffer = bucket;
return 1;
}
// length in bytes including NUL, or -1 if error
static int gtiCheckStringLen(char *inBuffer, int inLength)
{
int len = 0;
do
{
len++;
if(len > inLength)
return -1;
}
while(inBuffer[len - 1] != '\0');
return len;
}
// length in bytes (not chars) including NUL, or -1 if error
static int gtiCheckDoubleStringLen(char *inBuffer, int inLength)
{
int len = 0;
do
{
len += 2;
if(len > inLength)
return -1;
}
while((inBuffer[len - 2] != '\0') || (inBuffer[len - 1] != '\0'));
return len;
}
// length in bytes including NULs, or -1 if error
static int gtiCheckStringArrayLen(char *inBuffer, int inLength)
{
int len = 0;
int strLen;
do
{
strLen = gtiCheckStringLen(inBuffer + len, inLength - len);
if(strLen == -1)
return -1;
len += strLen;
}
while(strLen > 1);
return len;
}
static int gtiDecodeSingle(char elemType, char *inBuffer, int inLength, va_list *args)
{
switch (elemType)
{
case GT_INT:
GT_DECODE_ELEM(GT_INT_TYPE,inBuffer, inLength, args);
//break;
case GT_UINT:
GT_DECODE_ELEM(GT_UINT_TYPE,inBuffer, inLength, args);
//break;
case GT_SHORT:
GT_DECODE_ELEM(GT_SHORT_TYPE,inBuffer, inLength, args);
//break;
case GT_USHORT:
GT_DECODE_ELEM(GT_USHORT_TYPE,inBuffer, inLength, args);
//break;
case GT_CHAR:
GT_DECODE_ELEM(GT_CHAR_TYPE,inBuffer, inLength, args);
//break;
case GT_UCHAR:
GT_DECODE_ELEM(GT_UCHAR_TYPE,inBuffer, inLength, args);
//break;
case GT_FLOAT:
{
#if(0)
// no endian convert
GT_FLOAT_TYPE* v;
if (inLength < sizeof(GT_FLOAT_TYPE))
return -1;
v = va_arg(*args, GT_FLOAT_TYPE*);
v[0] = inBuffer[0];
v[1] = inBuffer[1];
v[2] = inBuffer[2];
v[3] = inBuffer[3];
return (int)sizeof(GT_FLOAT_TYPE);
#else
GT_DECODE_ELEM_NC(GT_FLOAT_TYPE,inBuffer, inLength, args);
#endif
}
case GT_DOUBLE:
#if(0)
// no endian convert
{ GT_DOUBLE_TYPE* v;
if (inLength < sizeof(GT_DOUBLE_TYPE))
return -1;
v = va_arg(*args, GT_DOUBLE_TYPE*);
v[0] = inBuffer[0];
v[1] = inBuffer[1];
v[2] = inBuffer[2];
v[3] = inBuffer[3];
v[4] = inBuffer[4];
v[5] = inBuffer[5];
v[6] = inBuffer[6];
v[7] = inBuffer[7];
return (int)sizeof(GT_DOUBLE_TYPE);
}
#else
GT_DECODE_ELEM_NC(GT_DOUBLE_TYPE,inBuffer, inLength, args);
#endif
//break;
case GT_BIT:
GT_DECODE_ELEM(GT_BIT_TYPE,inBuffer, inLength, args);
//break;
case GT_CSTR:
{
int len;
GT_CSTR_TYPE s = va_arg(*args, GT_CSTR_TYPE);
assert(s != NULL);
len = gtiCheckStringLen(inBuffer, inLength);
if(len == -1)
return -1;
memcpy(s, inBuffer, (size_t)len);
return len;
}
//break;
case GT_CSTR_PTR:
*va_arg(*args, GT_CSTR_PTR_TYPE) = (GT_CSTR_TYPE)inBuffer;
return gtiCheckStringLen(inBuffer, inLength);
//break;
case GT_DBSTR:
{
int len;
GT_DBSTR_TYPE s = va_arg(*args, GT_DBSTR_TYPE);
assert(s != NULL);
len = gtiCheckDoubleStringLen(inBuffer, inLength);
if (len == -1)
return -1;
memcpy(s, inBuffer, (size_t)len);
return len;
}
//break;
case GT_DBSTR_PTR:
*va_arg(*args, GT_DBSTR_PTR_TYPE) = (GT_DBSTR_TYPE)inBuffer;
return gtiCheckDoubleStringLen(inBuffer, inLength);
//break;
case GT_CSTR_ARRAY:
{
int len;
GT_CSTR_ARRAY_TYPE s = va_arg(*args, GT_CSTR_ARRAY_TYPE);
assert(s != NULL);
len = gtiCheckStringArrayLen(inBuffer, inLength);
if(len == -1)
return -1;
memcpy(s, inBuffer, (size_t)len);
return len;
}
//break;
case GT_CSTR_ARRAY_PTR:
*va_arg(*args, GT_CSTR_ARRAY_PTR_TYPE) = (GT_CSTR_ARRAY_TYPE)inBuffer;
return gtiCheckStringArrayLen(inBuffer, inLength);
//break;
case GT_RAW:
{
int *len, holdlen;
GT_RAW_TYPE data = va_arg(*args, GT_RAW_TYPE);
len = va_arg(*args, int *);
if (inLength < sizeof(*len))
return -1;
holdlen = *len;
memcpy(len, inBuffer, sizeof(*len));
if (*len > holdlen) //there isn't enough room in their dest!
return -1;
if (inLength < (int)sizeof(*len) + *len)
return -1;
memcpy(data, inBuffer + sizeof(*len), (unsigned int)*len);
return *len + (int)sizeof(*len);
}
case GT_RAW_PTR:
{
int *len;
*va_arg(*args, GT_RAW_PTR_TYPE) = (GT_RAW_TYPE)(inBuffer + sizeof(*len));
len = va_arg(*args, int *);
if (inLength < sizeof(*len))
return -1;
memcpy(len, inBuffer, sizeof(*len));
return *len + (int)sizeof(*len);
}
//break;
}
return -1; //bad type!
}
static int gtiEncodeSingle(char elemType, char *outBuffer, int outLength, va_list *args)
{
switch (elemType)
{
case GT_INT:
GT_ENCODE_ELEM(GT_INT_TYPE,outBuffer, outLength, args);
//break;
case GT_UINT:
GT_ENCODE_ELEM(GT_UINT_TYPE,outBuffer, outLength, args);
//break;
case GT_SHORT:
GT_ENCODE_ELEM(GT_SHORT_TYPE,outBuffer, outLength, args);
//break;
case GT_USHORT:
GT_ENCODE_ELEM(GT_USHORT_TYPE,outBuffer, outLength, args);
//break;
case GT_CHAR:
GT_ENCODE_ELEM(GT_CHAR_TYPE,outBuffer, outLength, args);
//break;
case GT_UCHAR:
GT_ENCODE_ELEM(GT_UCHAR_TYPE,outBuffer, outLength, args);
//break;
case GT_FLOAT: //floats are promoted to double in varargs, need to demote
{
double temp;
float f;
double v = va_arg(*args,double);
memcpy(&temp,&v,sizeof(double));
f = (float)temp;
if (outLength < sizeof(float))
return -1;
memcpy(outBuffer, &f, sizeof(float));
return sizeof(float);
}
//break;
case GT_DOUBLE:
{
double v;
if(outLength < sizeof(double))
return -1;
v = va_arg(*args, double);
memcpy(outBuffer, &v, sizeof(double));
return sizeof(double);
}
//break;
case GT_BIT:
GT_ENCODE_ELEM(GT_BIT_TYPE,outBuffer, outLength, args);
//break;
case GT_CSTR:
case GT_CSTR_PTR:
{
int len;
GT_CSTR_TYPE s = va_arg(*args, GT_CSTR_TYPE);
assert(s != NULL);
len = (int)strlen(s) + 1;
if (outLength < len )
return -1;
strcpy(outBuffer, s);
return len;
}
//break;
case GT_DBSTR:
case GT_DBSTR_PTR:
{
int len;
GT_DBSTR_TYPE s = va_arg(*args, GT_DBSTR_TYPE);
assert(s != NULL);
len = dbstrlen(s) + 1;
if (outLength < len * 2)
return -1;
dbstrcpy((short *)outBuffer, s);
return len * 2;
}
//break;
case GT_CSTR_ARRAY:
case GT_CSTR_ARRAY_PTR:
{
int len = 0;
int strLen;
GT_CSTR_ARRAY_TYPE s = va_arg(*args, GT_CSTR_ARRAY_TYPE);
assert(s != NULL);
do
{
strLen = (int)strlen(s + len) + 1;
len += strLen;
if(outLength < len)
return -1;
}
while(strLen != 1);
memcpy(outBuffer, s, (size_t)len);
return len;
}
//break;
case GT_RAW:
case GT_RAW_PTR:
{
int len;
GT_RAW_TYPE data = va_arg(*args, GT_RAW_TYPE);
len = va_arg(*args, int);
if (outLength < len + (int)sizeof(len))
return -1;
memcpy(outBuffer, &len, sizeof(len));
memcpy(outBuffer + sizeof(len), data, (unsigned int)len);
return len + (int)sizeof(len);
}
}
return -1; //bad type!
}
static int gtInternalEncodeV(int usetype, GTMessageType msgType, const char *fmtString, char *outBuffer, int outLength, va_list *args)
{
int elemSize;
int totSize = outLength;
const char *bitCounter;
//set the message type
if (usetype)
{
elemSize = sizeof(msgType);
if (outLength < elemSize)
return -1;
gt2MemCopy(outBuffer, (const char *)&msgType, elemSize);
outBuffer += elemSize;
outLength -= elemSize;
}
while (*fmtString)
{
if (*fmtString == GT_BIT) //see how many
{
for (bitCounter = fmtString; *bitCounter == GT_BIT && bitCounter - fmtString <= 8; bitCounter++)
{};
elemSize = gtiEncodeBits((int)(bitCounter - fmtString), outBuffer, outLength, args);
fmtString = bitCounter - 1;
} else
elemSize = gtiEncodeSingle(*fmtString, outBuffer, outLength, args);
if (elemSize < 0)
return -1; //out of space
outBuffer += elemSize;
outLength -= elemSize;
fmtString++;
}
return totSize - outLength;
}
int gtEncodeNoTypeV(const char *fmtString, char *outBuffer, int outLength, va_list *args)
{
return gtInternalEncodeV(0,0,fmtString, outBuffer, outLength, args);
}
int gtEncodeV(GTMessageType msgType, const char *fmtString, char *outBuffer, int outLength, va_list *args)
{
return gtInternalEncodeV(1,msgType,fmtString, outBuffer, outLength, args);
}
int gtEncode(GTMessageType msgType, const char *fmtString, char *outBuffer, int outLength, ...)
{
int rcode;
va_list args;
//set the values
va_start(args, outLength);
rcode = gtEncodeV(msgType, fmtString, outBuffer, outLength, &args);
va_end(args);
return rcode;
}
int gtEncodeNoType(const char *fmtString, char *outBuffer, int outLength, ...)
{
int rcode;
va_list args;
//set the values
va_start(args, outLength);
rcode = gtEncodeNoTypeV(fmtString, outBuffer, outLength, &args);
va_end(args);
return rcode;
}
static int gtDecodeInternalV(int usetype, const char *fmtString, char *inBuffer, int inLength, va_list *args)
{
int elemSize;
int totSize = inLength;
const char *bitCounter;
//skip the message type
if (usetype)
{
inBuffer += sizeof(GTMessageType);
inLength -= sizeof(GTMessageType);
}
while (*fmtString)
{
if (*fmtString == GT_BIT) //see how many
{
for (bitCounter = fmtString; *bitCounter == GT_BIT && bitCounter - fmtString <= 8; bitCounter++)
{};
elemSize = gtiDecodeBits((int)(bitCounter - fmtString), inBuffer, inLength, args);
fmtString = bitCounter - 1;
} else
elemSize = gtiDecodeSingle(*fmtString, inBuffer, inLength, args);
if (elemSize < 0)
return -1; //out of space
inBuffer += elemSize;
inLength -= elemSize;
fmtString++;
}
//NOTE: inLength should be 0 here if we "ate" the whole message
//If it's not 0, then the encoding and decoding strings probably did not match
//which would generally indicate a bug
//PANTS - commented out because we could be decoding the rest with a gtDecodeNoType
// assert(inLength == 0);
return totSize - inLength;
}
int gtDecodeV(const char *fmtString, char *inBuffer, int inLength, va_list *args)
{
return gtDecodeInternalV(1,fmtString, inBuffer, inLength, args);
}
int gtDecodeNoTypeV(const char *fmtString, char *inBuffer, int inLength, va_list *args)
{
return gtDecodeInternalV(0,fmtString, inBuffer, inLength, args);
}
int gtDecode(const char *fmtString, char *inBuffer, int inLength, ...)
{
int rcode;
va_list args;
//set the values
va_start(args, inLength);
rcode = gtDecodeV(fmtString, inBuffer, inLength, &args);
va_end(args);
return rcode;
}
int gtDecodeNoType(const char *fmtString, char *inBuffer, int inLength, ...)
{
int rcode;
va_list args;
//set the values
va_start(args, inLength);
rcode = gtDecodeNoTypeV(fmtString, inBuffer, inLength, &args);
va_end(args);
return rcode;
}
GTMessageType gtEncodedMessageType(char *inBuffer)
{
GTMessageType type;
//GS_ASSERT(sizeof(GTMessageType) ==2 )
gt2MemCopy16((char *)&type, inBuffer);
return type;
}
// change the message type for an encoded message
void gtEncodedMessageTypeSet (char *inBuffer, GTMessageType newtype)
{
gt2MemCopy16(inBuffer, (char *)&newtype);
}