#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <io.h>
#include <ftw.h>

int boost=0;

unsigned char * Sequence(unsigned char *fp,int t,unsigned char *out,int ix,int iy,int nbcarr,unsigned char *palette)
{
	unsigned int pt;
	unsigned int vval,val1,val2,i,i1,i2,i3,i4,i5,j,delta;
	unsigned char buf1[201],buf2[16];
	
	out+=3*t*(nbcarr*t*iy+(ix+1));
	out+=3*nbcarr*t*t;
	delta=-3*t*(nbcarr+1);
	for(j=0;j<t;j++)
	{
		out+=delta;
		pt=*fp++;
		if(pt==0x40)
		{
			pt=*fp++;
			val2=pt;
			val1=(val2+val2+val2);
			if(val1&7)
			{
				val1>>=3;
				val1++;
			}
			else
				val1>>=3;
			memcpy(buf1,fp,val1);
			fp+=val1;
			if(pt&7)
			{
				pt>>=3;
				pt++;
			}
			else
				pt>>=3;
			memcpy(buf2,fp,pt);
			fp+=pt;
			for(i=0;i<val2;i++)
			{
				i1=(i+i+i);
				i2=i1>>3;
				i3=(13-(i1&7));
				if(i3<8)
					vval=(buf1[i2]<<8)|(buf1[i2+1]);
				else
					vval=buf1[i2]<<8;
				vval>>=i3;
				vval&=7;
				vval++;
				i4=i>>3;
				i5=1<<(7-i&7);
				if(buf2[i4]&i5)
				{
					pt=(*fp++)<<2;
					while(vval)
					{
						*out++=palette[pt];
						*out++=palette[pt+1];
						*out++=palette[pt+2];
						vval--;
					}
				}
				else
				{
					while(vval)
					{
						pt=*fp++;
						pt<<=2;
						*out++=palette[pt++];
						*out++=palette[pt++];
						*out++=palette[pt];
						vval--;
					}
				}
			}
			continue;
		}
		if(pt==0x80)
		{
			pt=*fp++;
			val2=pt;
			val1=val2<<2;
			if(val1&7)
			{
				val1>>=3;
				val1++;
			}
			else
				val1>>=3;
			memcpy(buf1,fp,val1);
			fp+=val1;
			if(pt&7)
			{
				pt>>=3;
				pt++;
			}
			else
				pt>>=3;
			memcpy(buf2,fp,pt);
			fp+=pt;
			for(i=0;i<val2;i++)
			{
				i1=i<<2;
				i2=i1>>3;
				i3=(12-(i1&7));
				if(i3<8)
					vval=(buf1[i2]<<8)|(buf1[i2+1]);
				else
					vval=buf1[i2]<<8;
				vval>>=i3;
				vval&=15;
				vval++;
				i4=i>>3;
				i5=1<<(7-i&7);
				if(buf2[i4]&i5)
				{
					pt=(*fp++)<<2;
					while(vval)
					{
						*out++=palette[pt];
						*out++=palette[pt+1];
						*out++=palette[pt+2];
						vval--;
					}
				}
				else
				{
					while(vval)
					{
						pt=*fp++;
						pt<<=2;
						*out++=palette[pt++];
						*out++=palette[pt++];
						*out++=palette[pt];
						vval--;
					}
				}
			}
			continue;
		}
		if(!pt)
		{
			fp++;
			vval=t;
			while(vval)
			{
				pt=(*fp++)<<2;
				*out++=palette[pt++];
				*out++=palette[pt++];
				*out++=palette[pt];
				vval--;
			}
			continue;
		}
		printf("\nErreur 1 : Flag = %d\n",pt);
		exit(0);
	}
	return fp;
}

unsigned char * Sequence8(unsigned char *fp,int t,unsigned char *out,int ix,int iy,int nbcarr)
{
	unsigned char pt;
	unsigned int vval,val1,val2,i,i1,i2,i3,i4,i5,j,delta;
	unsigned char buf1[201],buf2[16];
	
	out+=t*(nbcarr*t*iy+(ix+1));
	out+=nbcarr*t*t;
	delta=-t*(nbcarr+1);
	for(j=0;j<t;j++)
	{
		out+=delta;
		pt=*fp++;
		if(pt==0x40)
		{
			pt=*fp++;
			val2=pt;
			val1=(val2+val2+val2);
			if(val1&7)
			{
				val1>>=3;
				val1++;
			}
			else
				val1>>=3;
			memcpy(buf1,fp,val1);
			fp+=val1;
			if(pt&7)
			{
				pt>>=3;
				pt++;
			}
			else
				pt>>=3;
			memcpy(buf2,fp,pt);
			fp+=pt;
			for(i=0;i<val2;i++)
			{
				i1=(i+i+i);
				i2=i1>>3;
				i3=(13-(i1&7));
				if(i3<8)
					vval=(buf1[i2]<<8)|(buf1[i2+1]);
				else
					vval=buf1[i2]<<8;
				vval>>=i3;
				vval&=7;
				vval++;
				i4=i>>3;
				i5=1<<(7-i&7);
				if(buf2[i4]&i5)
				{
					pt=*fp++;
					memset(out,pt,vval);
				}
				else
				{
					memcpy(out,fp,vval);
					fp+=vval;
				}
				out+=vval;
			}
			continue;
		}
		if(pt==0x80)
		{
			pt=*fp++;
			val2=pt;
			val1=val2<<2;
			if(val1&7)
			{
				val1>>=3;
				val1++;
			}
			else
				val1>>=3;
			memcpy(buf1,fp,val1);
			fp+=val1;
			if(pt&7)
			{
				pt>>=3;
				pt++;
			}
			else
				pt>>=3;
			memcpy(buf2,fp,pt);
			fp+=pt;
			for(i=0;i<val2;i++)
			{
				i1=i<<2;
				i2=i1>>3;
				i3=(12-(i1&7));
				if(i3<8)
					vval=(buf1[i2]<<8)|(buf1[i2+1]);
				else
					vval=buf1[i2]<<8;
				vval>>=i3;
				vval&=15;
				vval++;
				i4=i>>3;
				i5=1<<(7-i&7);
				if(buf2[i4]&i5)
				{
					pt=*fp++;
					memset(out,pt,vval);
				}
				else
				{
					memcpy(out,fp,vval);
					fp+=vval;
				}
				out+=vval;
			}
			continue;
		}
		if(!pt)
		{
			fp++;
			memcpy(out,fp,t);
			out+=t;
			fp+=t;
			continue;
		}
		printf("\nErreur 1 : Flag = %d\n",pt);
		exit(0);
	}
	return fp;
}

int copy1(unsigned char *dst,unsigned char *src,int i)
{
	int nb=0;

	while(i>254)
	{
		*dst++=0;
		*dst++=255;
		memcpy(dst,src,255);
		dst+=255;
		src+=255;
		*dst++=0;
		nb+=258;
		i-=255;
	}
	switch(i)
	{
		case 2:
			*dst++=1;
			*dst++=*src++;
			nb+=2;
		case 1:
			*dst++=1;
			*dst=*src;
			nb+=2;
			break;
		case 0:
			break;
		default:
			*dst++=0;
			*dst++=i;
			memcpy(dst,src,i);
			nb+=2;
			nb+=i;
			if(i&1)
			{
				dst+=i;
				*dst=0;
				nb++;
			}
			break;
	}
	return(nb);
}

int copy2(unsigned char *dst,unsigned char *src,int i)
{
	int nb=0;

	while(i>254)
	{
		*dst++=255;
		*dst++=*src;
		nb+=2;
		i-=255;
	}
	if(i)
	{
		*dst++=i;
		*dst=*src;
		nb+=2;
	}
	return nb;
}

int RLEPack(unsigned char *src,unsigned char *dst,int size)
{
	int nb=0,ret;
	unsigned char *tsrc1,*tsrc2;

	for(;;)
	{
		size--;
		tsrc1=src;
		while((*src!=*(src+1))||(*src!=*(src+2)))
		{
			size--;
			src++;
			if(size<2)
				break;
		}
		if(src!=tsrc1)
		{
			if(size<2)
			{
				nb+=copy1(dst,tsrc1,(int)src-(int)tsrc1+2);
				return nb;
			}
			ret=copy1(dst,tsrc1,(int)src-(int)tsrc1);
			nb+=ret;
			dst+=ret;
		}
		tsrc1=src;
		do
		{
			size--;
			src++;
			if(size<2)
				break;
		}
		while((*src==*(src+1))&&(*src==*(src+2)));
		ret=copy2(dst,tsrc1,(int)src-(int)tsrc1+2);
		nb+=ret;
		size--;
		src+=2;
		dst+=ret;
		if(size<3)
		{
			nb+=copy1(dst,src,size);
			return nb;
		}
	}
}

void SauveBMP(char *nom,int sizex,int sizey,unsigned char *palette,unsigned char *bitmap)
{
	FILE *fp;
	unsigned int t;
	unsigned short u;
	int factor;
	int i,tc,size=0,sp;
	unsigned char *pckd;
	int packed=0;

	if(palette)
		packed=1;
	nom[strlen(nom)-1]='P';
	nom[strlen(nom)-2]='M';
	nom[strlen(nom)-3]='B';
	if(palette)
	{
		tc=1024;
		factor=1;
	}
	else
	{
		tc=0;
		factor=3;
	}
	if(fp=fopen(nom,"wb"))
		if((pckd=malloc(sizex*factor*2)))
		{
			fwrite("BM",2,1,fp);
			t=0;
			fwrite(&t,4,1,fp);
			t=0;
			fwrite(&t,4,1,fp);
			t=54+tc;
			fwrite(&t,4,1,fp);
			t=40;
			fwrite(&t,4,1,fp);
			t=sizex;
			fwrite(&t,4,1,fp);
			t=sizey;
			fwrite(&t,4,1,fp);
			u=1;
			fwrite(&u,2,1,fp);
			u=8*factor;
			fwrite(&u,2,1,fp);
			t=1;
			fwrite(&t,4,1,fp);
			t=0;
			fwrite(&t,4,1,fp);
			t=0;
			fwrite(&t,4,1,fp);
			fwrite(&t,4,1,fp);
			t=0;
			fwrite(&t,4,1,fp);
			fwrite(&t,4,1,fp);
			if(tc)
				fwrite(palette,1024,1,fp);
			for(i=factor*(sizey-1)*sizex;i>=0;i-=factor*sizex)
			{
				if(packed)
				{
					sp=RLEPack(bitmap+i,pckd,factor*sizex);
					fwrite(pckd,sp,1,fp);
					size+=sp;
					t=0;
					fwrite(&t,2,1,fp);
				}
				else
					size+=fwrite(bitmap+i,factor,sizex,fp);

			}
			if(packed)
			{
				t=0;
				fwrite(&t,1,1,fp);
				t=1;
				fwrite(&t,1,1,fp);
				size+=(2*sizey)+2;
			}
			fseek(fp,2,SEEK_SET);
			t=size+54+tc;
			fwrite(&t,4,1,fp);
			fseek(fp,34,SEEK_SET);
			t=factor*sizex*sizey;
			fwrite(&t,4,1,fp);
			fclose(fp);
			free(pckd);
		}
	else
		printf("Can't write %s.\n",nom);
}

void SauveRAW(char *nom,unsigned char *bitmap,int size)
{
	FILE *fp;
	nom[strlen(nom)-1]='W';
	nom[strlen(nom)-2]='A';
	nom[strlen(nom)-3]='R';
	nom[strlen(nom)-4]='.';
	fp=fopen(nom,"wb");
	fwrite(bitmap,size,1,fp);
	fclose(fp);
}

void Go(char *nom)
{
	FILE *fp,*fq;
	int val,info[20],iinfo=0,nbimage,i,j,s,nbcarr,ix,iy;
	unsigned char pt;
	unsigned char palette[1024],*buffp,*tbuffp;
	char *out;

	if(fp=fopen(nom,"rb"))
	{
		val=filelength(fileno(fp));
		buffp=malloc(val);
		fread(buffp,val,1,fp);
		fclose(fp);
	}
	else
		exit(0);
	tbuffp=buffp;
	buffp+=8;
	nbimage=(buffp[0])|(buffp[1]<<8)|(buffp[2]<<16)|(buffp[3]<<24);
	buffp+=4;
	info[iinfo++]=nbimage;
	while(nbimage)
	{
		nbimage--;
		val=(buffp[0])|(buffp[1]<<8)|(buffp[2]<<16)|(buffp[3]<<24);
		buffp+=4;
		info[iinfo++]=val;
	}
	do
	{
		val=(buffp[0])|(buffp[1]<<8)|(buffp[2]<<16)|(buffp[3]<<24);
		buffp+=4;
	}
	while(!val);
	buffp-=4;
	nbimage=info[0];
	while(nbimage)
	{
		nbimage--;
		val=(buffp[0])|(buffp[1]<<8)|(buffp[2]<<16)|(buffp[3]<<24);
		buffp+=4;
		info[iinfo++]=val;
	}
	info[iinfo++]=0;
	if(boost)
		i=1;
	else
		i=3;
	buffp=tbuffp+16+info[i+info[0]];
	s=(buffp[0])|(buffp[1]<<8)|(buffp[2]<<16)|(buffp[3]<<24);
	buffp+=4;
	nbcarr=4000/(s*info[i]);
	buffp+=8;
	for(j=0;j<=255;j++)
	{
		palette[(j<<2)+0]=*buffp++;
		palette[(j<<2)+1]=*buffp++;
		palette[(j<<2)+2]=*buffp++;
		palette[(j<<2)+3]=0;
	}
	buffp+=((nbcarr*nbcarr)<<2);
	out=malloc(s*s*nbcarr*nbcarr);
	for(iy=nbcarr-1;iy>=0;iy--)
		for(ix=0;ix<nbcarr;ix++)
			buffp=Sequence8(buffp,s,out,ix,iy,nbcarr);
	SauveBMP(nom,s*nbcarr,s*nbcarr,palette,out);
	free(out);
	free(tbuffp);
}

char *Go2(char *nom,int size)
{
	FILE *fp,*fq;
	int val,info[20],iinfo=0,nbimage,i,j,s,nbcarr,ix,iy;
	unsigned char pt;
	unsigned char palette[1024],*buffp,*tbuffp;
	char *out;

	if(fp=fopen(nom,"rb"))
	{
		val=filelength(fileno(fp));
		buffp=malloc(val);
		fread(buffp,val,1,fp);
		fclose(fp);
	}
	else
		exit(0);

	tbuffp=buffp;
	buffp+=8;
	nbimage=(buffp[0])|(buffp[1]<<8)|(buffp[2]<<16)|(buffp[3]<<24);
	buffp+=4;
	info[iinfo++]=nbimage;
	while(nbimage)
	{
		nbimage--;
		val=(buffp[0])|(buffp[1]<<8)|(buffp[2]<<16)|(buffp[3]<<24);
		buffp+=4;
		info[iinfo++]=val;
	}
	do
	{
		val=(buffp[0])|(buffp[1]<<8)|(buffp[2]<<16)|(buffp[3]<<24);
		buffp+=4;
	}
	while(!val);
	buffp-=4;
	nbimage=info[0];
	while(nbimage)
	{
		nbimage--;
		val=(buffp[0])|(buffp[1]<<8)|(buffp[2]<<16)|(buffp[3]<<24);
		buffp+=4;
		info[iinfo++]=val;
	}
	info[iinfo++]=0;
	i=size;
	buffp=tbuffp+16+info[i+info[0]];
	s=(buffp[0])|(buffp[1]<<8)|(buffp[2]<<16)|(buffp[3]<<24);
	buffp+=4;
	nbcarr=4000/(s*info[i]);
	buffp+=8;
	for(j=0;j<=255;j++)
	{
		palette[(j<<2)+0]=*buffp++;
		palette[(j<<2)+1]=*buffp++;
		palette[(j<<2)+2]=*buffp++;
	}
	buffp+=((nbcarr*nbcarr)<<2);
	if(!(out=malloc(3*s*s*nbcarr*nbcarr)))
	{
		free(tbuffp);
		puts("NO RAM");
		exit(0);
	}
	for(iy=nbcarr-1;iy>=0;iy--)
		for(ix=0;ix<nbcarr;ix++)
			buffp=Sequence(buffp,s,out,ix,iy,nbcarr,palette);
	free(tbuffp);
	return out;
}

int LISTE(const char *path,struct stat *sb,int flag)
{
	if(flag==FTW_F)
		if(strstr(path,".byo"))
		{
			puts(path);
			Go((char *)path);
		}
	return 0;
}

char **mpath=NULL;
int ipath=0;

void FreeListe(void)
{
	int i;

	if(mpath)
	{
		for(i=0;mpath[i];i++);
		while(i)
		{
			i--;
			free(mpath[i]);
		}
	}
	free(mpath);
}

int LISTE2(const char *path,struct stat *sb,int flag)
{
	if(flag==FTW_F)
	{
		if(strstr(path,".byo"))
			if(mpath[ipath]=(char *)calloc(1000,1))
				strcpy(mpath[ipath++],path);
	}
	return 0;
}

char * basename(char *nom)
{
	int i;

	i=strlen(nom)-1;
	while(i&&(nom[i]!='/')&&(nom[i]!='\\'))
		i--;
	if(!i)
	{
		if((nom[0]=='/')||(nom[0]=='\\'))
			return(nom+1);
		else
			return(nom);
	}
	else
		return(nom+i+1);
}

void MemCopy(char *dst,char *src,int dx,int dy,int tx,int ty,int size)
{
	int k;

	dx=tx-dx-1;
	dy=ty-dy-1;
	for(k=0;k<size;k++)
		memcpy(dst+3*dy*size*tx*size+3*dx*size+3*k*tx*size,src+3*k*size,3*size);
}

void Transf(char *nom,int *l1,int *l2)
{
	int val,cnt,i,j,k,l,fl=1;

	cnt=0;
	val=0;
	for(i=0;i<strlen(nom);i++)
	{
		if((nom[i]>='0')&&(nom[i]<='9'))
		{
			val*=10;
			val+=(nom[i]-'0');
		}
		else
		{
			cnt++;
			if(cnt==1)
			{
				*l1=val;
				val=0;
			}
			else
				*l2=val;
		}

	}
	if(!*l2)
	{
		*l2=*l1/100;
		*l1%=100;
		j=*l2;
		*l2=*l1;
		*l1=j;
		fl=10;
	}
	j=(*l1)%10;
	k=((*l1-j)/10)%10;
	l=(*l1/100);
	*l1=j*100+k*10+l;
	j=(*l2)%10;
	k=((*l2-j)/10)%10;
	l=(*l2/100);
	*l2=j*100+k*10+l;
	*l1/=fl;
	*l2/=fl;
}

void Build(char *dirnom)
{
	int i,size,picsize;
	char *nom,*nom2,*buf,*bigbuff;
	int l1,l2,l1max=0,l1min=999,l2min=999,l2max=0;

	if(mpath=(char **)calloc(1000,sizeof(char *)))
	{
		if(nom2=(char *)calloc(1000,sizeof(char)))
		{
			ftw(dirnom,LISTE2,0);
			if(ipath)
			{
				for(i=0;i<ipath;i++)
				{
					nom=basename(mpath[i]);
					Transf(nom,&l1,&l2);
					if(l1max<l1)
						l1max=l1;
					if(l2max<l2)
						l2max=l2;
					if(l1min>l1)
						l1min=l1;
					if(l2min>l2)
						l2min=l2;
				}
				l1max-=l1min;
				l2max-=l2min;
				l1max++;
				l2max++;
				if(boost)
				{
					size=3;
					picsize=1000;
				}
				else
				{
					size=4;
					picsize=400;
				}
				printf("Cartes : %d x %d\n",l1max,l2max);
				if(bigbuff=(char *)malloc(3*l1max*l2max*picsize*picsize))
				{
					for(i=0;i<ipath;i++)
					{
						printf("%03d/%03d - ",i,ipath-1);
						nom=basename(mpath[i]);
						Transf(nom,&l1,&l2);
						if(buf=Go2(mpath[i],size))
						{
							printf("%s %d/%d %d/%d\n",mpath[i],l1-l1min,l1max,l2-l2min,l2max);
							MemCopy(bigbuff,buf,l2-l2min,l1-l1min,l2max,l1max,picsize);
							free(buf);
						}
						else
						{
							puts("NO RAM");
							break;
						}
					}
					if(i==ipath)
						SauveBMP(mpath[0],l2max*picsize,l1max*picsize,NULL,bigbuff);
					free(bigbuff);
				}
				else
					puts("NO RAM");
			}
			free(nom2);
		}
		FreeListe();
	}
}

main(char argc,char **argv)
{
	FILE *fp;
	int i=0,merge=0;

	while(argv[i])
	{
		if(strcmp(argv[i],"BOOST")==0)
			boost=1;
		else
			if(strcmp(argv[i],"MERGE")==0)
				merge=1;
		i++;
	}
	if(argv[1])
		if(merge)
			Build(argv[1]);
		else
		{
			if(fp=fopen(argv[1],"rb"))
			{
				fclose(fp);
				if(strstr(argv[1],".byo"))
					Go(argv[1]);
				else
					puts("not a .byo file");				
			}
			else
				ftw(argv[1],LISTE,0);
		}
	else
	{
		puts("\nBYO2BMP 0.04\n\nBrice Allenbrand 2003 .byo to .bmp file converter.");
		puts("usage : byo2bmp file|dir [MERGE,BOOST]\n\n  dir    = directory where the .byo are located.\n  file   = .byo file.\n  [MERGE]= merge all .byo found in the directory into one .bmp file.\n  [BOOST]= highest resolution. (huge memory needed in case of MERGE)");
	}
}
