/* converts a raw disk image file into a nibble disk image */
/* Copyright (c) 2001 by Christopher Bachmann (c-bachmann@northwestern.edu)

   Feel free to redistribute it, port it, copy it around, but if you
   change it, improve it, base something else on it, etc.  Please
   let me know, so that I can keep this up to date, and incorporate
   the best of everything.

*/

#include <stdio.h>

static long int start[35];		/* start positions for each track */
static long int length[35];		/* length of each track */

/* open the file for reading as binary */
FILE *openfile(char *filename) {
  FILE *fileno;

  fileno = fopen(filename, "rb");
  return fileno;
}

/* read in information from the header */
void readheader (FILE *fileid) {
  int i;

  fseek (fileid, (long) 0x2b0, 0);		/* point to first data field */
  for (i=0; i < 35; i++) {
    start[i] = 0;
    start[i] = ((((long) getc (fileid)) & 0xff) << 16) | start[i];
    start[i] = ((((long) getc (fileid)) & 0xff) << 8) | start[i];
    start[i] = ((((long) getc (fileid)) & 0xff)) | start[i];
    start[i] = ((((long) getc (fileid)) & 0xff) << 24) | start[i];
/*    start[i] = ((getc(fileid) & 0xff) << 16) | ((getc(fileid) & 0xff) << 8) |
      ((getc(fileid) & 0xff)) | ((getc(fileid) & 0xff) << 24); */
/*    printf ("%x ",start[i]); */
  }
/*  printf ("\n"); */
  fseek (fileid, (long) 0x440, 0);
  for (i=0; i < 35; i++) {
    length[i] = 0;
    length[i] = ((((long) getc (fileid)) & 0xff)) | length[i];
    length[i] = ((((long) getc (fileid)) & 0xff) << 8) | length[i];
    length[i] = ((((long) getc (fileid)) & 0xff) << 16) | length[i];
    length[i] = ((((long) getc (fileid)) & 0xff) << 24) | length[i];
/*    length[i] = ((getc(fileid) & 0xff)) | ((getc(fileid) & 0xff) << 8) |
      ((getc(fileid) & 0xff) << 16) | ((getc(fileid) & 0xff) << 24); */
/*    printf ("%x ",length[i]); */
  }
/*  printf ("\n"); */
  for (i=0; i < 35; i++) {
    printf ("%x: %x %x\n",i,start[i],length[i]);
  }
}

/* print the short as 4 hex digits, with a line number */
void printbyte (short number) {
  int high,low;
  high = (number >> 8) & 0xff;
  low = number & 0xff;
/*
  if (high < 16)
    printf ("0%x",high);
  else
    printf ("%x",high);
*/
  if (low < 16)
    printf ("0%x ",low);
  else
    printf ("%x ",low);
}

/* write out a raw track */
/* Note: we can't just copy the bytes, because the option
   board includes the sync bits.  The nibble format includes a
   lot of information, but drops them for some reason */
write_track(FILE *fileid,FILE *fileno) {
  int address[14];      /* address information */
  int done = 0;         /* flag */
  int buffer = 0xffff;  /* bit buffer (like apple latch) */
  int input_byte;       /* input byte */
  int input_bit;        /* current bit */
  int bit_count;        /* number of bits shifted in so far */
  int index=0;          /* index into address array */

  while (!done) {
    input_byte = getc(fileid);
    if (input_byte == EOF) {    /* check for end of file ?? */
      done = 1;
    } else {
      for (input_bit = 0; input_bit < 8; input_bit++) {
        /* get current bit */
        buffer = ((buffer << 1) & 0xfffe) | ((input_byte >> 7) & 1);
        input_byte = input_byte << 1;

        /* update count */
        bit_count++;

        /* test for valid data */
        if ((bit_count >= 8) && ((buffer & 0x0080) != 0)) {
/*          printbyte (buffer); */
          putc(buffer & 0xff,fileno);
          index++;

          /* this is clumsy, as we might write a partial sector at the end */
          /* however, it's better than nothing, and more accurate */
          if (index==6656) { done = 1; }

          bit_count = 0;                /* reset bit counter */
          buffer = 0xffff;        /*  and buffer */
        }       /* end valid data */
      }         /* end current byte */
    }           /* end EOF test */
  }             /* end while loop */
}


/* process the file as if we are a real apple reading the disk */
void process(FILE *fileid, char *filename) {
  FILE *fileno;
  int trk;		/* track */
  int j;		/* byte */

  printf ("Processing ");
  fileno = fopen(filename, "wb");
  for (trk=0; trk < 35; trk++) {
/*    printf ("Track %d\n",trk); */
    printf (".");
    fseek (fileid, start[trk], 0);	/* seek to start of track */
    /* write out the track */
    write_track(fileid,fileno);
  }
  fclose (fileno);
  printf ("Done\n");
}

/* close the file after reading */
void closefile(FILE *fileid) {
  fclose (fileid);
}

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

  if (argc < 3) {
    printf ("img2nib <image file> <outputfile>\n");
  } else {
    fileid = openfile(argv[1]);
    if (fileid == NULL) {
      printf ("Filename not found\n");
    } else {
      readheader (fileid);
      process (fileid, argv[2]);
      closefile(fileid);
    }
  }
  return(0);
}
