/* inforead.c V1.0
 *
 * Read Infocom data files from an IBM bootable diskette
 *
 * Usage: inforead datafile-name [start-track [drive#]]
 *
 *    datafile-name is required
 *    start-track is optional (default is 6, should be OK)
 *    drive# is optional (default is 0 for a:, use 1 for b:)
 *
 * The data file is extracted starting at track 6 and continues
 * for the length of the data area. The data file that is created
 * is the correct length and is verified using the checksum in the
 * data area.
 *
 * This only works for type 3 games on IBM 5 1/4" diskettes. I
 * believe that all of the bootable Infocom games were type 3.
 *
 * Once you have extracted the datafile use the /G switch with
 * a type 3 Infocom interpreter, for example:
 *
 * C> zork1/ginfidel.dat
 *
 * NB. no space between the /g and the data file name and nothing
 * after the data file name.
 *
 * This C program was written with MicroSoft C specifically for the
 * IBM PC.
 *
 * I also have a CBM 64/128 version of this program for Commodore disks.
 *
 * Mark Howell 20 January 1992 howell_ma@movies.enet.dec.com
 *
 */

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

#define TRACK_SIZE 4096

int read_track (int drive, int track, unsigned char *tp);

int main (int argc, char *argv[])
{
    int track = 6;
    int drive = 0;
    FILE *fp;
    unsigned char *tp;
    int i, j, size, status;
    unsigned long int glength;
    unsigned short gchksum, chksum = 0;

    if (argc >= 4)
        drive = atoi (argv[3]);
    if (drive < 0 || drive > 1) {
        fprintf (stderr, "invalid drive #%d\n", drive);
        exit (1);
    }
    if (argc >= 3)
        track = atoi (argv[2]);
    if (track < 0 || track > 39) {
        fprintf (stderr, "invalid track #%d\n", track);
        exit (1);
    }
    if (argc < 2) {
        fprintf (stderr, "usage: %s datafile-name [start track [drive]]\n",
                 argv[0]);
        exit (1);
    }

    if ((tp = (unsigned char *) malloc (TRACK_SIZE)) == NULL) {
        perror ("malloc");
        exit (1);
    }
    if ((fp = fopen (argv[1], "wb")) == NULL) {
        perror ("fopen");
        exit (1);
    }

    for (i = track; i < 40; i++) {
        if (status == read_track (drive, i, tp)) {
            fprintf (stderr, "error %d from drive #%d, track #%d\n",
                     status, drive, track);
            exit (1);
        }
        if (i == track) {
            glength = ((unsigned) tp[26] * 256) + tp[27];
            gchksum = ((unsigned) tp[28] * 256) + tp[29];
            glength = (glength * 2) - TRACK_SIZE;
            for (j = 64; j < TRACK_SIZE; j++)
                chksum += tp[j];
            if (fwrite (tp, TRACK_SIZE, 1, fp) != 1) {
                perror ("fwrite");
                exit (1);
            }
        } else {
            if (glength > TRACK_SIZE) {
                size = TRACK_SIZE;
                glength -= TRACK_SIZE;
            } else {
                size = (int) glength;
                i = 40;
            }
            for (j = 0; j < size; j++)
                chksum += tp[j];
            if (fwrite (tp, (size_t) size, 1, fp) != 1) {
                perror ("fwrite");
                exit (1);
            }
        }
    }

    if (gchksum == chksum)
        printf ("game copied OK\n");
    else
        fprintf (stderr, "game copy failed!\n");

    free (tp);
    fclose (fp);

    exit (0);

    return (0);

}/* main */

int read_track (int drive, int track, unsigned char *tp)
{
    struct diskinfo_t di;
    unsigned int status;
    int i;

    di.drive = drive;
    di.head = 0;
    di.track = track;
    di.sector = 1;
    di.nsectors = 8;
    di.buffer = (void far *) tp;

    for (i = 0; i < 3; i++) {
        status = _bios_disk (_DISK_READ, &di);
        if (status == 8)
            return (0);
        _bios_disk (_DISK_RESET, NULL);
    }

    return (status >> 8);

}/* read_track */
