/* Base type primitives */

#ifndef __CODER_H_SEEN__
#define __CODER_H_SEEN__

#ifndef __GNUC__
#define __inline__	/* */
#endif

#ifndef __cplusplus
#ifndef ALLOC
extern void *malloc(unsigned long);
extern void free(void *);
#define ALLOC(s)	malloc(s)
#define FREE(s)		free(s)
#endif /* ALLOC */
#endif __cplusplus

/* Types we use */
typedef unsigned char Uchar;
typedef unsigned short Ushort;
typedef unsigned long Ulong;
typedef unsigned long Uint;
typedef unsigned long long Ulonglong;
typedef long long longlong;

/** char **/
__inline__ static unsigned char *encode_char(const char *ch, unsigned char *buf)
{
	*buf = *ch;
	return buf+1;
}

__inline__ static unsigned char *decode_char(char *ch, unsigned char *buf)
{
	*ch = *buf;
	return buf+1;
}

__inline__ static unsigned int sizeof_char(const char *c)
{
	return 1;
}

/** unsigned char **/
__inline__ static unsigned char *encode_Uchar(const Uchar *ch, unsigned char *buf)
{
	*buf = *ch;
	return buf+1;
}

__inline__ static unsigned char *decode_Uchar(Uchar *ch, unsigned char *buf)
{
	*ch = *buf;
	return buf+1;
}

__inline__ static unsigned int sizeof_Uchar(const Uchar *c)
{
	return 1;
}

/** short **/
__inline__ static unsigned char *encode_short(const short *sh, unsigned char *buf)
{
	register short sv = *sh;
	
	buf[0] = (sv >> 8)& 0xff;
	buf[1] =  sv      & 0xff;
	return buf+2;
}

__inline__ static unsigned char *decode_short(short *sh, unsigned char *buf)
{
	*sh = (buf[0] << 8) | buf[1];
	return buf+2;
}

__inline__ static unsigned int sizeof_short(const short *c)
{
	return 2;
}

/** unsigned short **/
__inline__ static unsigned char *encode_Ushort(const Ushort *sh, unsigned char *buf)
{
	register Ushort sv = *sh;
	
	buf[0] = (sv >> 8)& 0xff;
	buf[1] =  sv      & 0xff;
	return buf+2;
}

__inline__ static unsigned char *decode_Ushort(Ushort *sh, unsigned char *buf)
{
	*sh = (buf[0] << 8) | buf[1];
	return buf+2;
}

__inline__ static unsigned int sizeof_Ushort(const Ushort *c)
{
	return 2;
}

/** long **/
__inline__ static unsigned char *encode_long(const long *l, unsigned char *buf)
{
	register long lv = *l;
	
	buf[0] = (lv >> 24) & 0xff;
	buf[1] = (lv >> 16) & 0xff;
	buf[2] = (lv >> 8)  & 0xff;
	buf[3] =  lv        & 0xff;
	return buf+4;
}

__inline__ static unsigned char *decode_long(long *l, unsigned char *buf)
{
	*l = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
	return buf+4;
}

__inline__ static unsigned int sizeof_long(const long *c)
{
	return 4;
}

/** unsigned long **/
__inline__ static unsigned char *encode_Ulong(const Ulong *l, unsigned char *buf)
{
	register Ulong lv = *l;
	
	buf[0] = (lv >> 24) & 0xff;
	buf[1] = (lv >> 16) & 0xff;
	buf[2] = (lv >> 8)  & 0xff;
	buf[3] =  lv        & 0xff;
	return buf+4;
}

__inline__ static unsigned char *decode_Ulong(Ulong *l, unsigned char *buf)
{
	*l = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
	return buf+4;
}

__inline__ static unsigned int sizeof_Ulong(const Ulong *c)
{
	return 4;
}

/** long long */
__inline__ static unsigned char *encode_longlong(const long long *l,
						 unsigned char *buf)
{
	register long long lv = *l;

	buf[0] = (lv >> 56) & 0xff;
	buf[1] = (lv >> 48) & 0xff;
	buf[2] = (lv >> 40) & 0xff;
	buf[3] = (lv >> 32) & 0xff;
	buf[4] = (lv >> 24) & 0xff;
	buf[5] = (lv >> 16) & 0xff;
	buf[6] = (lv >> 8)  & 0xff;
	buf[7] =  lv        & 0xff;

	return buf+8;
}

__inline__ static unsigned char *decode_longlong(long long *l,
						 unsigned char *buf)
{
#define BUF(x)	((long long)(buf[x]))
	*l = (BUF(0) << 56)|(BUF(1) << 48)|(BUF(2) << 40)|(BUF(3) << 32)|
	     (BUF(4) << 24)|(BUF(5) << 16)|(BUF(6) <<  8)|BUF(7);
#undef BUF
	return buf+8;
}

__inline__ static unsigned int sizeof_longlong(const long long *c)
{
	return 8;
}

/** unsigned long long */
__inline__ static unsigned char *encode_Ulonglong(const unsigned long long *l,
						  unsigned char *buf)
{
	register unsigned long long lv = *l;

	buf[0] = (lv >> 56) & 0xff;
	buf[1] = (lv >> 48) & 0xff;
	buf[2] = (lv >> 40) & 0xff;
	buf[3] = (lv >> 32) & 0xff;
	buf[4] = (lv >> 24) & 0xff;
	buf[5] = (lv >> 16) & 0xff;
	buf[6] = (lv >> 8)  & 0xff;
	buf[7] =  lv        & 0xff;

	return buf+8;
}

__inline__ static unsigned char *decode_Ulonglong(unsigned long long *l,
						  unsigned char *buf)
{
#define BUF(x)	((unsigned long long)(buf[x]))
	*l = (BUF(0) << 56)|(BUF(1) << 48)|(BUF(2) << 40)|(BUF(3) << 32)|
	     (BUF(4) << 24)|(BUF(5) << 16)|(BUF(6) <<  8)|BUF(7);
#undef BUF
	return buf+8;
}

__inline__ static unsigned int sizeof_Ulonglong(const unsigned long long *c)
{
	return 8;
}

/** void **/
__inline__ static unsigned char *encode_void(const void *v, unsigned char *buf)
{
	return buf;
}

__inline__ static unsigned char *decode_void(void *v, unsigned char *buf)
{
	return buf;
}

__inline__ static unsigned int sizeof_void(const void *c)
{
	return 0;
}

/* Assuming this host has IEEE 754 floats, this is all OK */
/** float **/
__inline__ static unsigned char *encode_float(const float *f, unsigned char *buf)
{
	*(float *)buf = *f;
	return buf + sizeof(float);
}

__inline__ static unsigned char *decode_float(float *f, unsigned char *buf)
{
	*f = *(float *)buf;
	return buf + sizeof(float);
}

__inline__ static unsigned int sizeof_float(const float *c)
{
	return sizeof(float);
}

/** double **/
__inline__ static unsigned char *encode_double(const double *d, unsigned char *buf)
{
	*(double *)buf = *d;
	return buf + sizeof(double);
}

__inline__ static unsigned char *decode_double(double *d, unsigned char *buf)
{
	*d = *(double *)buf;
	return buf + sizeof(double);
}

__inline__ static unsigned int sizeof_double(const double *c)
{
	return sizeof(double);
}

#endif /* __CODER_H_SEEN__ */
