/*
 * Utility to extract stuff from ADFS images
 */

#include <stdio.h>
#include <string.h>

typedef unsigned char byte;
typedef unsigned int dword;

int map;

#pragma pack(1)
struct threebyte
{
	byte lo, mid, hi;
};

#define DECODE_3B(x) (x.lo | (x.mid << 8) | (x.hi << 16))

struct fsmap
{
	struct threebyte addr[82];
	byte reserved[6];
	struct threebyte total_sect;
	byte checksum_sect0;
	
	struct threebyte length[82];
	byte reserved_1[5];
	byte discid[2];
	byte bootopt;
	byte end_fslist;
	byte checksum_sect1;
};

struct adfs_dir
{
	byte msn;
	byte hugo[4];
	struct entry
	{
		byte name_access[10];
		dword load;
		dword exec;
		dword len;
		struct threebyte start_sect;
		byte sequence;
	} entries[47];
	byte zero;
	byte filename[10];
	struct threebyte parent_ptr;
	byte dirtitle[19];
	byte reserved[14];
	byte msn_copy;
	byte hugo_2[4];
	byte zero_2;
};
#pragma pack()

FILE *f;
struct fsmap fsm;

void read_sectors (void *ptr, int nsectors, int first)
{
	int trk;
	int i;
	int sect;
	int lsect;
	
	if (map)
	{
		for (i = 0; i < nsectors; i++)
		{
			trk = (first+i)/10;
			sect = (first+i)%10;
			if (trk & 1)
				lsect = ((80+(trk>>1))*10)+sect;
			else
				lsect = ((trk>>1)*10)+sect;
			printf ("trk%d sect%d --> lsect%d\n", trk, sect, lsect);
			fseek (f, lsect*256, SEEK_SET);
			fread (ptr + (i*256), 256, 1, f);
		}
	}
	else
	{
		fseek (f, first*256, SEEK_SET);
		fread (ptr, nsectors, 256, f);
	}
}

void do_dir (int sector)
{
	struct adfs_dir dir;
	char namebuf[20], namebuf2[20];
	int i, j;
	
	read_sectors (&dir, 5, sector);
	
	if (strncmp (dir.hugo, "Hugo", 4))
		printf ("Warning: first hugo mismatch\n");
	if (strncmp (dir.hugo_2, "Hugo", 4))
		printf ("Warning: second hugo mismatch\n");
	
	for (i = 0; i < 10; i++)
	{
		namebuf[i] = dir.filename[i] & 0x7f;
		if (namebuf[i] == 0xd)
			namebuf[i] = 0;
	}
	for (i = 0; i < 19; i++)
	{
		namebuf2[i] = dir.dirtitle[i] & 0x7f;
		if (namebuf2[i] == 0xd)
			namebuf2[i] = 0;
	}
	namebuf[19] = 0;
	
	printf ("\n%s '%s' (%d %d)\n", namebuf, namebuf2,
		dir.msn, dir.msn_copy);
	
	for (i = 0; i < 47; i++)
	{
		if (dir.entries[i].name_access[0] == 0)
			break;
		for (j = 0; j < 10; j++)
		{
			namebuf[j] = dir.entries[i].name_access[j] & 0x7f;
			if (namebuf[j] == 0xd)
				namebuf[j] = 0;
		}
		namebuf[10] = 0;
		printf ("%.10s		%c %c %c %c	%08x %08x %d\n",
			namebuf,
			dir.entries[i].name_access[0] & 0x80 ? 'R' : 'r',
			dir.entries[i].name_access[1] & 0x80 ? 'W' : 'w',
			dir.entries[i].name_access[2] & 0x80 ? 'L' : 'l',
			dir.entries[i].name_access[3] & 0x80 ? 'D' : 'd',
			dir.entries[i].load,
			dir.entries[i].exec,
			dir.entries[i].len);
		if (dir.entries[i].name_access[3] & 0x80)
			do_dir (DECODE_3B (dir.entries[i].start_sect));
	}
	printf ("\n");
}

int main(int argc, char *argv[])
{
	printf ("%d %d\n", sizeof (struct fsmap),
		sizeof (struct adfs_dir));
	
	if (argc >= 3)
		map = 1;
	else
		map = 0;
	
	f = fopen (argv[1], "r");
	fread (&fsm, sizeof (fsm), 1, f);
	
	do_dir (2);
}

/* End of file. */
