/*
 *
 * CueCat decoder
 * version 0.1
 *
 * (c) 2000 Michael Rothwell
 * rothwell@holly-springs.nc.us
 *
 * Released under the GPL
 *
 */

#include "libcue.h"


struct chunks *convert(char *sample)
{
	struct chunks *c;
	int i;

	c=chunk(sample);

	if (c != NULL)
	{
		c->serial 	= decode(c->serial,strlen(c->serial));
		c->data		= decode(c->data,strlen(c->data));
		c->ctype	= decode(c->ctype,strlen(c->ctype));
	};
	
	return c;
};


struct chunks *chunk(char *sample)
{
	int 	x,y,l;
	struct chunks *ret;

	ret=(struct chunks *)malloc(sizeof(struct chunks));

	ret->head=NULL;
	ret->serial=NULL;
	ret->ctype=NULL;
	ret->data=NULL;
	ret->formatted=NULL;

	y=0;
	l=strlen(sample);
	ret->head=&sample[0];
	
	for (x=0; x<l; x++)
	{
		if (sample[x]=='.')
		{	
			y++;
			sample[x]=0;
			switch(y)
			{
				case 1:
					ret->serial=(&sample[x])+1;
					break;
				case 2:
					ret->ctype=(&sample[x])+1;
					break;
				case 3:
					ret->data=(&sample[x])+1;
					break;
			};
		};
		if (y>=4) {break;};
	};
	if (y!=4)
	{
		free(ret);
		return NULL;
	}
	else
	{
		return ret;
	};
}; //chunk


void init_codetable()
{
	int i;

	
	for (i=0; i<255; i++)
	{
		codetable[i]=0x80;
	};

	for (i='a'; i <= 'z'; i++)
	{
		codetable[i] = (i - 'a');
	};

	for (i='A'; i <= 'Z'; i++)
	{
		codetable[i] = 26 + (i - 'A');
	};

	for (i='0'; i <= '9'; i++)
	{
		codetable[i] = 52 + (i - '0');
	};

	codetable['+']=62;
	codetable['/']=63;
	
};

// advance 4 chars at a time through encoded sequence,
// produce base64-decoded output
char *decode(char *buf, int length)
{
	char 	*ret=NULL;
	char 	*txt=NULL;
	int 	i,j,k,t,z,l;
	unsigned char	a[4], b[4], c[4];
	unsigned long int n;

	if (__base64_codetable_initialized==0)
	{
		__base64_codetable_initialized=1;
		init_codetable();
	};

	
	if (length > 0)
	{
		// malloc more than enough space for return value
		ret=(char *)malloc(sizeof(char)*length);
		memset(ret,0,length);

		// copy source string into zeros-padded area
		txt=(char *)malloc(sizeof(char)*length+50);
		memset(txt,0,length+50);
		memcpy(txt,buf,length);
		length=strlen(txt);

		l=4-((length)%4);
		j=0;
		k=0;

		while(1)
		{
			memset(a,0,4);
			memset(b,0,4);
			memset(c,0,4);
			
			n=0;

			for(i=0; i<4; i++)
			{
				// skip invalid chars
				if (codetable[ txt[j+1] ] & 0x80) 
				{
					i--;
					continue;
				};
				b[i]=(unsigned char)codetable[ txt[j+i] ];
			};

			n = ((b[0] << 6 | b[1]) << 6 | b[2]) << 6 | b[3];
			ret[k]=(char)((n>>16)^67);
			ret[k+1]=(char)((n>>8 & 255)^67);
			ret[k+2]=(char)((n & 255)^67);

			j+=4;
			k+=3;

			if(j >= length)
			{
				if (l!=4)
				{
					ret[strlen(ret)-l]=0;
				};

				if (txt !=NULL)
				{
					free(txt);
					txt=NULL;
				};
				return ret;
			};
		};
	}
	else
	{
		return NULL;
	};
}		

int decode_type(struct chunks *c)
{
	int 	ret=0;
	int 	i,j,s;
	char	buf[1024];
	char	*fret;

	memset(buf,0,1024);
	s=0;

	if ((strcmp(c->ctype,"IB5")==0) || (strcmp(c->ctype,"IBN")==0))
	{
		for (i=3; i<=11; i++)
		{
			buf[i-3]=c->data[i];
		};
		for (i=0; i<strlen(buf); i++)
		{
			j=buf[i]-48;
			if (j==40 || j==72) {j=10;};
			if (j>10) {j=0;};
			if (j<0) {j=0;};
			s+=j*(i+1);
		};
		s=s%11;
		if (s==10)
		{
			buf[9]=88;
		}
		else
		{
			buf[9]=(s+48);
		};
		fret=(char *)malloc(sizeof(char)*strlen(buf));
		strcpy(fret,buf);
		c->formatted=fret;
		return 0;
	};
	
	return -1;
};

