#include <stdio.h>
#include <stdlib.h>
#include <string.h>


unsigned char fill=0x00; 

unsigned char block[0x100];
int blockwhere;

int blocktype;
char checksum;

FILE *outFILE;

static int mode_mo5=0;

char *mo_fname="DEFAULT\0BIN";

void
create_block(int type) {
	int i;
	for (i=0;i<16;i++) {
		fputc(0x01,outFILE);
	}	

   	fputc(0x3C,outFILE);
   	fputc(0x5A,outFILE);
	checksum=0;
	blockwhere=0;
	blocktype=type;
}

void
put_block(unsigned char c){
	checksum+=c;
	checksum&=0xFF;
	block[blockwhere]=c;
	blockwhere++;
}

void
end_block() {
	int i;
	switch (blocktype) {
	case 0x00:
	case 0x01:
		fputc(blocktype,outFILE);		
		fputc((blockwhere+2)&0xff,outFILE);
		fprintf(stderr,"output a %d block type %d\n",(blockwhere+3)&0xFF,blocktype);
		for (i=0;i<blockwhere;i++)
			fputc(block[i],outFILE);
		fputc((0-checksum)&0xFF,outFILE);
		checksum+=(0-checksum)&0xFF;
		fprintf(stderr,"sum=%d\n",checksum);
		break;
	case 0xff:
		fputc(0xff,outFILE);
		fputc(0x02,outFILE);
		fputc(0x00,outFILE);
	break;
	}
}

 
static int
LoadBinFile(char *fname,char *k7Fname,int start,int exec)
{
   	unsigned char mem[0x10000+6];

	int address;
	int minaddr=0xffff;
	int maxaddr=0x0;

	int offset;
	int type;

	int i,j;
	int sizedata;
   	int size;
	unsigned char *data;
	FILE *f;

   	// clears mem
   	for (i=0;i<0x10000;i++) mem[i]=fill;
   
   	f=fopen(fname,"rb");
	if (f==NULL) {
		fprintf(stderr,"cannot open %s",fname);
		exit(-1);
	}

	// un fichier est composé de plusieurs blocs...
	while (!feof(f)) {	

		type=fgetc(f);

		if (type==0) {
			size=fgetc(f);
			size=(size<<8)|fgetc(f);

			address=fgetc(f);
			address=(address<<8)|fgetc(f);
			if (minaddr>address) minaddr=address;

			fprintf(stderr,"found block type %d len %x address %x\n",
				type,size,address);

   			fread(&mem[address],1,size,f);
			if (maxaddr<(address+size)) maxaddr=address+size;
		}

		if (type==0xff) {
			size=fgetc(f);
			size=(size<<8)|fgetc(f);

			if (exec==-1) {
				exec=fgetc(f);
				exec=(exec<<8)|fgetc(f);
			} else {fgetc(f);fgetc(f);}
			fprintf(stderr,"found block type %d exec %x\n",type,exec);
		}
	
	}


	if (start==-1)
	   	offset=minaddr;
	else
		offset=start;

	data=&mem[offset];
	sizedata=1+maxaddr-offset;


   	fprintf(stderr,"Size : 0x%x start:0x%x end:0x%x exec:0x%x\n",sizedata,offset,maxaddr,exec);
   	fclose(f);

   	// we now have bin in mem from low to high... 
   	outFILE=fopen(k7Fname,"wb");

   	// create a header
	create_block(0x00);
	{
		int i;
		for (i=0;i<11;i++) {
			put_block(mo_fname[i]);
		}
	}

	put_block(0x02); // binary	
	put_block(0x00); // binary	
	put_block(0x00); // dummy	

	end_block();

	j=0;


	create_block(0x01);
	// type de bloc logique
	put_block(0x00); // dummy
	put_block((sizedata&0xFF00)>>8);
	put_block(sizedata&0xFF);
	// adresse de chargement
	address=offset+i;
	put_block((address&0xFF00)>>8);
	put_block(address&0xFF);
	// data

	// on ajoute le bloc de fin
	data[sizedata++]=0xff;
	data[sizedata++]=0x0;
	data[sizedata++]=0x0;
	data[sizedata++]=(exec&0xFF00)>>8;
	data[sizedata++]=(exec&0xFF);

	while (sizedata>0) {
		while((blockwhere<254) && (sizedata>0)) {
			put_block(data[j++]);
			sizedata--;
		}
		end_block();
		if (sizedata>0) {
			create_block(0x01);
			// type de bloc logique
			put_block(0x01);			
		}
	}


   	// special end block
	create_block(0xFF);
	end_block();
        
   	fclose(outFILE);
   	return 0;
}

int 
main(int argc, char *argv[]) {
	char *file_in=NULL;
	char *file_out=NULL;
	
	int start=-1;
	int exec=-1;
	
	int argnum;
	
	for (argnum=1;argnum<argc;argnum++) {
		if (strncmp(argv[argnum],"-o",2)==0) file_out=&argv[argnum][2];
		if (strncmp(argv[argnum],"-i",2)==0) file_in=&argv[argnum][2];
		if (strncmp(argv[argnum],"-start",6)==0) 
			sscanf(&argv[argnum][6],"%x",&start);
		if (strncmp(argv[argnum],"-exec",5)==0)	
			sscanf(&argv[argnum][5],"%x",&exec);
		if (strncmp(argv[argnum],"-mo5",4)==0) {
			mode_mo5=1;
		}	
		if (strncmp(argv[argnum],"-fname",6)==0) {
			int i;
			mo_fname=&argv[argnum][6];
			/* normalize name (space converted to \0)*/
			for (i=7;i>0;i--) {
				if (mo_fname[i]!=' ') break;
				if (mo_fname[i]==' ') mo_fname[i]='\0';
			}
		}	
	}
	
	if (file_in==NULL) { fprintf(stderr,"No input file");exit(-1);};
	if (file_out==NULL) { fprintf(stderr,"No output file");exit(-1);};

	LoadBinFile(file_in,file_out,start,exec);
	return 0;
	
}
