/****************************************************************************************/
/* Nib2Dsk - convert Apple II nibble order disk images to DOS order images              */
/*                                                                                      */
/* Original C++ source EMU2EM.CPP by Dan Scholnik   dpscholn@mtu.edu                    */
/*                                                                                      */
/* Translation to ANSI C, minor modifications, and port to RiscOS                       */
/*                                by M.I.K.e        mlkoenig@linguistik.uni-erlangen.de */
/* Last change: 1998-2-5                                                                */
/****************************************************************************************/

#include <stdio.h>
#include <stdlib.h>

#define	addr_mask	0x55
#define	mask1	  	0x03
#define	mask2		0x0C
#define	mask3		0x30
#define	mark		0xD5

int main(int argc, char *argv[])
{
	FILE *outfile;
	FILE *infile;
	unsigned char nibble_high[256], nibble_low[86], bytes[256];
	unsigned char trans_table[] =
					{ 0x96, 0x97, 0x9A, 0x9B, 0x9D, 0x9E, 0x9F, 0xA6,
				   	  0xA7, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB2, 0xB3,
					  0xB4, 0xB5, 0xB6, 0xB7, 0xB9, 0xBA, 0xBB, 0xBC,
					  0xBD, 0xBE, 0xBF, 0xCB, 0xCD, 0xCE, 0xCF, 0xD3,
					  0xD6, 0xD7, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE,
					  0xDF, 0xE5, 0xE6, 0xE7, 0xE9, 0xEA, 0xEB, 0xEC,
					  0xED, 0xEE, 0xEF, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6,
					  0xF7, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF };
	unsigned char reverse_bits[] = {0x00, 0x02, 0x01, 0x03};
	unsigned char interleave[] =
					{ 0x00, 0x07, 0x0E, 0x06, 0x0D, 0x05, 0x0C, 0x04,
					  0x0B, 0x03, 0x0A, 0x02, 0x09, 0x01, 0x08, 0x0F };
	int x, y, byte_count, nibble_count;
	unsigned int header;
	long file_count,pos;
	unsigned char nibble_in,nibble_trans,byte_out,track_even, track_odd, track;
	unsigned char chksum, sector_odd, sector_even, sector, last_nibble;
	unsigned char volume, volume_odd, volume_even;
	char command[30];

	if (argc!=3)
	{
		printf("Usage: nib2dsk infile outfile\n");
		exit(1);
	}
	else
	{
		infile = fopen(argv[1], "rb");
		if (infile == NULL)
		{
			printf("Input file does not exist.\n");
			exit(2);
		}
		
		fseek(infile, 0, SEEK_END);
		if(ftell(infile) != 232960)
		{
		  printf("Input file is no nibble order image.\n");
		  exit(5);
		}
		rewind(infile);
		
		outfile = fopen(argv[2], "wb");
		if (outfile == NULL)
		{
			printf("Could not create output file.\n");
			exit(3);
		}
	}
	/* fill output file with 143360 bytes */
	for(x=0;x<35;x++)
		for(y=0;y<16;y++)
			fwrite(bytes, 256, 1, outfile);
	rewind(outfile);

  for(x=0;x<(35*16);x++)
  {
	byte_count=nibble_count=header=0;
	/* seek to address field */
	nibble_in=0;
	while (!header && !feof(infile))
	{
		while ((nibble_in!=mark) && !feof(infile))
			nibble_in = fgetc(infile);
		nibble_in = fgetc(infile);
		if (nibble_in==0xAA)
		{
			nibble_in = fgetc(infile);
			if (nibble_in==0x96)
				header=1;
		}
	}
	if (feof(infile)) break;
	/* get volume */
	volume_odd = fgetc(infile);
	volume_even = fgetc(infile);
	volume_odd&=addr_mask;
	volume_odd<<=1;
	volume_even&=addr_mask;
	volume=volume_odd|volume_even;
	/* get track# */
	track_odd = fgetc(infile);
	track_even = fgetc(infile);
	track_odd&=addr_mask;
	track_odd<<=1;
	track_even&=addr_mask;
	track=track_odd|track_even;
	/* get sector# */
	sector_odd = fgetc(infile);
	sector_even = fgetc(infile);
	sector_odd&=addr_mask;
	sector_odd<<=1;
	sector_even&=addr_mask;
	sector=sector_odd|sector_even;
	/* get checksum and check
	   get epilogue and check */

	/* seek to data field */
	header=0;
	while (!header && !feof(infile))
	{
		while ((nibble_in!=mark) && !feof(infile))
			nibble_in = fgetc(infile);
		nibble_in = fgetc(infile);
		if (nibble_in==0xAA)
		{
			nibble_in = fgetc(infile);
			if (nibble_in==0xAD)
				header=1;
		}
	}
	if (feof(infile)) break;
	/* read in 342 bytes data and do cumulative xor */
	last_nibble=0;

	pos = ftell(infile);

	for(nibble_count=0;nibble_count<86;nibble_count++)
	{
		nibble_in = fgetc(infile);
		nibble_trans=0;
		while (trans_table[nibble_trans]!=nibble_in)
			nibble_trans++;
		last_nibble=nibble_trans^last_nibble;
		nibble_low[nibble_count]=last_nibble;
	}
	for(nibble_count=0;nibble_count<256;nibble_count++)
	{
		nibble_in = fgetc(infile);
		nibble_trans=0;
		while (trans_table[nibble_trans]!=nibble_in)
			nibble_trans++;
		last_nibble=nibble_trans^last_nibble;
		nibble_high[nibble_count]=last_nibble<<2;
	}
	/* get checksum byte and xor with last data. should be 0 */
	nibble_in = fgetc(infile);
	nibble_trans=0;
	while (trans_table[nibble_trans]!=nibble_in)
		nibble_trans++;
	chksum=last_nibble^nibble_trans;
	/* put bytes back together */
	for(byte_count=0;byte_count<256;byte_count++)
	{
		if (byte_count<86)
			bytes[byte_count]=nibble_high[byte_count]|reverse_bits[(nibble_low[byte_count]&mask1)];
		else if (byte_count<172)
			bytes[byte_count]=nibble_high[byte_count]|reverse_bits[((nibble_low[byte_count-86]&mask2)>>2)];
		else
			bytes[byte_count]=nibble_high[byte_count]|reverse_bits[((nibble_low[byte_count-172]&mask3)>>4)];
	}
	fseek(outfile, (((long)track*16)+(long)interleave[sector])*256, SEEK_SET);
	fwrite(bytes, 256, 1, outfile);
  };
  fclose(outfile);
  fclose(infile);
  
  printf("Volume: %d\n", volume);
  sprintf(command, "Set Nib2Dsk$Volume %d", volume);
  system(command);

  return(0);
}
