/* obj2exl sourceFile targetFile [-t:EXE|DOS|ROM|K7|BAS] [-r:0xRelocAdr] [-b:0xBranchAdr] [-n:4LettersK7Filename] [-l:1|2] [-p] 
*/

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>

void erreur(int);
void init();
void end();
int ManageArguments();
int ExeConv();
int DosConv();
int RomConv();
int K7Conv();
int BasConv();
int load();
int save();

struct header_Exec
{
	unsigned char Reserved2;
	unsigned char Reserved1;
	unsigned char BrL;
	unsigned char BrH;	
	unsigned char CodeLengthL;
	unsigned char CodeLengthH;
	unsigned char RelocL;
	unsigned char RelocH;
	unsigned char Flag;
	unsigned char VersionL;
	unsigned char VersionH;
	char Check[6];

};

struct header_DCExel
{
	unsigned char Check;
	unsigned char Flag;
	unsigned char NbRecordH;
	unsigned char NbRecordL;	
	unsigned char MaxRecordLengthH;
	unsigned char MaxRecordLengthL;
	char Reserved1[7];
	unsigned char FirstAuH;
	unsigned char FirstAuL;
	unsigned char NbAu;
	char Reserved2[496];
};

char *source=NULL;
char *target=NULL;
int TypeDest=0;
unsigned short RelocAdr=0x0000;
unsigned short BrAdr=0x0000;
unsigned char K7Name[4]={0x20,0x20,0x20,0x20};
unsigned char *bufIN;
unsigned char *bufOUT;
int LengthIN;
int LengthOUT;
int pagination=0;
int clearvdp=0;
int loaderk7=0;

int main (int argc, char *argv[])
{
	int result;

	printf("Obj2Exl 2010.01 (c) Jester\n");
	if (ManageArguments(argc,argv))	exit(1);
	
	init();
	LengthIN=load();
	if (LengthIN) {
		switch (TypeDest)
		{
			case 1: result=ExeConv();break;
			case 2: result=DosConv();break;
			case 3: result=RomConv();break;
			case 4: result=K7Conv();break;
			case 5: result=BasConv();break;
		}
		if (!result) save();
	}
	end();
	exit(0);
}

void erreur(int err)
{
	fprintf(stderr,"ERROR: ");
	switch (err)
	{
		case 1: fprintf(stderr,"Same filename for source and target files.\n");break;
		case 2: fprintf(stderr,"Cannot open source file.\n");break;
		case 3: fprintf(stderr,"Cannot save target file.\n");break;
		case 4: fprintf(stderr,"When loading source file.\n");break;
		case 5: fprintf(stderr,"When saving target file.\n");break;
		case 6: fprintf(stderr,"Memory problem.\n");break;
		case 7: fprintf(stderr,"Allocation memory out of range.\n");break;
		case 8: fprintf(stderr,"Branch address out of range.\n");break;
		case 9: fprintf(stderr,"Binary source file too long.\n");break;
		default: fprintf(stderr,"Erreur %i\n",err);
	}
}

int ManageArguments(int argc, char *argv[])
{	int c,i;
	
	while ((c = getopt (argc, argv, "hpct:r:b:n:l:")) != -1)
		switch (c)
		{
			case 'h':
				fprintf(stdout,"Usage: obj2exl sourceFile targetFile [-t:EXE|DOS|ROM|K7|BAS] [-r:0xRelocAdr] [-b:0xBranchAdr] [-n:4LettersK7Filename] [-l:1|2] [-p] [-c]\n");	
				return 1;
			case 't':
				if (!strcmp(":EXE",optarg)) {
					TypeDest=1;
					if (!RelocAdr) RelocAdr=0x1000; }
				else
					if (!strcmp(":DOS",optarg)) {
						TypeDest=2;
						if (!RelocAdr) RelocAdr=0x1000; }
				else
					if (!strcmp(":ROM",optarg)) {
						TypeDest=3;
						if (!RelocAdr) RelocAdr=0x1000; }
				else
					if (!strcmp(":K7",optarg)) {
						TypeDest=4;
						if (!RelocAdr) RelocAdr=0xC300; }						
				else
					if (!strcmp(":BAS",optarg)) {
						TypeDest=5;
						if (!RelocAdr) RelocAdr=0xC380; }												
				break;
			case 'r':
				RelocAdr=strtol(optarg+1, NULL, 16);
				if (!TypeDest)
					{ if (RelocAdr<0xBFFF) TypeDest=1; else TypeDest=4;}
				break;
			case 'b':
				BrAdr=strtol(optarg+1, NULL, 16);
				if (!TypeDest)
					{ if (BrAdr<0xBFFF) TypeDest=1; else TypeDest=4;}
				break;
			case 'n':
				if (strlen(optarg+1)) {
					if (strlen(optarg+1)>4) {
						fprintf (stderr, "Incorrect K7 Filename.\n");
						return 1;}
					i=0;
					while ((optarg+1)[i]) K7Name[i++]=(optarg+1)[i];
				}
				break;
			case 'p':
				pagination=1;
				break;
			case 'c':
				clearvdp=1;
				break;
			case 'l':
				loaderk7=strtol(optarg+1, NULL, 10);
				if (loaderk7<1 || loaderk7>2)
					{ fprintf (stderr, "Basic loader must be type 1 or 2 (80 col mode init).\n");
						return 1;}				
				break;
			case '?':
				if (optopt == 'r' || optopt == 'b' || optopt == 'n' || optopt=='t')
					fprintf (stderr, "Option -%c requires an argument.\n", optopt);
				else if (isprint (optopt))
					fprintf (stderr, "Unknown option `-%c'.\n", optopt);
				else
					fprintf (stderr,"Unknown option character `\\x%x'.\n",optopt);
				return 1;
			default: return 1;
		}
	if (!TypeDest) {
		TypeDest=1;
		RelocAdr=0x1000; }
		
	if (!BrAdr) BrAdr=RelocAdr;
	else if (!RelocAdr) RelocAdr=BrAdr;
		else if (BrAdr<RelocAdr) {
			fprintf (stderr, "Branch Address must be greater than Relocation Adress.\n");
			return 1; }		
	
	if (argc-optind<2 || argc-optind>2)
		{
		fprintf (stderr,"Two arguments required: sourceFile TargetFile.\n");
		return 1; }
		
	source=argv[optind];
	target=argv[optind+1];
	if (!strcmp(source,target)) {erreur(1); return 1;}
	return 0;
}
 
 void init()
 {
	bufIN=malloc(65535);
	if (!bufIN) erreur(6);
	bufOUT=malloc(120320);
	if (!bufOUT) erreur(6);	
}
 
void end()
{
	if (bufIN) free(bufIN);
	if (bufOUT) free(bufOUT);
}

int load()
{
	FILE *fd;
	int longueur;
	
	fd=fopen(source,"rb");
	if (!fd) {erreur(2); return 0;}
	longueur=fread(bufIN,1,(unsigned short) 65535,fd);
	if (!longueur) erreur(4);
	fclose(fd);
	return longueur;
}

int save()
{
	FILE *fd;
	int longueur;
	
	fd=fopen(target,"wb");
	if (!fd) {erreur(3); return 0;}
	
	longueur=fwrite(bufOUT,1,LengthOUT,fd);
	if (LengthOUT!=longueur) erreur(5);
	fclose(fd);
	fprintf(stderr,"%s file written.\n",target);
	return longueur;
}

int ExeConv()
{	int i;
	int ptt=0;
	struct header_Exec hdex;	
	struct header_DCExel hddc;	
	if (RelocAdr<0x0200 || RelocAdr>0xBFFF) {erreur(7); return 1;}
	if (BrAdr<0x0200 || BrAdr>0xBFFF) {erreur(8); return 1;}
	if (LengthIN+RelocAdr>0xBFFF) {erreur(9); return 1;}


	hdex.Check[5]='J';
	hdex.Check[4]='E';
	hdex.Check[3]='S';
	hdex.Check[2]='T';
	hdex.Check[1]='E';
	hdex.Check[0]='R';	
	hdex.VersionL=0x01;
	hdex.VersionH=0x00;	
	hdex.Reserved1=0x00;
	hdex.Reserved2=0x00;
	hdex.Flag=0x01;
	
	if (RelocAdr<0x1000) hdex.Flag=hdex.Flag & 0xFE;
	if (RelocAdr+LengthIN>0x8000) hdex.Flag=hdex.Flag | 0x04;
	if (clearvdp) hdex.Flag=hdex.Flag | 0x02;

	hddc.Check=0xFD;
	hddc.Flag=0x00;
	hddc.NbRecordH=0x00;
	hddc.NbRecordL=0x02;	
	for(i=0;i<7;i++) hddc.Reserved1[i]=0;
	hddc.FirstAuH=0x00;
	hddc.FirstAuL=0x01;
	for(i=0;i<496;i++) hddc.Reserved2[i]=0;

	hddc.MaxRecordLengthH=LengthIN/256;
	hddc.MaxRecordLengthL=LengthIN & 0xFF;	
	float NBAU=ceil((LengthIN+2+sizeof(struct header_Exec))/512);
	if (NBAU<((float)(LengthIN+2+sizeof(struct header_Exec))/(float)512)) hddc.NbAu=NBAU+1;
	else hddc.NbAu=NBAU;
	
	hdex.RelocL=(RelocAdr +LengthIN -1)& 0xFF;
	hdex.RelocH=(RelocAdr +LengthIN -1) / 256;
	hdex.BrL=BrAdr & 0xFF;
	hdex.BrH=BrAdr / 256;
	hdex.CodeLengthL=LengthIN & 0xFF;
	hdex.CodeLengthH=LengthIN / 256;

	memcpy(bufOUT,&hddc, sizeof(struct header_DCExel));
	ptt=ptt+sizeof(struct header_DCExel);
	bufOUT[ptt++]=sizeof(struct header_Exec) / 256;
	bufOUT[ptt++]=sizeof(struct header_Exec) & 0xFF;
	memcpy(bufOUT+ptt,&hdex, sizeof(struct header_Exec));
	ptt=ptt+sizeof(struct header_Exec);
	bufOUT[ptt++]=hddc.MaxRecordLengthH;
	bufOUT[ptt++]=hddc.MaxRecordLengthL;
	
	for(i=LengthIN-1;i>=0;i--) bufOUT[ptt++]=bufIN[i];
	for(;ptt<(hddc.NbAu+1)*512;ptt++) bufOUT[ptt]=0;

	LengthOUT=ptt;
	
	return 0;
}

int DosConv()
{	int i,j,nbfulline,Wlastline,Blastline,nbR,byteL,byteH;
	int ptt,pts,ptl;
	struct header_DCExel hddc;
	char firstline[]= {00,71,'K',0,0,0,0,'J','E','S','T','E','R',32,32,'F',
					   32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
					   32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
					   32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
					   32,32,32,32,32,32,32,32,32};
	char lastline[]= {00,71,':','O','B','J','2','E','X','L',32,'C','O','N','V','E',
					  'R','T','E','R',32,'2','.','0',32,32,32,32,32,32,32,32,
					  32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
					  32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
					  32,32,32,32,32,32,32,32,32};
	char line[]= {00,71,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
				  32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
				  32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
			      32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
				  32,32,32,32,32,32,32,32,32};
	char linebis[]= {00,71,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
				  32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
				  32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
			      32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,
				  32,32,32,32,32,32,32,32,32};

	char hexadigit[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
	
	if (RelocAdr!=0x1000) {erreur(7); return 1;}
	if (BrAdr!=0x1000) {erreur(8); return 1;}
	if (LengthIN>0xB000) {erreur(9); return 1;}

	nbfulline=LengthIN / 28;
	Wlastline=(LengthIN % 28)/2;
	Blastline=(LengthIN % 28)%2;
	nbR=nbfulline + 2 + (Wlastline+Blastline >0);
	
	hddc.Check=0xFD;
	hddc.Flag=0x00;
	hddc.NbRecordH=nbR / 256;
	hddc.NbRecordL=nbR & 0xFF;	
	for(i=0;i<7;i++) hddc.Reserved1[i]=0;
	hddc.FirstAuH=0x00;
	hddc.FirstAuL=0x01;
	for(i=0;i<496;i++) hddc.Reserved2[i]=0;

	hddc.MaxRecordLengthH=71/256;
	hddc.MaxRecordLengthL=71 & 0xFF;	
	float NBAU=ceil( (nbR*73) /512);
	if (NBAU<((float)(nbR*73)/(float)512)) hddc.NbAu=NBAU+1;
	else hddc.NbAu=NBAU;
	
	pts=ptt=0;
	
	memcpy(bufOUT,&hddc, sizeof(struct header_DCExel));
	ptt=ptt+sizeof(struct header_DCExel);
	memcpy(bufOUT+ptt,firstline, 73);
	ptt=ptt+73;
	
	for(i=0;i<nbfulline;i++){
		ptl=2;
		for(j=0;j<14;j++) {
			line[ptl++]='B';
			byteH=bufIN[pts++];
			byteL=bufIN[pts++];
			line[ptl++]=hexadigit[byteH/16];
			line[ptl++]=hexadigit[byteH%16];
			line[ptl++]=hexadigit[byteL/16];
			line[ptl++]=hexadigit[byteL%16];
			}
		line[ptl++]='F';
		memcpy(bufOUT+ptt,line, 73);
		ptt=ptt+73;
	}

	ptl=2;
	for(i=0;i<Wlastline;i++){
		linebis[ptl++]='B';
		byteH=bufIN[pts++];
		byteL=bufIN[pts++];
		linebis[ptl++]=hexadigit[byteH/16];
		linebis[ptl++]=hexadigit[byteH%16];
		linebis[ptl++]=hexadigit[byteL/16];
		linebis[ptl++]=hexadigit[byteL%16];
	}
	if (Blastline) {
		linebis[ptl++]='*';
		byteL=bufIN[pts++];
		linebis[ptl++]=hexadigit[byteL/16];
		linebis[ptl++]=hexadigit[byteL%16];
	}
	linebis[ptl++]='F';
	memset(linebis+ptl,32,73-ptl);
	memcpy(bufOUT+ptt,linebis, 73);
	ptt=ptt+73;
	
	memcpy(bufOUT+ptt,lastline, 73);
	ptt=ptt+73;

	for(;ptt<(hddc.NbAu+1)*512;ptt++) bufOUT[ptt]=0;
	LengthOUT=ptt;

	return 0;
}

int RomConv()
{
	int i;
	
	if (RelocAdr<0x0200 || RelocAdr>0x7FFB) {erreur(7); return 1;}
	if (BrAdr<0x0200 || BrAdr>0x7FFB) {erreur(8); return 1;}
	if (LengthIN+RelocAdr>0x7FFB) {erreur(9); return 1;}

	for(i=0;i<0x7E00;i++) bufOUT[i]=0;
	
	if (pagination) bufOUT[0x7DFC]=0x55;
	else bufOUT[0x7DFC]=0xAA;
	bufOUT[0x7DFD]=0x8C;
	bufOUT[0x7DFE]=BrAdr/256;
	bufOUT[0x7DFF]=BrAdr & 0xFF;
	
	for(i=0;i<LengthIN;i++) bufOUT[RelocAdr-0x0200+i]=bufIN[i];
	
	LengthOUT=0x7E00;
	
	return 0;
}

int K7Conv()
{
	char sync[256] = {
										0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
										0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
										0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
										0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
										0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
										0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
										0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
										0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
										0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
										0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
										0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
										0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
										0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
										0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
										0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
										0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
										0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
										0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
										0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
										0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
										0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
										0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
										0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
										0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
										0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
										0x55,0x55,0x55,0x55,0x55,0x70};
	char loader1[29] = {
0x49,0x4D,0x44,0xB3,0x7A,0xDD,0xC0,0xCC,0xC0,0x80,0x0F,0xDD,0x00,0x00,0x5D,0x00,
0x5D,0x00,0x00,0x00,0x04,0x01,0x00,0x02,0x00,0x00,0x00,0x2D,0x2D};
	char loader1b[105] = {
0x49,0x4D,0x44,0x4C,0x7A,0x3A,0x10,0xDD,0x0F,0x80,0x03,0x00,0x57,0x64,0x00,0x50,
0x95,0xCA,0x04,0x50,0x4F,0x4B,0x45,0xC0,0xC4,0x42,0x05,0x11,0x89,0xAD,0xC3,0x41,
0x01,0x84,0xAD,0xC2,0x41,0x02,0xAD,0xC3,0x41,0x01,0x14,0xAD,0xC2,0x40,0x03,0xAD,
0xC2,0x40,0x32,0xAD,0xC3,0x41,0x01,0x16,0xAD,0xC2,0x40,0x08,0xAD,0xC2,0x40,0x32,
0xAD,0xC3,0x41,0x02,0x41,0xAD,0xC3,0x41,0x01,0x56,0xAD,0xC2,0x40,0x28,0xAF,0x00,
0x95,0xCA,0x04,0x45,0x58,0x45,0x43,0xC0,0xC4,0x42,0x05,0x11,0x89,0xAF,0x00,0xFF,
0x7F,0x03,0x86,0x00,0x20,0x00,0x10,0x7B,0x7B};
	char loader2[29] = {
0x50,0x4D,0x44,0x4C,0x7A,0xDD,0xC0,0xCC,0xC0,0x80,0x0F,0xDD,0x00,0x02,0x21,0x02,
0x21,0x00,0x00,0x00,0x04,0x01,0x00,0x0A,0x00,0x00,0x00,0xC1,0xC1};
	char loader2b[557] = {
0x50,0x4D,0x44,0x4C,0x7A,0xFE,0x11,0xDD,0x0F,0x80,0x03,0x02,0x13,0x64,0x00,0x0F,
0xA2,0xCA,0x05,0x35,0x31,0x31,0x31,0x36,0xAD,0xCA,0x02,0x38,0x34,0x00,0x6E,0x00,
0x5C,0xA2,0xCA,0x03,0x31,0x34,0x30,0xAD,0xCA,0x03,0x31,0x39,0x39,0xAD,0xCA,0x03,
0x32,0x32,0x36,0xAD,0xCA,0x03,0x31,0x33,0x39,0xAD,0xCA,0x01,0x31,0xAD,0xCA,0x02,
0x35,0x33,0xAD,0xCA,0x03,0x31,0x39,0x37,0xAD,0xCA,0x03,0x31,0x37,0x30,0xAD,0xCA,
0x03,0x31,0x39,0x39,0xAD,0xCA,0x03,0x31,0x39,0x30,0xAD,0xCA,0x03,0x31,0x33,0x30,
0xAD,0xCA,0x02,0x34,0x35,0xAD,0xCA,0x03,0x31,0x39,0x35,0xAD,0xCA,0x02,0x39,0x33,
0xAD,0xCA,0x02,0x33,0x36,0xAD,0xCA,0x03,0x32,0x33,0x30,0x00,0x78,0x00,0x4E,0xA2,
0xCA,0x03,0x32,0x34,0x36,0xAD,0xCA,0x02,0x31,0x30,0xAD,0xCA,0x01,0x34,0xAD,0xCA,
0x02,0x31,0x36,0xAD,0xCA,0x01,0x35,0xAD,0xCA,0x03,0x31,0x32,0x38,0xAD,0xCA,0x01,
0x36,0xAD,0xCA,0x03,0x31,0x33,0x36,0xAD,0xCA,0x01,0x37,0xAD,0xCA,0x01,0x30,0xAD,
0xCA,0x01,0x31,0xAD,0xCA,0x03,0x32,0x35,0x35,0xAD,0xCA,0x01,0x32,0xAD,0xCA,0x03,
0x32,0x35,0x35,0xAD,0xCA,0x01,0x38,0xAD,0xCA,0x01,0x30,0x00,0x82,0x00,0x49,0xA2,
0xCA,0x01,0x30,0xAD,0xCA,0x01,0x31,0xAD,0xCA,0x03,0x32,0x35,0x35,0xAD,0xCA,0x01,
0x32,0xAD,0xCA,0x03,0x32,0x35,0x35,0xAD,0xCA,0x01,0x39,0xAD,0xCA,0x01,0x30,0xAD,
0xCA,0x01,0x30,0xAD,0xCA,0x01,0x31,0xAD,0xCA,0x03,0x32,0x35,0x35,0xAD,0xCA,0x01,
0x32,0xAD,0xCA,0x01,0x39,0xAD,0xCA,0x02,0x31,0x30,0xAD,0xCA,0x01,0x30,0xAD,0xCA,
0x01,0x30,0xAD,0xCA,0x01,0x31,0x00,0x8C,0x00,0x57,0xA2,0xCA,0x03,0x32,0x35,0x35,
0xAD,0xCA,0x01,0x32,0xAD,0xCA,0x03,0x32,0x35,0x35,0xAD,0xCA,0x02,0x31,0x35,0xAD,
0xCA,0x01,0x30,0xAD,0xCA,0x01,0x30,0xAD,0xCA,0x03,0x31,0x38,0x34,0xAD,0xCA,0x03,
0x32,0x30,0x30,0xAD,0xCA,0x03,0x31,0x33,0x38,0xAD,0xCA,0x03,0x32,0x34,0x30,0xAD,
0xCA,0x01,0x36,0xAD,0xCA,0x02,0x34,0x35,0xAD,0xCA,0x03,0x32,0x35,0x35,0xAD,0xCA,
0x03,0x32,0x32,0x36,0xAD,0xCA,0x02,0x31,0x38,0xAD,0xCA,0x03,0x31,0x34,0x32,0x00,
0x96,0x00,0x5A,0xA2,0xCA,0x03,0x31,0x39,0x39,0xAD,0xCA,0x03,0x31,0x37,0x35,0xAD,
0xCA,0x03,0x31,0x34,0x32,0xAD,0xCA,0x03,0x32,0x34,0x30,0xAD,0xCA,0x02,0x33,0x34,
0xAD,0xCA,0x03,0x31,0x34,0x32,0xAD,0xCA,0x03,0x32,0x34,0x30,0xAD,0xCA,0x02,0x32,
0x32,0xAD,0xCA,0x03,0x31,0x31,0x34,0xAD,0xCA,0x01,0x33,0xAD,0xCA,0x02,0x33,0x32,
0xAD,0xCA,0x03,0x31,0x31,0x36,0xAD,0xCA,0x01,0x38,0xAD,0xCA,0x02,0x33,0x32,0xAD,
0xCA,0x03,0x32,0x34,0x31,0xAD,0xCA,0x03,0x31,0x35,0x36,0x00,0xA0,0x00,0x18,0xA2,
0xCA,0x02,0x32,0x38,0xAD,0xCA,0x03,0x32,0x30,0x31,0xAD,0xCA,0x03,0x31,0x38,0x35,
0xAD,0xCA,0x02,0x31,0x30,0x00,0xAA,0x00,0x33,0xA1,0x20,0xAD,0x21,0x00,0x9B,0x22,
0xB6,0xC2,0x00,0x00,0xAB,0x21,0xBB,0xC2,0x40,0x01,0x00,0xA1,0x23,0x00,0x95,0xCA,
0x04,0x50,0x4F,0x4B,0x45,0xC0,0x20,0xBA,0x22,0xAD,0x23,0xAF,0x00,0x9C,0x22,0x00,
0x95,0xCA,0x04,0x45,0x58,0x45,0x43,0xC0,0x20,0xAF,0x00,0xFF,0x7F,0x03,0x86,0x00,
0x24,0x01,0xC4,0x01,0xC9,0x01,0xCE,0x01,0xC1,0x00,0x00,0xB0,0xB0};
	int i,ptt=0;
	unsigned char checksum=0;

	if ((RelocAdr<0x8000 || RelocAdr>0xBFFF)&&(RelocAdr<0xC300 || RelocAdr>0xC7FF)) {erreur(7); return 1;}
	if (RelocAdr!=BrAdr) {erreur(8); return 1;}
	if (RelocAdr>=0x8000 && RelocAdr<=0xBFFF && LengthIN+RelocAdr>0xBFFF) {erreur(9); return 1;}

	if (loaderk7==1) {
		if (RelocAdr>=0xC300 && RelocAdr<0xC800 && LengthIN+RelocAdr>0xC7FE) {erreur(9); return 1;}
		loader1[0]=K7Name[3];
		loader1[1]=K7Name[2];
		loader1[2]=K7Name[1];
		loader1[3]=K7Name[0];

		loader1b[0]=K7Name[3];
		loader1b[1]=K7Name[2];
		loader1b[2]=K7Name[1];
		loader1b[3]=K7Name[0];
		memcpy(bufOUT+ptt,sync,256);
		ptt=ptt+256;
		memcpy(bufOUT+ptt,loader1,29);
		ptt=ptt+29;
		memcpy(bufOUT+ptt,sync,256);
		ptt=ptt+256;
		memcpy(bufOUT+ptt,loader1b,105);
		ptt=ptt+105;
	}
	else if (loaderk7==2) {
		if (RelocAdr>=0xC300 && RelocAdr<0xC800 && LengthIN+RelocAdr>0xC7FA) {erreur(9); return 1;}
		loader2[0]=K7Name[3];
		loader2[1]=K7Name[2];
		loader2[2]=K7Name[1];
		loader2[3]=K7Name[0];

		loader2b[0]=K7Name[3];
		loader2b[1]=K7Name[2];
		loader2b[2]=K7Name[1];
		loader2b[3]=K7Name[0];
		memcpy(bufOUT+ptt,sync,256);
		ptt=ptt+256;
		memcpy(bufOUT+ptt,loader2,29);
		ptt=ptt+29;
		memcpy(bufOUT+ptt,sync,256);
		ptt=ptt+256;
		memcpy(bufOUT+ptt,loader2b,557);
		ptt=ptt+557;}
	else
		if (RelocAdr>=0xC300 && RelocAdr<0xC800 && LengthIN+RelocAdr>0xC7FF) {erreur(9); return 1;}
	
	memcpy(bufOUT+ptt,sync,256);
	ptt=ptt+256;
	bufOUT[ptt++]=K7Name[3];
	bufOUT[ptt++]=K7Name[2];
	bufOUT[ptt++]=K7Name[1];
	bufOUT[ptt++]=K7Name[0];
	bufOUT[ptt++]=0x7A;	
	bufOUT[ptt++]=(RelocAdr+LengthIN-1)&0x00FF;
	bufOUT[ptt++]=(RelocAdr+LengthIN-1)/256;
	bufOUT[ptt++]=RelocAdr & 0xFF;
	bufOUT[ptt++]=RelocAdr/256;	
	for(i=0;i<LengthIN;i++) {
		bufOUT[ptt++]=bufIN[i];
		checksum=checksum+bufIN[i];}
	bufOUT[ptt++]=checksum;
	bufOUT[ptt++]=checksum;	
	
	LengthOUT=ptt;
		
	return 0;
}

int BasConv()
{
	int i;
	int parlg=17;
	int nblg=100;
	int ptt=0;
	
	if (RelocAdr<0xC380 || RelocAdr>0xC7FF) {erreur(7); return 1;}
	if (BrAdr!=RelocAdr) {erreur(8); return 1;}
	if (LengthIN+RelocAdr>0xC7FF) {erreur(9); return 1;}

	ptt=ptt+sprintf(bufOUT,"%u DATA %u,%u",nblg,RelocAdr,LengthIN);
	nblg=nblg+10;
	for(i=0; i<LengthIN; i++,parlg++)
	{
		if (parlg>16)
		{
			ptt=ptt+sprintf(bufOUT+ptt,"\r\n%u DATA ",nblg);
			parlg=1;
			nblg=nblg+10;
		}
		ptt=ptt+sprintf(bufOUT+ptt,"%u",bufIN[i]);
		if (i<LengthIN-1 && parlg<16) ptt=ptt+sprintf(bufOUT+ptt,",");
	}
	ptt=ptt+sprintf(bufOUT+ptt, "\r\n");
	
	ptt=ptt+sprintf(bufOUT+ptt, "%u READ A,N:FOR I=0 TO N-1:READ D:CALL POKE(A+I,D):NEXT I:CALL EXEC(A)\r\n",nblg);
	
	LengthOUT=ptt;
	
	return 0;
}
