/* CreatePPF.c (Playstation Patch File) for Playstation Images.
 *
 * Modifications for Playstation Images by Icarus / Paradox 1999
 * Original APS Code by Silo / BlackBag 1998
 *
 * Version 1.0 990704
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifndef TRUE
#define TRUE  1
#define FALSE !TRUE
#endif

#define MESSAGE   "\nMakePPF Version 1.0 / Build 990704\n"
#define COPYRIGHT "By Icarus/Paradox 1999 (More Infos at: http://www.paradogs.com)\nTaken from APS coded by Silo/Blackbag\n\n"

#define BUFFERSIZE 255

char Magic[]="PPF10";
#define MagicLength 5

#define DESCRIPTION_LEN 50

#define ENCODINGMETHOD 0 /* Encodemethod for version 1.0 */

unsigned char EncodingMethod=ENCODINGMETHOD;

FILE	*APSFile;
FILE	*ORGFile;
FILE	*NEWFile;
int		Quiet=FALSE;
int		ChangeFound;

void
syntax (void)
{
	printf ("%s", MESSAGE);
	printf ("%s", COPYRIGHT);
	printf ("MakePPF <options> <Original File> <Modified File> <Output PPF File>\n");
	printf (" -d %c<Image Title>%c : Description\n", 34, 34);
	printf (" -q                 : Quiet Mode\n");
	fflush (stdout);
}

void
WriteStdHeader (char *Desc)
{
	char Description[DESCRIPTION_LEN];

	fwrite (Magic,1,MagicLength,APSFile);
	fwrite (&EncodingMethod,sizeof (EncodingMethod),1,APSFile);

	memset (Description,' ',DESCRIPTION_LEN);
	strcpy (Description,Desc);
	Description[strlen(Desc)]=' ';

	fwrite (Description,1,DESCRIPTION_LEN,APSFile);

}


int GetImgSize (char *Filename1,char *Filename2)
{

	FILE	*ORGFile2;
	FILE	*NEWFile2;

	long NEWSize,ORGSize;

	ORGFile2 = fopen (Filename1,"rb");
	NEWFile2 = fopen (Filename2,"rb");


	fseek (NEWFile2,0,SEEK_END);
	fseek (ORGFile2,0,SEEK_END);

	NEWSize = ftell (NEWFile2);
	ORGSize = ftell (ORGFile2);

	if (ORGSize != NEWSize)
	{
		if (!Quiet)
		{
			printf ("Images doesnt match (length)!!\n");
			fflush (stdout);
		}
		return (FALSE);
		
	}
	return (TRUE);

	fclose (NEWFile2);
	fclose (ORGFile2);

}


void
WritePatch ()
{
	long ORGReadLen;
	long NEWReadLen;
	int Finished=FALSE;
	unsigned char ORGBuffer[BUFFERSIZE];
	unsigned char NEWBuffer[BUFFERSIZE];
	long FilePos;
	int i;
	long ChangedStart=0;
	long ChangedOffset=0;
	int ChangedLen=0;
	int State;

	fseek (ORGFile,0,SEEK_SET);
	fseek (NEWFile,0,SEEK_SET);

	FilePos = 0;

	while (!Finished)
	{
		ORGReadLen = fread (ORGBuffer,1,BUFFERSIZE,ORGFile);
		NEWReadLen = fread (NEWBuffer,1,BUFFERSIZE,NEWFile);

		if (ORGReadLen != NEWReadLen)
		{
			int a;

			for (a=ORGReadLen;a<NEWReadLen;a++) ORGBuffer[a]=0;
		}

		i=0;
		State=0;

		if (NEWReadLen != 0)
		{
		while (i<NEWReadLen)
		{
			switch (State)
			{
			case 0:
				if (NEWBuffer[i] != ORGBuffer[i])
				{
					State=1;
					ChangedStart=FilePos+i;
					ChangedOffset=i;
					ChangedLen=1;
					ChangeFound=TRUE;
				}
				i++;
				break;
			case 1:
				if (NEWBuffer[i] != ORGBuffer[i])
				{
					ChangedLen++;
					i++;
				}
				else
					State=2;
				break;
			case 2:
				fwrite (&ChangedStart,sizeof (ChangedStart),1,APSFile);
				fputc  ((ChangedLen&0xff),APSFile);
				fwrite (NEWBuffer+(ChangedOffset),1,ChangedLen,APSFile);
				State=0;
				break;
			}
		}
		}

		if (State!=0)
		{
			if (ChangedLen==0) ChangedLen=255;
			fwrite (&ChangedStart,sizeof (ChangedStart),1,APSFile);
			fputc ((ChangedLen&0xff),APSFile);
			fwrite (NEWBuffer+(ChangedOffset),1,ChangedLen,APSFile);
		}

		if (NEWReadLen==0) Finished=TRUE;
		FilePos+=NEWReadLen;
	}
}


int main (int argc, char *argv[]) {
	int		Result;
	char	File1[256];
	char	File2[256];
	char	OutFile[256];
	char	Description[81];
	int     i;
	int     mode = 0;

	ChangeFound = FALSE;

	Description[0]=0;


	if (argc < 4) {
		syntax();
		return (1);
	}

	for(i=1; i<argc;i++) {

	 switch(argv[i][0]) {
	   case '-': switch(argv[i][1]) {
					case 'd': strcpy(Description,argv[i+1]);
							  i++;
							break;
					case 'q': Quiet=TRUE;
							break;
					default : printf("Unknown Option: %c\n",argv[i][1]);
							  syntax();
							  return(1);
				 }
				 break;
	   default : switch(mode) {
					case 0: strcpy(File1,argv[i]);
							mode++;
						  break;
					case 1: strcpy(File2,argv[i]);
							mode++;
						  break;
					case 2:	strcpy(OutFile,argv[i]);
							mode++;
						  break;
					default : printf("Too much Options!\n");
							  syntax();
							  return(1);
				 }
	  }
	 }

	if (!GetImgSize (File1,File2)) return(1);

	APSFile = fopen (OutFile,"wb");
	ORGFile = fopen (File1,"rb");
	NEWFile = fopen (File2,"rb");

	

	if (!Quiet)
	{
		printf ("%s", MESSAGE);
		printf ("%s", COPYRIGHT);
		printf ("Writing PPF Header...");
		fflush (stdout);
	}

	WriteStdHeader (Description);

	if (!Quiet) { printf ("Done\nComparing files: Finding Changes..."); fflush (stdout); }

	WritePatch ();

	if (!Quiet) { printf ("Done\n"); fflush (stdout); }

	fclose (NEWFile);
	fclose (ORGFile);
	fclose (APSFile);


	if (!Quiet && !ChangeFound)
	{
		printf ("No Changes Found\n");
		fflush (stdout);
		unlink (OutFile);
	}

	return (0);
}
