#include #include #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); }