 /*
 |  Converts an AmigaDOS executable to a MAPUX one
*/

#include <stdio.h>
#include <stdlib.h>
#include <libraries/dos.h>

#define	EMAGIC1	(0x12345678)

 /*
 |  These are the only hunk types recognised
*/
#define HUNK_CODE       1001
#define HUNK_DATA       1002
#define HUNK_BSS        1003
#define HUNK_RELOC32    1004
#define HUNK_END        1010
#define HUNK_HEADER     1011


int	*hunk[64];		/* Maximum number of hunks */
int	*thunk, *block;
int	htype[64];		/* Maximum again */
int	hlen[64];		/* ...and again */
int	haddr[64];		/* ...and again */
int	hids[64];

typedef struct thing
{
	int	len;
	char	*block;
} thing;

thing	theader,
	tcode,
	tdata,
	treloc1,
	treloc2,
	treloc3,
	treloc4,
	treloc5,
	treloc6;


 /*
 |  Modularity?  Wassat then?
*/
main( argc, argv )
int	argc;
char	**argv;
{
	int	word, len, ignore, currhunk, t, totlen, a, b, pos, hunknum, lasthunk;
	int	codelen, datalen, bsslen;
	char	*outname;
	BPTR	infile, outfile;

	for(t=0;t<32;t++)
	{
		hunk[t]=0;
		hids[t]=-1;
	}

	if( argc != 2 )
	{
		printf("Usage: ados2mapux filename\n");
		exit(0);
	}

	if( (infile=Open( argv[1], MODE_OLDFILE )) == 0 )
	{
		printf("Error: cannot open input file\n");
		exit(0);
	}

	outname=(char*)malloc( strlen(argv[1])+7 );
	strcpy( outname, argv[1] );
	strcat( outname, ".mapux" );
	
	if( (outfile=Open( outname, MODE_NEWFILE )) == 0 )
	{
		free( outname );
		Close( infile );
		printf("Error: cannot open output file (%s)\n", outname );
		exit(0);
	}

	free( outname );

	hunknum=0;
	currhunk=0;
	ignore=0;
	lasthunk=-1;

	while( myread( infile, &word, 4 ) == 4 )
	{
		_CheckIntr();
		if( ignore-- == 0 )
		{
			ignore=0;
			if( word != HUNK_END )
				myread( infile, &len, 4 );
			else
				len=0;
			switch( word )
			{
				case HUNK_CODE:
				case HUNK_DATA:
				{
					hids[currhunk]=hunknum++;
					htype[currhunk]=word;
					hlen[currhunk]=len;
					hunk[currhunk]=(int*)malloc( len*4 );
					myread( infile, hunk[currhunk], len*4 );
					lasthunk=currhunk++;
					break;
				}
				case HUNK_BSS:
				{
					hids[currhunk]=hunknum++;
					htype[currhunk]=word;
					hlen[currhunk]=len;
					hunk[currhunk]=(void*)1; /* This is not a terminator */
					currhunk++;
					break;
				}
				case HUNK_HEADER:
				{
					htype[currhunk]=word;
					myread( infile, &t, 4 );
					hunk[currhunk]=(int*)malloc( 16 + (4*t) );
					hlen[currhunk]=4+t;
					*hunk[currhunk]=len;
					*(hunk[currhunk]+1)=t;
					myread( infile, hunk[currhunk++]+2, 8+(4*t) );
					break;
				}
				case HUNK_RELOC32:
				{
					htype[currhunk]=word;
					hlen[currhunk]=0;
					hunk[currhunk]=0;
					while( len != 0 )
					{
						thunk=(int*)malloc((hlen[currhunk]+len+3)*4);
						*(thunk+hlen[currhunk]+len+2)=0;
						if( hunk[currhunk]!=0 )
						{
							for( t=0; t<hlen[currhunk]; t++ )
								*(thunk+t)=*(hunk[currhunk]+t);
							free( hunk[currhunk] );
						}
						myread( infile, thunk+hlen[currhunk]+1, (len+1)*4 );
						*(thunk+hlen[currhunk])=len;
						hlen[currhunk]+=len+2;
						hunk[currhunk]=thunk;
						myread( infile, &len, 4 );
					}
					hlen[currhunk]=lasthunk;
					currhunk++;
					break;
				}
				case HUNK_END:
				{
					break;
				}
				default:
				{
					printf("ados2mapux: Unknown hunktype %i - trying to skip\n",word);
					ignore=len;
				}
			}
		}
	}

	Close( infile );

	/* Total up the length of the file and get some memory for it */
	totlen=codelen=datalen=bsslen=0;
	t=-1;
	while( hunk[++t] )
	{
		if( (htype[t]==HUNK_CODE) )
		{
			totlen+=hlen[t];
			codelen+=hlen[t];
		}
		if( (htype[t]==HUNK_DATA) )
		{
			totlen+=hlen[t];
			datalen+=hlen[t];
		}
		if( (htype[t]==HUNK_BSS) )
			bsslen+=hlen[t];
	}

	block = (int*)malloc( 32 );	/* Length of header */
	*block     = EMAGIC1;
	*(block+1) = codelen;
	*(block+2) = datalen;
	*(block+3) = bsslen;
	*(block+4) = 2048;	/* 8KB stack */
	*(block+5) = 0;		/* Minimal break space (1 block) */
	*(block+6) = 0;		/* Extentions offset unknown */
	*(block+7) = 0;		/* Currently unused */
	theader.len = 32;
	theader.block = block;

	/* Space for code */
	block = (int*)malloc(codelen*4);

	/* Put all the text segments in */
	pos=0;
	t=-1;
	while( hunk[++t] )
		if( htype[t]==HUNK_CODE )
		{
			for( a=0; a<hlen[t]; a++ )
				*(block+pos+a)=*(hunk[t]+a);
			haddr[t]=pos;
			pos+=hlen[t];
		}

	/* Write the code (base=0) to disc */
	tcode.len = codelen*4;
	tcode.block = block;

	/* Space for code */
	block = (int*)malloc(datalen*4);

	/* Put all the data segments in */
	pos = 0;
	t=-1;
	while( hunk[++t] )
		if( htype[t]==HUNK_DATA )
		{
			for( a=0; a<hlen[t]; a++ )
				*(block+pos+a)=*(hunk[t]+a);
			haddr[t]=pos;
			pos+=hlen[t];
		}

	tdata.len = datalen*4;
	tdata.block = block;

	/* Pretend to put all the bss segments in */
	pos = 0;
	t=-1;
	while( hunk[++t] )
		if( htype[t]==HUNK_BSS )
		{
			haddr[t]=pos;
			pos+=hlen[t];
		}

	/* Create relocations */
	makereloc( HUNK_CODE, HUNK_CODE, &treloc1 );
	makereloc( HUNK_CODE, HUNK_DATA, &treloc2 );
	makereloc( HUNK_CODE, HUNK_BSS,  &treloc3 );
	makereloc( HUNK_DATA, HUNK_DATA, &treloc4 );
	makereloc( HUNK_DATA, HUNK_CODE, &treloc5 );
	makereloc( HUNK_DATA, HUNK_BSS,  &treloc6 );

	t=-1;
	while( hunk[++t] )
		if( hunk[t] != (void*)1 )
			free( hunk[t] );

	Write( outfile, theader.block, theader.len );
	Write( outfile, tcode.block, tcode.len );
	Write( outfile, tdata.block, tdata.len );
	Write( outfile, treloc1.block, treloc1,len );
	Write( outfile, treloc2.block, treloc2,len );
	Write( outfile, treloc3.block, treloc3,len );
	Write( outfile, treloc4.block, treloc4,len );
	Write( outfile, treloc5.block, treloc5,len );
	Write( outfile, treloc6.block, treloc6,len );

	Close( outfile );

}

int makereloc( btype, rtype, this_thing )
int	btype,
	rtype;
thing	*this_thing;
{
	int	bpos = 1;
	int	blen = 0;
	int	t=-1, a, b, flag, len, hunknum, ch;
	int	*block = (int*)malloc(16384);
	int	*fitblk;
	char	*bblk;
	
	while( hunk[++t] )
	{
		if( htype[t]==HUNK_RELOC32 && (htype[hlen[t]]==btype) )
		{
			len=*hunk[t];
			a=0;
			while( len )
			{
				ch=*(hunk[t]+a+1);
				hunknum=-1;
				flag=0;
				while( hunk[++hunknum] && !flag )
					if( hids[hunknum]==ch )
						flag=1;
				hunknum--;
				if( flag && (htype[hunknum]==rtype) )
				{
					for(b=0;b<len;b++)
					{
						block[1+blen] = (int)( ((char*)haddr[hlen[t]])+*(hunk[t]+2+b+a) );
						if( btype == HUNK_DATA )
							bblk = tdata.block;
						else
							bblk = tcode.block;
						*((int*)((bblk)+block[1+blen])) += (int)( (haddr[hunknum]*4) );
						blen++;
					}
				}
				a+=2+len;
				len=*(hunk[t]+a);
			}
		}
	}

	block[0] = blen;

	fitblk = (int*)malloc( 4*(blen+1) );

	bcopy( block, fitblk, 4*(blen+1) );
	free(block);

	this_thing->len = 4*(blen+1);
	this_thing->block = fitblk;
}


int myread( infile, buf, len )
BPTR	*infile;
char	*buf;
int	len;
{
	int	sofar = len;
	int	one;

	while( sofar && (one=Read(infile,buf,sofar)) )
	{
		buf   += one;
		sofar -= one;
	}

	return( len-sofar );
}

/* Yawn... put on the kettle, George */
bcopy( src, dst, len )
char	*src,
	*dst;
int	len;
{
	while( len-- )
		*dst++ = *src++;
}

