/*******************************************************************************
 *	BBuffer.c	Buffer Class
 *			T.Barnaby,	BEAM Ltd,	27/2/94
 *******************************************************************************
 */
#include <stdlib.h>
#include <memory.h>
#include <BBuffer.h>
#include <BEndian.h>

#include <BTimeStamp.h>
#include <BComplex.h>

const int roundSize = 256;

BBuffer::BBuffer(BUInt size){
	osize = 0;
	odataSize = 0;
	odata = 0;
	setSize(size);
}

BBuffer::~BBuffer(){
	if(odata)
		free(odata);
	osize = 0;
	odataSize = 0;
	odata = 0;
}

BUInt32 BBuffer::size(){
	return osize;
}

int	BBuffer::setSize(BUInt32 size){
	BUInt32	asize;

	// Round up to a multiple of roundSize
	asize = roundSize * ((size + roundSize - 1) / roundSize);

	if(asize != odataSize){
		if((odata = (char*)realloc(odata, asize)) == 0){
			odataSize = 0;
			osize = 0;
			return 1;
		}
		odataSize = asize;
	}
	osize = size;
	return 0;
}

char*	BBuffer::data(){
	return odata;
}

int	BBuffer::setData(const void* data, BUInt32 size){
	if(!setSize(size)){
		memcpy(odata, data, size);
		return 0;
	}
	else {
		return 1;
	}
}

int	BBuffer::writeData(BUInt32 pos, const void* data, BUInt32 size){
	if((pos + size) > osize){
		if(setSize(pos + size))
			return 1;
	}
	memcpy((char*)odata + pos, data, size);
	return 0;
}


BBufferStore::BBufferStore(BUInt size, int swapBytes) : BBuffer(size){
	opos = 0;
	oswapBytes = swapBytes;
}

BBufferStore::~BBufferStore(){
}

BUInt32 BBufferStore::getPos(){
	return opos;
}

void BBufferStore::setPos(BUInt32 pos){
	opos = pos;
}
	
BString BBufferStore::getHexString(){
	BString	s;
	BUInt32	n;
	char*	buf = new char [size() * 2 + 1];
	char*	p = buf;
	
	for(n = 0; n < size(); n++){
		*p = '0' + ((odata[n] >> 4) & 0x0F);
		if(*p > '9')
			*p += 7;
		p++;
		*p = '0' + ((odata[n] >> 0) & 0x0F);
		if(*p > '9')
			*p += 7;
		p++;
	}
	buf[size() * 2] = '\0';
	s = buf;
	delete buf;
	return s;
}

void BBufferStore::setHexString(BString s){
	int	n;
	char*	p;

	setSize(s.len() / 2);
	p = odata;
	for(n = 0; n < s.len(); n += 2){
		*p = ((s[n] > '9' ? s[n] - '7' : s[n] - '0') & 0x0F) << 4;
		*p |= (s[n+1] > '9' ? s[n+1] - '7' : s[n+1] - '0') & 0x0F;
		p++;
	}
	opos = 0;
}

int BBufferStore::push(BInt8 v){
	setSize(opos + sizeof(v));
	bswap_copy(oswapBytes, &v, &odata[opos], sizeof(v), "1");
	opos += sizeof(v);
	return 0;
}

int BBufferStore::push(BUInt8 v){
	setSize(opos + sizeof(v));
	bswap_copy(oswapBytes, &v, &odata[opos], sizeof(v), "1");
	opos += sizeof(v);
	return 0;
}

int BBufferStore::push(BInt16 v){
	setSize(opos + sizeof(v));
	bswap_copy(oswapBytes, &v, &odata[opos], sizeof(v), "2");
	opos += sizeof(v);
	return 0;
}

int BBufferStore::push(BUInt16 v){
	setSize(opos + sizeof(v));
	bswap_copy(oswapBytes, &v, &odata[opos], sizeof(v), "2");
	opos += sizeof(v);
	return 0;
}

int BBufferStore::push(BInt32 v){
	setSize(opos + sizeof(v));
	bswap_copy(oswapBytes, &v, &odata[opos], sizeof(v), "4");
	opos += sizeof(v);
	return 0;
}

int BBufferStore::push(BUInt32 v){
	setSize(opos + sizeof(v));
	bswap_copy(oswapBytes, &v, &odata[opos], sizeof(v), "4");
	opos += sizeof(v);
	return 0;
}

int BBufferStore::push(BInt64 v){
	setSize(opos + sizeof(v));
	bswap_copy(oswapBytes, &v, &odata[opos], sizeof(v), "8");
	opos += sizeof(v);
	return 0;
}

int BBufferStore::push(BUInt64 v){
	setSize(opos + sizeof(v));
	bswap_copy(oswapBytes, &v, &odata[opos], sizeof(v), "8");
	opos += sizeof(v);
	return 0;
}

int BBufferStore::push(BFloat32 v){
	setSize(opos + sizeof(v));
	bswap_copy(oswapBytes, &v, &odata[opos], sizeof(v), "4");
	opos += sizeof(v);
	return 0;
}

int BBufferStore::push(BFloat64 v){
	setSize(opos + sizeof(v));
	bswap_copy(oswapBytes, &v, &odata[opos], sizeof(v), "8");
	opos += sizeof(v);
	return 0;
}

int BBufferStore::push(const BString& v){
	BInt32	l = v.len() + 1;
	
	setSize(opos + sizeof(l) + l);
	bswap_copy(oswapBytes, &l, &odata[opos], sizeof(l), "4");
	opos += sizeof(l);
	bswap_copy(oswapBytes, v.retStr(), &odata[opos], l, "1");
	opos += l;
	return 0;
}

int BBufferStore::push(const BError& v){
	BInt32	n = v.getErrorNo();
	BString	s = v.getString();
	push(n);
	push(s);
	return 0;
}

int BBufferStore::push(const BTimeStamp& v){
	push(v.oyear);
	push(v.oyday);
	push(v.ohour);
	push(v.ominute);
	push(v.osecond);
	push(v.omicroSecond);
	return 0;
}

int BBufferStore::push(const BComplex& v){
	push(v.real());
	push(v.imag());
	return 0;
}

int BBufferStore::push(BUInt32 nBytes, const void* data, const char* swapType){
	setSize(opos + nBytes);
	bswap_copy(oswapBytes, data, &odata[opos], nBytes, swapType);
	opos += nBytes;
	return 0;
}


int BBufferStore::pop(BInt8& v){
	if((osize - opos) < sizeof(v))
		return 1;

	bswap_copy(oswapBytes, &odata[opos], &v, sizeof(v), "1");
	opos += sizeof(v);
	return 0;
}

int BBufferStore::pop(BUInt8& v){
	if((osize - opos) < sizeof(v))
		return 1;

	bswap_copy(oswapBytes, &odata[opos], &v, sizeof(v), "1");
	opos += sizeof(v);
	return 0;
}

int BBufferStore::pop(BInt16& v){
	if((osize - opos) < sizeof(v))
		return 1;

	bswap_copy(oswapBytes, &odata[opos], &v, sizeof(v), "2");
	opos += sizeof(v);
	return 0;
}

int BBufferStore::pop(BUInt16& v){
	if((osize - opos) < sizeof(v))
		return 1;

	bswap_copy(oswapBytes, &odata[opos], &v, sizeof(v), "2");
	opos += sizeof(v);
	return 0;
}

int BBufferStore::pop(BInt32& v){
	if((osize - opos) < sizeof(v))
		return 1;

	bswap_copy(oswapBytes, &odata[opos], &v, sizeof(v), "4");
	opos += sizeof(v);
	return 0;
}

int BBufferStore::pop(BUInt32& v){
	if((osize - opos) < sizeof(v))
		return 1;

	bswap_copy(oswapBytes, &odata[opos], &v, sizeof(v), "4");
	opos += sizeof(v);
	return 0;
}

int BBufferStore::pop(BInt64& v){
	if((osize - opos) < sizeof(v))
		return 1;

	bswap_copy(oswapBytes, &odata[opos], &v, sizeof(v), "8");
	opos += sizeof(v);
	return 0;
}

int BBufferStore::pop(BUInt64& v){
	if((osize - opos) < sizeof(v))
		return 1;

	bswap_copy(oswapBytes, &odata[opos], &v, sizeof(v), "8");
	opos += sizeof(v);
	return 0;
}

int BBufferStore::pop(BFloat32& v){
	if((osize - opos) < sizeof(v))
		return 1;

	bswap_copy(oswapBytes, &odata[opos], &v, sizeof(v), "4");
	opos += sizeof(v);
	return 0;
}

int BBufferStore::pop(BFloat64& v){
	if((osize - opos) < sizeof(v))
		return 1;

	bswap_copy(oswapBytes, &odata[opos], &v, sizeof(v), "8");
	opos += sizeof(v);
	return 0;
}

int BBufferStore::pop(BString& v){
	BUInt32	l;
	
	if((osize - opos) < sizeof(l))
		return 1;
	
	bswap_copy(oswapBytes, &odata[opos], &l, sizeof(l), "4");
	opos += sizeof(l);

	if((osize - opos) < l)
		return 1;
	
	v = (char*)&odata[opos];
	opos += l;
	return 0;
}

int BBufferStore::pop(BError& v){
	int	e;
	BInt32	n;
	BString	s;

	if(e = pop(n))
		return e;
	if(e = pop(s))
		return e;
	v.set(n, s);
	return 0;
}

int BBufferStore::pop(BTimeStamp& v){
	int	e;

	if(e = pop(v.oyear))
		return e;
	if(e = pop(v.oyday))
		return e;
	if(e = pop(v.ohour))
		return e;
	if(e = pop(v.ominute))
		return e;
	if(e = pop(v.osecond))
		return e;
	if(e = pop(v.omicroSecond))
		return e;

	return 0;
}

int BBufferStore::pop(BComplex& v){
	int	e;
	double	r, i;

	if(e = pop(r))
		return e;
	if(e = pop(i))
		return e;
	
	v = BComplex(r, i);	

	return 0;
}

int BBufferStore::pop(BUInt32 nBytes, void* data, const char* swapType){
	if((osize - opos) < nBytes)
		return 1;

	bswap_copy(oswapBytes, &odata[opos], data, nBytes, swapType);
	opos += nBytes;
	return 0;
}

