// Common, group Encoding
// Copyright Alexander Liss
#include "string.h"
#include "wirepack.h"
#include "porting.h"
using namespace Porting;
const int INT=4 ;
const int LONG=4 ;
const int SHORT=2 ;
static
void swap(unsigned char* d, unsigned char* z, int size)
{
for(int i=size-1,s=size;i>=0;--i)
{
if(z[i]) break;
--s;
}
for(i=0;i<s;++i)
d[size-i]=z[i];
}
template<class T>
int local_put(T data,int t,CommBuffer* write_buffer)
{
if(!write_buffer) return 1;
unsigned char buf[LONG];
memset(buf,0,LONG);
unsigned char* z=(unsigned char*)&data;
int s=sizeof(data);
if(s>t)
{
for(int i=t-1;i<=s;++i)
if(z[i]) return 2;
s=t;
}
if(big_endian)
memcpy(buf,z,s);
else
swap(buf,z,s);
return write_buffer->append(buf,t);
}
template<class T>
int local_get(T& data,int t,const CommBuffer* read_buffer, ReadControl* read_control)
{
if(!read_buffer || !read_control) return 1;
if(read_buffer->data_left(*read_control)<t) return 2;
data=0;
unsigned char* z=read_buffer->read_start(*read_control);
int s=sizeof(data);
if(s>t)
{
for(int i=t-1;i<=s;++i)
if(z[i]) return 3;
s=t;
}
if(big_endian)
memcpy(&data,z,s);
else
swap((unsigned char*)&data,z,s);
read_control->offset+=t;
return 0;
}
// WirePacker
int WirePacker::put(const void * data,int size)
{
if(!write_buffer) return 1;
return write_buffer->append((const unsigned char*)data,size);
}
int WirePacker::get(void * data,int size)
{
if(!read_buffer || !read_control) return 1;
if(read_buffer->data_left(*read_control)<size) return 2;
memcpy(data,read_buffer->read_start(*read_control),size);
read_control->offset+=size;
return 0;
}
int WirePacker::put(unsigned int data)
{
return local_put(data,INT,write_buffer);
}
int WirePacker::get(unsigned int& data)
{
return local_get(data,INT,read_buffer,read_control);
}
int WirePacker::put(unsigned long data)
{
return local_put(data,LONG,write_buffer);
}
int WirePacker::get(unsigned long& data)
{
return local_get(data,LONG,read_buffer,read_control);
}
int WirePacker::put(unsigned short data)
{
return local_put(data,SHORT,write_buffer);
}
int WirePacker::get(unsigned short& data)
{
return local_get(data,SHORT,read_buffer,read_control);
}
int WirePacker::put(unsigned char data)
{
if(!write_buffer) return 1;
return write_buffer->append(1,(char)data);
}
int WirePacker::get(unsigned char& data)
{
if(!read_buffer || !read_control) return 1;
if(read_buffer->data_left(*read_control)<1) return 2;
data=*read_buffer->read_start(*read_control);
read_control->offset++;
return 0;
}
int WirePacker::put_tail(int data, int bytes)
{
if(bytes>4 || bytes<1) return 1;
return local_put(data,bytes,write_buffer);
}
int WirePacker::get_tail(int& data, int bytes)
{
if(bytes>4 || bytes<1) return 1;
return local_get(data,bytes,read_buffer,read_control);
}
int WirePacker::put(const CommBuffer& data, int bytes)
{
if(!write_buffer) return 1;
if(bytes>4 || bytes<1) return 2;
int g=put_tail(data.data_size,bytes);
if(!g) g=write_buffer->append(data.write_start(),data.data_size);
return g;
}
int WirePacker::get(CommBuffer& data, int bytes)
{
if(!read_buffer || !read_control) return 1;
if(bytes>4 || bytes<1) return 2;
int size=0;
int g=get_tail(size,bytes);
if(g) return 3;
if(size>read_buffer->data_left(*read_control))
return 4;
g=data.append(read_buffer->read_start(*read_control),size);
if(g) return 4;
read_control->offset+=size;
return 0;
}
// functions
int put_message_size(CommBuffer& buf,unsigned int size)
{
return WirePacker(buf).put(size);
}
int prepend_message_size(CommBuffer& d,unsigned int size)
{
unsigned char buf[INT];
memset(buf,0,INT);
unsigned char* z=(unsigned char*)&size;
int s=sizeof(size);
if(s>INT)
{
for(int i=INT-1;i<=s;++i)
if(z[i]) return 1;
s=INT;
}
if(big_endian)
memcpy(buf,z,s);
else
swap(buf,z,s);
return d.prepend(buf,INT);
}
unsigned int get_message_size(const CommBuffer& buf,ReadControl& c)
{
unsigned int size=0;
WirePacker(buf,c).get(size);
return size;
}