/*
 * The Lurking Horror update
 *
 *      This is a small utility to update the Infocom game The Lurking
 *      Horror release 203 to release 221.  Written 1995 by Stefan
 *      Jokisch.
 *
 * ---------------------------------------------------------------------------
 *
 * Sherlock update
 *
 *      This is a small utility to update the Infocom game Sherlock from
 *      release 21 to release 26.  Written 1995 by Stefan Jokisch.
 *
 * ---------------------------------------------------------------------------
 *
 *      Modified & Combined 1997 by Musus Umbra to allow use as functions
 *      from some calling program.
 *      Error strings are for my RISC OS vsersion in particular
 *
 */

#include <stdio.h>



/* new vars added by MU */
char *upd8_err = "<none>";
static char temp_file[L_tmpnam];		/* temp'ry filename */

/* The errer text */
static char *err_open_story = "uerr.opens";
static char *err_open_cnv   = "uerr.openc";
static char *err_open_temp  = "uerr.opent";
static char *err_read_story = "uerr.reads";
static char *err_read_cnv   = "uerr.readc";
static char *err_write_temp = "uerr.writet";
static char *err_version    = "uerr.version";
static char *err_checksum   = "uerr.checksum";


char *update_lh( char *story_file, char *cnv_file )
{
	FILE *source = NULL;
	FILE *conv = NULL;
	FILE *dest = NULL;
	long source_file_size = 0x7fffffff;
	long dest_file_size = 0x7fffffff;
	unsigned short source_checksum = 0;	/* 'short's added by MU */
	unsigned short dest_checksum = 0;
	unsigned short source_sum = 0;
	unsigned short dest_sum = 0;
	int byte1 = 0;
	int byte2 = 0;
	int byte3 = 0;
	long count = 0;

	tmpnam(temp_file);		/* generate a temp-file name */

	/*
	 * Open all files.
	 */

	if ((source = fopen ( story_file, "rb")) == NULL)
	{
		upd8_err = err_open_story;
		goto emergency;
	}

	if ((conv = fopen ( cnv_file, "rb")) == NULL)
	{
		upd8_err = err_open_cnv;
		goto emergency;
	}

	if ((dest = fopen ( temp_file, "wb")) == NULL)
	{
		upd8_err = err_open_temp;
		goto emergency;
	}

	/*
	 * Loop until the destination file is complete.
	 */

	while (count < dest_file_size)
	{
		/* Read the data file. */
		byte1 = (count >= source_file_size) ? 0 : fgetc (source);

		if (byte1 == EOF)
		{
			upd8_err = err_read_story;
			goto emergency;
		}

		/* Read the conversion file. */

		byte2 = fgetc (conv);

		if (byte2 == EOF)
		{
			upd8_err = err_read_cnv;
			goto emergency;
		}

		/* Calculate the destination file using EXOR. */

		byte3 = byte1 ^ byte2;

		if (count == 3 && byte1 != 203)
		{
			upd8_err = err_version;
			goto emergency;
		}

		/* Read the file size entries. */

		if (count == 26)
		{
			source_file_size = (long) byte1 << 9;
			dest_file_size = (long) byte3 << 9;
		}

		if (count == 27)
		{
			source_file_size |= (long) byte1 << 1;
			dest_file_size |= (long) byte3 << 1;
		}

		/* Read the checksum entries. */

		if (count == 28)
		{
			source_checksum = byte1 << 8;
			dest_checksum = byte3 << 8;
		}

		if (count == 29)
		{
			source_checksum |= byte1;
			dest_checksum |= byte3;
		}

		/* Sum up all bytes starting at $40. */

		if (count >= 64)
		{
			source_sum += byte1;
			dest_sum += byte3;
		}

		/* Write the destination file. */

		if (fputc (byte3, dest) == EOF)
		{
			upd8_err = err_write_temp;
			goto emergency;
		}

		count++;
	}

	/*
	 * Validate checksums.
	 */

	if (source_sum != source_checksum || dest_sum != dest_checksum)
	{
		upd8_err = err_checksum;
		goto emergency;
	}

	/*
	 * Close all files.
	 */

	fclose (source);
	fclose (conv);
	fclose (dest);

	return (temp_file);


emergency:

	/*
	 * Panic! Close all open files and exit.
	 */

	if (source != NULL) { fclose (source); }
	if (conv != NULL) { fclose (conv); }
	if (dest != NULL) { fclose (dest); }
	if (dest != NULL) { remove (temp_file); }

	return NULL;
}








char *update_sh( char *story_file, char *cnv_file )
{
	FILE *source = NULL;
	FILE *conv = NULL;
	FILE *dest = NULL;
	long source_file_size = 0x7fffffff;
	long dest_file_size = 0x7fffffff;
	unsigned short source_checksum = 0;	/* 'short's added by MU */
	unsigned short dest_checksum = 0;
	unsigned short source_sum = 0;
	unsigned short dest_sum = 0;
	int byte1 = 0;
	int byte2 = 0;
	int byte3 = 0;
	long count = 0;

	tmpnam(temp_file);		/* generate a temp-file name */

	/*
	 * Open all files.
	 */

	if ((source = fopen ( story_file, "rb")) == NULL)
	{
		upd8_err = err_open_story;
		goto emergency;
	}

	if ((conv = fopen ( cnv_file, "rb")) == NULL)
	{
		upd8_err = err_open_cnv;
		goto emergency;
	}

	if ((dest = fopen ( temp_file, "wb")) == NULL)
	{
		upd8_err = err_open_temp;
		goto emergency;
	}

	while (count < dest_file_size)
	{
		/* Read the data file. */
		byte1 = (count >= source_file_size) ? 0 : fgetc (source);

		if (byte1 == EOF)
		{
			upd8_err = err_read_story;
			goto emergency;
		}

		/* Read the conversion file. */

		byte2 = fgetc (conv);

		if (byte2 == EOF) {
			upd8_err = err_read_cnv;
			goto emergency;
		}

		/* Calculate the destination file using EXOR. */

		byte3 = byte1 ^ byte2;

		if (count == 3 && byte1 != 21)
		{
			upd8_err = err_version;
			goto emergency;
		}

		/* Read the file size entries. */

		if (count == 26)
		{
			source_file_size = (long) byte1 << 10;
			dest_file_size = (long) byte3 << 10;
		}

		if (count == 27)
		{
			source_file_size |= (long)byte1 << 2;
			dest_file_size |= (long)byte3 << 2;
		}

		/* Read the checksum entries. */

		if (count == 28)
		{
			source_checksum = byte1 << 8;
			dest_checksum = byte3 << 8;
		}

		if (count == 29)
		{
			source_checksum |= byte1;
			dest_checksum |= byte3;
		}

		/* Sum up all bytes starting at $40. */

		if (count >= 64)
		{
			source_sum += byte1;
			dest_sum += byte3;
		}

		/* Write the destination file. */

		if (fputc (byte3, dest) == EOF)
		{
			upd8_err = err_write_temp;
			goto emergency;
		}

		count++;
	}

	/*
	 * Validate checksums.
	 */

	if (source_sum != source_checksum || dest_sum != dest_checksum)
	{
		upd8_err = err_checksum;
		goto emergency;
	}

	/*
	 * Close all files.
	 */

	fclose (source);
	fclose (conv);
	fclose (dest);

	return temp_file;


emergency:

	/*
	 * Panic! Close all open files and exit.
	 */

	if (source != NULL) { fclose (source); }
	if (conv != NULL) { fclose (conv); }
	if (dest != NULL) { fclose (dest); }
	if (dest != NULL) { remove (temp_file); }

	return NULL;
}


