/* verify.c V1.1
 *
 * Perform the same action as $verify on Infocom story files.
 *
 * Usage: $verify story-file-name
 *
 * Mark Howell 11 August 1992 howell_ma@movies.enet.dec.com
 *
 * History:
 *    Make endian neutral
 */

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

#define H_TYPE 0
#define H_CONFIG 1
#define H_VERSION 2
#define H_RELEASE_DATE 18
#define H_FILE_SIZE 26
#define H_CHECKSUM 28
#define H_SIZE 64

#define PAGE_SIZE 512

#if !defined(EXIT_SUCCESS)
#define EXIT_SUCCESS 0
#endif

#if !defined(EXIT_FAILURE)
#define EXIT_FAILURE 1
#endif

#define get_byte(offset) ((unsigned char) header[offset])
#define get_word(offset) ((unsigned short) (((unsigned short) header[offset] << 8) + (unsigned short) header[offset + 1]))

#ifdef __STDC__
int main (int argc, char *argv[])
#else
int main (argc, argv)
int argc;
char *argv[];
#endif
{
    FILE *fp;
    unsigned char header[H_SIZE], buffer[PAGE_SIZE];
    unsigned long file_size, size;
    unsigned short checksum, calculated_checksum = 0;
    int i;

    if (argc != 2) {
        fprintf (stderr, "Usage: %s story-file-name\n", argv[0]);
	exit (EXIT_FAILURE);
    }
    if ((fp = fopen (argv[1], "rb")) == NULL) {
        perror ("fopen");
	exit (EXIT_FAILURE);
    }
    if (fread (header, H_SIZE, 1, fp) != 1) {
        perror ("fread(story header)");
	exit (EXIT_FAILURE);
    }
    printf ("Story type = %d, version = %d, release date = %c%c/%c%c/%c%c, configuration byte = %02x\n",
        (int) get_byte (H_TYPE),
        (int) get_word (H_VERSION),
        (char) get_byte (H_RELEASE_DATE + 4), (char) get_byte (H_RELEASE_DATE + 5),
        (char) get_byte (H_RELEASE_DATE + 2), (char) get_byte (H_RELEASE_DATE + 3),
        (char) get_byte (H_RELEASE_DATE + 0), (char) get_byte (H_RELEASE_DATE + 1),
        (int) get_byte (H_CONFIG));

    checksum = (unsigned short) get_word (H_CHECKSUM);
    if (checksum) {
        file_size = (unsigned long) get_word (H_FILE_SIZE);
        switch ((int) get_byte (H_TYPE)) {
            case 6: file_size *= 2;
            case 5:
            case 4: file_size *= 2;
            case 3: file_size *= 2;
            default: break;
        }

        file_size -= H_SIZE;
        size = PAGE_SIZE - H_SIZE;
        while (file_size) {
            if (fread (buffer, (size_t) size, 1, fp) != 1) {
                perror ("fread(story data)");
                exit (EXIT_FAILURE);
            }
            for (i = 0; i < size; i++)
                calculated_checksum += buffer[i];
            file_size -= size;
            if (file_size >= PAGE_SIZE)
                size = PAGE_SIZE;
            else
                size = file_size;
        }

        if (checksum == calculated_checksum) {
            printf ("Story file verified OK\n");
        } else {
            fprintf (stderr,
                     "Story file verify failed! actual checksum = %x, required checksum = %x\n",
                     (int) calculated_checksum,
                     (int) checksum);
            exit (1);
        }
    } else
        printf ("Story file has no checksum!\n");

    fclose (fp);
    exit (EXIT_SUCCESS);
    return (0);

}/* $verify */
