git » fp-git.git » master » tree

[master] / PR / src / lib / actions / classify.c

/*  Princed V3 - Prince of Persia Level Editor for PC Version
    Copyright (C) 2003 Princed Development Team

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    The authors of this program may be contacted at http://forum.princed.com.ar
*/

/*
classify.c: Princed Resources : File classify routines
����������
 Copyright 2003 Princed Development Team
  Created: 24 Aug 2003

  Author: Enrique Calot <ecalot.cod@princed.com.ar>
  Version: 1.01 (2003-Oct-23)

 Note:
  DO NOT remove this copyright notice
*/

#include "autodetect.h"
#include "classify.h"
#include "common.h"
#include "dat.h"
#include "disk.h" /* mLoadFileArray */
#include "memory.h"
#include <stdio.h>

/***************************************************************\
|                    Get the type of a DAT file                 |
\***************************************************************/

#define READ_ERROR {mReadCloseDatFile();return PR_RESULT_F_INVALID_DAT;}

int prClassifyDat(const char* vFiledat) {
	int                indexNumber;
	tResourceType      type=eResTypeOtherBinary;
	unsigned short int numberOfItems;
	tPopVersion        popVersion;
	tResource          res;
	int                error;

	/* Initialize abstract variables to read this new DAT file */
	if ((error=mReadBeginDatFile(&numberOfItems,vFiledat))) return error;

	popVersion=mReadGetVersion();

	/* main loop */
	for (indexNumber=0;(indexNumber<numberOfItems)&&(type==eResTypeOtherBinary);indexNumber++) {
		int ok;
		ok=mReadFileInDatFile(&res,indexNumber);
		if (ok==PR_RESULT_F_INDEX_NOT_FOUND) READ_ERROR; /* Read error */
		/*if (ok==PR_RESULT_CHECKSUM_ERROR) fprintf(outputStream,"Warning: Checksum error\n"); Warning TODO: add an output for the checksum warning */
		if (res.id.value==0xFFFF) continue; /* Tammo Jan Bug fix */
		type=verifyHeader(res.content);
	}

	mReadCloseDatFile();
	return (popVersion==pop1)?type:(type+10);
}

typedef struct {
	unsigned long int checkSum;
	long size;
}tExeClassification;

int prClassify(const char* fileName) {
	int result;

	/* 1) check if it is a DAT file */
	result=prClassifyDat(fileName);

	if (!result) { /* it's not a DAT file*/
		/*long int fileContent.size;
		unsigned char* fileContent.data;*/
		tBinary fileContent;

		/* let's get it's content and see what it is */
		fileContent=mLoadFileArray(fileName);
		if (fileContent.size<=0) return fileContent.size;

		/* 2) let's compare the size with a .SAV size */
		if (fileContent.size==8) {
			int framesLeft;
			/* check that the frames (seconds/12) are in the range [0*12,60*12) */
			framesLeft=fileContent.data[2]|fileContent.data[3]<<8;
			if (framesLeft<60*12)
				result=30; /* SAV file */
		}

		/* 3) let's compare the size with a .HOF size */
		if (fileContent.size==176) {
			int records;
			/* check that the number of stored records are 6 or less */
			records=fileContent.data[0]|fileContent.data[1]<<8;
			if (records<=6) {
				result=31; /* HOF file */
				while (records) {
					int framesLeft;
					/* wrong seconds left format for this record will invalidate the whole file */
					framesLeft=fileContent.data[29*records-2]|fileContent.data[29*records-1]<<8;
					if (framesLeft>=60*12) result=0;
					records--;
				}
			}
		}

		/* 4) as the last resource, check if it is an EXE file */
		if (!result && fileContent.size>2 && fileContent.data[0]=='M' && fileContent.data[1]=='Z') {
			static tExeClassification x[]={
				/* install.pdm         : 41 */ {717181985,4233},
				/* prince.exe v1.0 THG : 42 */ {622612442,123335},
				{0,0}
			};
			unsigned long checkSum=0;
			int i;
			result=40; /* generic EXE file */
			/* Now I'll try to recognize some known EXE files */
			/* calculate checksum */
			for (i=0;i<fileContent.size;i++) {
				checkSum+=fileContent.data[i]<<((3-(i%4))*8);
			}
#ifdef DEBUG_GETCHECKSUM
			printf("{%lu,%ld},\n",checkSum,fileContent.size);
#endif

			/* compare checksum*/
			for (i=0;x[i].size;i++)
				if ((x[i].checkSum==checkSum) && (x[i].size==fileContent.size)) {
					result=41+i;
					break;
				}
		}

		free(fileContent.data);
	}

	return result;
}