/*-+ extremely quick and dirty DIB to CPC MODE 0+1+2 graphics encoder +-*/
/*-+ written by CNGSOFT for his personal projects a looooong time ago +-*/

#include <stdio.h>
#include <string.h> // strcmp
#include <stdlib.h> // atoi

FILE *fi,*fo; unsigned char tt[200],*si=NULL,*so=NULL,bi[1<<18],bo[1<<16],*s,*t,xlat[1<<8];
int encoding=0,mulx=2,muly=2,bx,by;
int grayjump[8]={+1,+2,-1,+4,+1,-2,-1,+4},grayturn; // 0,1,3,2,6,7,5,4: set 3,h.. set 4,h.. res 3,h.. set 5,h.. set 3,h.. res 4,h.. res 3,h.. res 5,h

int readint()
{
	unsigned char c; int n=1,t=0;
	while ((c=*s++)=='-')
		n=-1;
	do
		t=t*10+(c-48);
	while (((c=*s++)>='0')&&(c<='9'));
	return n*t;
}

int puterror(char *s) { return fprintf(stderr,"%s!\n",s),1; }

void parseline()
{
	if (*s>='0'&&*s<='9')
	{
		int x,y,gray;
		int px=readint();
		int py=readint();
		int lx=readint();
		int ly=readint();
		int tx=readint();
		int ty=readint();
		if (gray=(lx<=0))
			lx=-lx;
		for (int tty=0;tty<ty;++tty)
			for (int ttx=0;ttx<tx;++ttx)
				if ((by=ly*muly)>0)
				{
					y=(py+ly*tty)*muly;
					grayturn=0;
					while (by--)
					{
						s=bi+y*256+(px+lx*ttx)*mulx;
						x=lx*mulx;
						while (x--)
							*t++=*s++;
						if (gray)
							y+=grayjump[grayturn++&7];
						else
							++y;
					}
				}
				else
				{
					y=(py-ly*tty-ly)*muly-1;
					grayturn=0;
					while (by++)
					{
						s=bi+y*256+(px+lx*ttx)*mulx;
						x=lx*mulx;
						while (x--)
							*t++=*s++;
						if (gray)
							y-=grayjump[grayturn++&7];
						else
							--y;
					}
				}
	}
}

int main(int argc,char *argv[])
{
	int i=1,j; char *c,*script[256],scripts=0,glue=0;
	while (i<argc)
	{
		if (!strcmp(argv[i],"-a"))
			glue=1;
		else if (!strcmp(argv[i],"-m"))
			encoding=atoi(argv[++i]);
		else if (!strcmp(argv[i],"-x"))
			mulx=atoi(argv[++i]);
		else if (!strcmp(argv[i],"-y"))
			muly=atoi(argv[++i]);
		else if (!strcmp(argv[i],"-e"))
			script[scripts++]=argv[++i];
		else if (!si)
			si=argv[i];
		else if (!so)
			so=argv[i];
		else
			i=argc; // HELP!
		++i;
	}
	if (i>argc||!so)
	{
		fprintf(stderr,"syntax: DIB2 [-a] [-m MODE] [-x MULX] [-y MULY] source.dib target.bin/- [-e script_line] [< script_file.txt]");
		return 1;
	}
	switch (encoding)
	{
		case 0:
			for (i=0;i<256;++i)
				xlat[i]=((i&1)<<6)+((i&2)<<1)+((i&4)<<2)+((i&8)>>3)+
					((i&16)<<3)+((i&32)>>2)+((i&64)>>1)+((i&128)>>6);
			break;
		case 1:
			for (i=0;i<256;++i)
				xlat[i]=((i&1)<<4)+((i&2)>>1)+
					((i&4)<<3)+((i&8)>>2)+
					((i&16)<<2)+((i&32)>>3)+
					((i&64)<<1)+((i&128)>>4);
			break;
		default://case 2:
			for (i=0;i<256;++i)
				xlat[i]=i;
			break;
	}
	if (!(fi=fopen(si,"rb")))
		return puterror("cannot open source");
	fread(bo,1,10+4,fi);
	i=bo[10]+bo[11]*256-(10+4);
	fread(bo,1,i,fi);
	bx=bo[4]+bo[5]*256;
	by=bo[8]+bo[9]*256;
	while (by--)
	{
		t=bi+by*256; // UPSIDE DOWN!
		fread(s=bo,1,bx,fi);
		j=bx;
		switch (encoding)
		{
			case 0:
				while (j)
				{
					i=(15&*s++)<<4;
					i+=15&*s++;
					*t++=xlat[i];
					j-=2;
				}
				break;
			case 1:
				while (j)
				{
					i=(3&*s++)<<6;
					i+=(3&*s++)<<4;
					i+=(3&*s++)<<2;
					i+=3&*s++;
					*t++=xlat[i];
					j-=4;
				}
				break;
			case 2:
				while (j)
				{
					i=(1&*s++)<<7;
					i+=(1&*s++)<<6;
					i+=(1&*s++)<<5;
					i+=(1&*s++)<<4;
					i+=(1&*s++)<<3;
					i+=(1&*s++)<<2;
					i+=(1&*s++)<<1;
					i+=1&*s++;
					*t++=i;
					j-=8;
				}
				break;
			default:
				break;
		}
	}
	fclose(fi);

	t=bo;
	if (scripts)
		for (int z=0;z<scripts;++z)
			s=script[z],parseline();
	else
		while (gets(s=tt)&&*s!='*')
			parseline();

	if (strcmp(so,"-"))
	{
		if (!(fo=fopen(so,glue?"ab":"wb")))
			return puterror("cannot create target");
		//FILE *ff=fopen("temp","wb"); fwrite(bi,256,256,ff); fclose(ff);
		fwrite(bo,1,t-bo,fo);
		fclose(fo);
	}
	else
	{
		s=bo; i=0;
		while (s<t)
		{
			if (!i)
				printf(" db %i",*s++);
			else
				printf(",%i",*s++);
			if (++i>=16)
				i=0,printf("\n");
		}
		if (i)
			printf("\n");
	}
	return 0;
}
