git » fp-git.git » commit b409bc8

added resource handling directory

author ecalot
2004-06-12 02:48:12 UTC
committer ecalot
2004-06-12 02:48:12 UTC
parent 538204ad507c53074e1489fc4750b4fa8de739d5

added resource handling directory

FP/src/res/dat.c +249 -0
FP/src/res/disk.c +457 -0
FP/src/res/resources.c +186 -0

diff --git a/FP/src/res/dat.c b/FP/src/res/dat.c
new file mode 100644
index 0000000..070ba99
--- /dev/null
+++ b/FP/src/res/dat.c
@@ -0,0 +1,249 @@
+/*  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
+*/
+
+/*
+dat.c: Princed Resources : DAT library
+\xaf\xaf\xaf\xaf\xaf
+ Copyright 2004 Princed Development Team
+  Created: 15 Mar 2004
+
+  Author: Enrique Calot <ecalot.cod@princed.com.ar>
+  Version: 1.00 (2004-Mar-15)
+
+ Note:
+  DO NOT remove this copyright notice
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include "pr.h"
+
+#include "disk.h"
+#include "dat.h"
+
+/***************************************************************\
+|                     DAT reading primitives                    |
+\***************************************************************/
+
+#ifdef PR_DAT_INCLUDE_DATREAD
+
+char               recordSize;
+int                ofk=0;
+int                pop1;
+unsigned char*     indexPointer;
+unsigned long  int indexOffset;
+unsigned long  int offset;
+unsigned short int indexSize;
+unsigned char*     readDatFile;
+int                readDatFileSize;
+
+void mReadCloseDatFile() {
+	free(readDatFile);
+}
+
+int mReadBeginDatFile(unsigned short int *numberOfItems,const char* vFiledat){
+	/*
+		Return Values:
+			0 Wrong Format or file not found
+			1 Ok
+	*/
+
+	int ok;
+	unsigned char* readDatFilePoint;
+
+	/* Open file */
+	readDatFileSize=mLoadFileArray(vFiledat,&readDatFile);
+	if (!readDatFileSize) return 0;
+	if (readDatFileSize<=6) {free(readDatFile);return 0;}
+
+	readDatFilePoint=readDatFile;
+
+	/* verify dat format */
+	indexOffset=array2long(readDatFilePoint);
+	readDatFilePoint+=4;
+	indexSize=array2short(readDatFilePoint);
+
+	if ((indexOffset>readDatFileSize)&&((indexOffset+indexSize)!=readDatFileSize)) {
+		free(readDatFile);
+		return 0; /* this is not a valid prince dat file */
+	}
+
+	indexPointer=readDatFile+indexOffset;
+	*numberOfItems=array2short(indexPointer);
+	indexPointer+=2;
+	pop1=(((*numberOfItems)*8+2)==indexSize);
+
+	if (!pop1) { /* verify if pop2 */
+		ofk=(*numberOfItems)*6+2+((*numberOfItems)-2)*13;
+		(*numberOfItems)=((indexSize-6-((*numberOfItems)*6)-(((*numberOfItems)-2)*13))/11);
+	} else {
+		ofk=0;
+	}
+	recordSize=pop1?8:11;
+
+	return 1;
+}
+
+int mReadFileInDatFile(int k,unsigned char* *data,unsigned long  int *size) {
+	int ok=1; /* TODO: rename mRead* for mRead* and mWrite for mWrite */
+	unsigned short int id;
+
+	/* for each archived file the index is read */
+	id=    array2short(indexPointer+ofk+k*recordSize);//(indexPointer[ofk+k*recordSize])+(indexPointer[ofk+k*recordSize+1]<<8);
+	printf("a ver: %d %d\n",id,(indexPointer[ofk+k*recordSize])+(indexPointer[ofk+k*recordSize+1]<<8));
+	
+	offset=array2long(indexPointer+ofk+k*recordSize+2);//indexPointer[ofk+k*recordSize+2])+(indexPointer[ofk+k*recordSize+3]<<8)+(indexPointer[ofk+k*recordSize+4]<<16)+(indexPointer[ofk+k*recordSize+5]<<24);
+	*size= array2short(indexPointer+ofk+k*recordSize+6);//indexPointer[ofk+k*recordSize+6])+(indexPointer[ofk+k*recordSize+7]<<8)+1;
+	if ((!pop1)&&(!(indexPointer[ofk+k*recordSize+8]==0x40)&&(!indexPointer[ofk+k*recordSize+9])&&(!indexPointer[ofk+k*recordSize+10]))) return -1;
+	if (offset+indexSize>readDatFileSize) return -1;
+	*data=readDatFile+offset;
+	return ok?id:-1;
+}
+
+int mReadInitResource(tResource** res,const unsigned char* data,long size) {
+	if ((*res)==NULL) {
+		(*res)=(tResource*)malloc(sizeof(tResource));
+		if ((*res)==NULL) return -1; /* no memory */
+		(*res)->path=NULL;
+		(*res)->palAux=NULL;
+		(*res)->desc=NULL;
+		(*res)->name=NULL;
+		(*res)->palette=0;
+		(*res)->number=0;
+		(*res)->size=(unsigned short int)size;
+		(*res)->offset=(unsigned short)offset; /* TODO delete this line */
+		(*res)->type=verifyHeader(data,(unsigned short int)size);
+	} else { /* If resource type is invalid or 0, the type will be decided by PR */
+		if (!((*res)->type)) (*res)->type=verifyHeader(data,(unsigned short int)size);
+	}
+	return 0;
+}
+#endif
+
+/***************************************************************\
+|                     DAT Writing primitives                    |
+\***************************************************************/
+
+#ifdef PR_DAT_INCLUDE_DATWRITE
+FILE* writeDatFile;
+
+int mWriteBeginDatFile(const char* vFile, int optionflag) {
+	/*
+		Opens safely a dat file for writing mode and
+		reserves space for the headers
+
+		Return Values:
+			 1 Ok
+			 0 File couldn't be open
+
+	*/
+	if (writeOpen(vFile,&writeDatFile,optionflag|backup_flag)) {
+		fseek(writeDatFile,6,SEEK_SET);
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
+void mWriteInitResource(tResource** res) {
+	if ((*res)==NULL) {
+		(*res)=(tResource*)malloc(sizeof(tResource));
+		(*res)->path=NULL;
+		(*res)->palAux=NULL;
+		(*res)->desc=NULL;
+		(*res)->name=NULL;
+	}
+	(*res)->offset=(unsigned long)ftell(writeDatFile);
+}
+
+void mWriteFileInDatFile(const unsigned char* data, int size) {
+	/*
+		Adds a data resource to a dat file keeping
+		abstractly the checksum ver	ifications
+	*/
+
+	/* Declare variables */
+	int            k        = size;
+	unsigned char  checksum = 0;
+	const unsigned char* dataAux  = data;
+
+	/* calculates the checksum */
+	while (k--) checksum+=*(dataAux++);
+	checksum=~checksum;
+
+	/* writes the checksum and the data content */
+	fwritechar(&checksum,writeDatFile);
+	fwrite(data,size,1,writeDatFile);
+}
+
+void mWriteFileInDatFileIgnoreChecksum(unsigned char* data, int size) {
+	fwrite(data,size,1,writeDatFile);
+}
+
+void mWriteCloseDatFile(tResource* r[],int dontSave,int optionflag, const char* backupExtension) {
+	/*
+		Closes a dat file filling the index and other structures
+	*/
+	unsigned short int id=1;
+	unsigned short int totalItems=0;
+	unsigned short int size2=2;
+	unsigned long  int size1=ftell(writeDatFile);
+
+	/* Write index */
+	fwriteshort(&totalItems,writeDatFile); /* Junk total items count to reserve 2 bytes */
+	for (;id!=MAX_RES_COUNT;id++) {
+		if (r[id]!=NULL) {
+			/* the file is in the archive, so i'll add it to the index */
+			totalItems++;
+			fwriteshort(&id,writeDatFile);
+			fwritelong(&(r[id]->offset),writeDatFile);
+			fwriteshort(&(r[id]->size),writeDatFile);
+		}
+	}
+	size2+=totalItems<<3;
+	fseek(writeDatFile,size1,SEEK_SET);
+	fwriteshort(&totalItems,writeDatFile); /* Definitive total items count */
+
+	/* Write first 6 bytes header */
+	fseek(writeDatFile,0,SEEK_SET);
+	fwritelong(&size1,writeDatFile);
+	fwriteshort(&size2,writeDatFile);
+
+	/* Closes the file and flushes the buffer */
+	writeClose(writeDatFile,dontSave,optionflag,backupExtension);
+}
+#endif
+
+/***************************************************************\
+|                       DAT R/W primitives                      |
+\***************************************************************/
+
+#ifdef PR_DAT_INCLUDE_DATREAD
+#ifdef PR_DAT_INCLUDE_DATWRITE
+int mRWBeginDatFile(const char* vFile, unsigned short int *numberOfItems, int optionflag) {
+	if (!mReadBeginDatFile(numberOfItems,vFile)) return -2;
+	if (!mWriteBeginDatFile(vFile,optionflag)) {
+		mReadCloseDatFile();
+		return -1;
+	}
+	return 0;
+}
+#endif
+#endif
diff --git a/FP/src/res/disk.c b/FP/src/res/disk.c
new file mode 100644
index 0000000..afb01d2
--- /dev/null
+++ b/FP/src/res/disk.c
@@ -0,0 +1,457 @@
+/*  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
+*/
+
+/*
+disk.c: Princed Resources : Disk Access & File handling functions
+\xaf\xaf\xaf\xaf\xaf\xaf
+ Copyright 2003 Princed Development Team
+  Created: 29 Oct 2003
+
+  Author: Enrique Calot <ecalot.cod@princed.com.ar>
+  Version: 1.00 (2003-Oct-29)
+
+  Modified by: Enrique Calot <ecalot.cod@princed.com.ar>
+  Version: 1.10 (2003-Dec-03)
+  Modified by: Santiago Zamora <drkzight@users.sourceforge.net>
+  Version: 1.20 (2004-Jan-06)
+
+ Note:
+  DO NOT remove this copyright notice
+*/
+
+/* Defines */
+#include "memory.h"
+#include <string.h>
+#include "pr.h"
+#include "disk.h"
+//#include "xmlparse.h" /* equalsIgnoreCase */
+#define IGNORERECURSIVEFUNCTIONS
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef UNIX
+	#define defmkdir(a) mkdir (a,(mode_t)0755)
+	#include <dirent.h>
+	#include <termios.h>
+	#include <unistd.h>
+	#include <fcntl.h>
+	#define osIndepGetCharacter() getchar()
+#else
+	#include <direct.h>
+	#include "direntwin.h"
+	#define defmkdir(a) mkdir (a)
+	#include <conio.h>
+	#define osIndepGetCharacter() getche()
+#endif
+
+extern FILE* outputStream;
+
+/***************************************************************\
+|              Disk Access & File handling functions            |
+\***************************************************************/
+
+/* Repair folders */
+const char *repairFolders(const char* a) {
+	int i,k;
+	static char result[MAX_FILENAME_SIZE];
+fld("rf1");
+
+	for (i=0,k=0;a[i]&&(k<MAX_FILENAME_SIZE);) {
+		if (isDirSep(a,i)) {
+			result[k]=DIR_SEPARATOR;
+			i++;
+			while (isDirSep(a,i)) i++;
+		} else {
+			result[k]=a[i];
+			i++;
+		}
+		k++;
+	}
+fld("rf2");
+	result[k]=0;
+fld("rf3");
+	return result;
+}
+
+
+/* Create base directory of a file */
+int makebase(const char* p) {
+	/*
+		Creates the base directory of the given file "p"
+		Returns 0 if created
+		Returns -1 if an error occurred
+
+		Note: if the base directory already exists it will return -1!
+	*/
+
+	/* Declare variables */
+	static char old[MAX_FILENAME_SIZE];
+	int i,a,equal=1;
+	int size;
+	char* aux;
+
+	/* Initialize variables */
+	size=(strlen(p)+1);
+	aux=(char*)malloc(size);
+
+	/* Make directories */
+	for (i=0;i<size;i++) {
+		aux[i]=0;
+		equal=equal&&(old[i]==p[i]);
+		if ((!equal)&&(p[i]==DIR_SEPARATOR)) a=defmkdir(aux);
+		old[i]=p[i];
+		aux[i]=p[i];
+	}
+
+	free(aux);
+	return a;
+}
+
+#if 0
+static tOpenFiles* openFilesList=NULL;
+
+void addFileToOpenFilesList(const char* fileName,int hasBackup) {
+	/*
+		Add a recently safe open file to the file pointer dynamic table
+		using the LIFO philosophy.
+	*/
+
+	tOpenFiles* newNode;
+
+	/* Create the new node and fill in the fields */
+	newNode=(tOpenFiles*)malloc(sizeof(tOpenFiles));
+	newNode->next=openFilesList;
+	newNode->name=strallocandcopy(fileName);
+	if (hasBackup) {
+		newNode->size=mLoadFileArray(fileName,&(newNode->content));
+	} else {
+		newNode->size=0;
+	}
+	openFilesList=newNode;
+}
+
+void addPointerToOpenFilesList(FILE* fp) { /* TODO: use a define */
+	openFilesList->file=fp;
+}
+
+int getFromOpenFilesList(FILE* fp, char** fileName, unsigned char** content, unsigned long int *size) {
+	tOpenFiles* currentNode;
+	tOpenFiles* priorNode=NULL;
+
+	/* Search using FILE* file as key */
+	if (openFilesList==NULL) return 0; /* Empty list */
+	currentNode=openFilesList;
+	while ((currentNode->file!=fp)&&(currentNode->next!=NULL)) {
+		priorNode=currentNode;
+		currentNode=currentNode->next;
+	}
+	if (currentNode->file!=fp) return 0; /* Not found */
+
+	/* Return results */
+	*fileName=currentNode->name;
+	*content=currentNode->content;
+	*size=currentNode->size;
+
+	/* free node and set prior pointer to the next */
+	if (priorNode==NULL) {
+		openFilesList=currentNode->next;
+	} else {
+		priorNode->next=currentNode->next;
+	}
+	free(currentNode);
+
+	return 1;
+}
+
+#endif
+int writeClose(FILE* fp,int dontSave,int optionflag,const char* backupExtension) {
+	unsigned char* content;
+	char* fileName;
+	unsigned long int size;
+
+	if (getFromOpenFilesList(fp,&fileName,&content,&size)) {
+		if (dontSave) {
+			fclose(fp);
+			if (size) {
+				fp=fopen(fileName,"wb");
+				if (fp==NULL) return -1;
+				fwrite(content,1,size,fp);
+			} else {
+				remove(fileName);
+			}
+		} else {
+			/* File Existed before and we need to back it up */
+			if (hasFlag(backup_flag)) {
+				char aux[MAX_FILENAME_SIZE];
+				static const char defaultbackupExtension[]=DEFAULT_BACKUP_EXTENSION;
+				/* Set default values if there isn't */
+				if (backupExtension==NULL) backupExtension=defaultbackupExtension;
+				/* generate the file name */
+				sprintf(aux,"%s.%s",fileName, backupExtension);
+				fclose(fp);
+				fp=fopen(aux,"wb");
+				if (fp==NULL) return -2;
+				fwrite(content,1,size,fp);
+			}
+		}
+
+		free(fileName);
+		if (size) free(content);
+	}
+
+	return fclose(fp);
+}
+
+int writeOpen(const char* vFileext, FILE* *fp, int optionflag) {
+	/*
+		Opens vFileext for write access
+		 if the path doesn't exist it is created
+		 if the file doesn't exist it is created
+		 if the file does exist it is overwritten
+
+		Sets the file pointer and returns 1 if Ok or 0 if error
+
+		Returns
+		 0 if error
+		 1 if ok
+	*/
+	const char* file;
+	whatIs fileType;
+	int result;
+
+	/* Create base directory and save file */
+	file=repairFolders(vFileext);
+
+	/* Verify if file already exists. */
+	fileType=isDir(vFileext);
+	if (fileType==eDirectory) return 0;
+
+	if (fileType==eFile) {
+		/* File exists. We need to ask */
+	} else {
+		makebase(file);
+	}
+
+	/*
+		If the file exists, we need to remember the old content in memory
+		if not, we need to know the name in case we need to delete it
+	*/
+
+	addFileToOpenFilesList(file,hasFlag(backup_flag));
+	if ((result=((*fp=fopen(file,"wb"))!=NULL))) addPointerToOpenFilesList(*fp);
+	return result;
+}
+
+
+int writeData(const unsigned char* data, int ignoreChars, char* vFileext, int size, int optionflag,const char* backupExtension) {
+	/*
+		Creates vFileext and saves data in it. In case the directory doesn't
+		exist it will be created.
+
+		Data is read from ignoreChars to size.
+		Example:
+			if data="123456789", ignoreChars=3, size=8
+			saved file will contain "45678"
+
+		Returns
+		 0 if error
+		 1 if ok
+	*/
+
+	/* Declare variables */
+	FILE* target;
+	char  ok;
+
+	/* Verify parameters */
+	size-=ignoreChars;
+	if (size<0) return 0;
+	//if (size==0) return 1; /* Wrote 0 bytes */
+
+	/* Save file */
+	ok=writeOpen(vFileext,&target,optionflag);
+	ok=ok&&((!size)||fwrite(data+ignoreChars,size,1,target));
+	ok=ok&&(!writeCloseOk(target,optionflag,backupExtension));
+	return ok;
+}
+
+int mLoadFileArray(const char* vFile,unsigned char** array) {
+	/*
+		Using the string in vFile, it opens the file and returns the
+		number of bytes	in it and the content of the file in array.
+		In case the file couldn't be open or memory allocated returns 0.
+	*/
+
+	/* declare variables */
+	FILE *fp;
+	int  aux;
+
+	/* Open the file */
+	fp=fopen(repairFolders(vFile),"rb");
+	if ((fp=fopen(repairFolders(vFile),"rb"))==NULL) {
+		return 0;
+	} else {
+		/* get file size */
+		fseek(fp,0,SEEK_END);
+		aux=ftell(fp);
+		if ( !aux || (aux>SIZE_OF_FILE) || ( ((*array=(unsigned char*)malloc(sizeof(char)*aux))==NULL) ) ) {
+			/* if the file was null or bigger than the max size or couldn't allocate the file in memory */
+			fclose(fp);
+			return 0;
+		} else {
+			/* if the file was successfully open */
+			fseek(fp,0,SEEK_SET);
+			aux=fread (*array,1,aux,fp);
+			fclose(fp);
+			return aux;
+		}
+	}
+}
+
+#ifdef PR_FUTURE_CODE
+int mDiskVealidateFileHeader(unsigned char* text, int size, FILE* fp) {
+	/*
+		Validates if the file contains the following text in the stream.
+		1 if it does
+		0 if error or doesn't
+
+		Moves the file pointer to the next position
+	*/
+
+	/* Declare variables */
+	int i;
+	unsigned char* readText;
+
+	/* Reserves memory to allocate the read bytes */
+	readText=getMemory(size);
+	if (readText==NULL) return 0; /* memory error, abort */
+
+	/* Read the file and move the file pointer */
+	if (!fread(readText,size,1,fp)) {
+		free(readText);
+		return 0;
+	}
+
+	/* Make the binary compare */
+	for (i=0;(i<size)&&(readText[i]==text[i]);i++);
+
+	/* Frees memory and returns the result */
+	free(readText);
+	return (i==size); /* 0 if the compare for was stopped before end reached */
+}
+#endif
+
+const char* getFileNameFromPath(const char* path) {
+	/*
+		If you give a path you get the filename,
+		if you give a filename, you get the same filename
+	*/
+	int size;
+	size=strlen(path);
+	while (size) {
+		if (isDirSep(path,size)) {
+			return path+size+1;
+		}
+		size--;
+	}
+	return path;
+}
+
+whatIs isDir(const char *path) {
+	/*
+		eDirectory if path is a directory
+		eNotFound if path isn't a directory or doesn't exist
+		eFile if it is a file
+	*/
+	struct stat buf;
+
+	if(stat(path,&buf)==-1) return eNotFound;
+	return (S_IFDIR&buf.st_mode)?eDirectory:eFile;
+}
+
+#ifndef IGNORERECURSIVEFUNCTIONS
+
+int recurseDirectory(const char* path,int optionflag, const char* extension,const char* dirName,const char* resFile, const char* datfilename,const char* datAuthor,FILE* output) {
+	/*
+		Search for all .dat files in the directory
+		if recursive flag is set search over the subdirectories
+		if verbose flag is set shows some messages in the screen
+		when .dat files are found it runs prMain form each of them
+	*/
+
+	/* Declare variables */
+	char*          recursive;
+	struct dirent* directoryStructure;
+	DIR*           dir;
+
+	/* Opens directory */
+	if ((dir = opendir(path))==NULL) {
+		return 0;
+	}
+
+	/* Shows some messages */
+	if ((hasFlag(recursive_flag))&&(hasFlag(verbose_flag))) { /* Only recourse if recursive and verbose flags are set */
+		fprintf(outputStream,PR_TEXT_DISK_PROCESSING,path);
+	}
+
+	/* Main loop: while there are still more files left */
+	while ((directoryStructure = readdir(dir))!=NULL) {
+		if /* Don't look over the system directories */
+			(
+				strcmp(directoryStructure->d_name,".")&&
+				strcmp(directoryStructure->d_name,"..")
+		) {
+			/* Declare variables */
+			int sizeOfPath=strlen(path);
+			int sizeOfFile=strlen(directoryStructure->d_name);
+
+			/* Generate recursive path */
+			recursive=(char*)malloc(sizeOfPath+2+sizeOfFile);
+			memcpy(recursive,path,sizeOfPath);
+			recursive[sizeOfPath]=DIR_SEPARATOR;
+			memcpy(recursive+sizeOfPath+1,directoryStructure->d_name,sizeOfFile+1);
+
+			/*
+				If recursive path is a directory and recursive flag is set recourse into it
+				if recursive path is a directory and recursive flag wasn't set, just ignore
+				if recursive path is not a directory and is a dat file, do prMain
+				if recursive path is not a directory and is not a dat file, ignore
+			*/
+			if (isDir(recursive)==eDirectory) {
+				if (hasFlag(recursive_flag)) { /* Only recourse if recursive flag is set */
+					recurseDirectory(recursive,optionflag,extension,dirName,resFile,datfilename,datAuthor,output);
+				}
+			} else {
+				char aux[]=".dat";
+				if (sizeOfFile>4) {
+					if (equalsIgnoreCase(aux,directoryStructure->d_name+sizeOfFile-4)) {
+						prMain(optionflag,extension,dirName,resFile,recursive,directoryStructure->d_name,datAuthor,output);
+					}
+				}
+			}
+			/* Free all allocated memory */
+			free(recursive);
+		}
+	}
+	return 1;
+}
+
+#endif
+
diff --git a/FP/src/res/resources.c b/FP/src/res/resources.c
new file mode 100644
index 0000000..dbd9217
--- /dev/null
+++ b/FP/src/res/resources.c
@@ -0,0 +1,186 @@
+/*  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
+*/
+
+/*
+extract.c: Princed Resources : DAT Extractor
+\xaf\xaf\xaf\xaf\xaf\xaf\xaf\xaf\xaf
+ Copyright 2003, 2004 Princed Development Team
+  Created: 24 Aug 2003
+
+  Author: Enrique Calot <ecalot.cod@princed.com.ar>
+  Version: 1.01 (2003-Oct-23)
+  Version: 1.20 (2004-Mar-07)
+  Version: 1.30 (2004-Mar-15)
+
+ Note:
+  DO NOT remove this copyright notice
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include "freeprince.h"
+
+#include "dat.h"
+#include "disk.h"
+
+/***************************************************************\
+|                  I M P L E M E N T A T I O N                  |
+\***************************************************************/
+
+#define initializePaletteList \
+for (id=0;id<MAX_RES_COUNT;id++) {\
+	if (r[id]!=NULL) {\
+		r[id]->palAux=NULL;\
+	}\
+}
+
+/***************************************************************\
+|                    M A I N   E X T R A C T                    |
+\***************************************************************/
+
+
+/*
+	Extracts a dat file
+	For parameter documentation, see pr.c
+*/
+
+int extract(const char* vFiledat,const char* vDirExt, tResource* r[], int optionflag, const char* vDatFileName, const char* vDatAuthor,const char* backupExtension) {
+	char               vFileext[MAX_FILENAME_SIZE];
+	int                indexNumber;
+	int                ok=1;
+	long int           id;
+	tImage             image; /* this is used to make a persistent palette */
+	unsigned char*     data;
+	unsigned long  int size;
+	unsigned short int numberOfItems;
+	unsigned short int paletteId=0;
+
+	/* Initialize abstract variables to read this new DAT file */
+	if (!mReadBeginDatFile(&numberOfItems,vFiledat)) return -1;
+fld("a");
+	/* Initializes the palette list */
+	initializePaletteList;
+fld("b");
+
+	/* main loop */
+	for (indexNumber=0;ok&&(indexNumber<numberOfItems);indexNumber++) {
+		id=mReadFileInDatFile(indexNumber,&data,&size);
+fld("c");
+printf("*K) id=%d size=%d %d:%d:%d:%d:%d:%d\n",id,size,data[0],data[1],data[2],data[3],data[4],data[5]);
+
+		if (id<0) return -3; /* Read error */
+		if (id==0xFFFF) continue; /* Tammo Jan Bug fix */
+		if (id>=MAX_RES_COUNT) return -3; /* A file with an ID out of range will be treated as invalid */
+fld("d");
+
+		/* set resource information on this index entry */
+		if (mReadInitResource(r+id,data,size)) return -2;
+fld("e");
+printf("z->%d\n",r[id]->type);
+		if ((r[id]->type==RES_TYPE_PALETTE)||isInThePartialList(r[id]->path,id)) { /* If the resource was specified or is a palette, do the tasks */
+			if (!(hasFlag(unknown_flag))) { /* If unknown flag is set do nothing but generate the unknown.xml file */
+				if (hasFlag(raw_flag)) r[id]->type=0; /* If "extract as raw" is set, type is 0 */
+
+				/* get save file name (if unknown document it in the xml) */
+				getFileName(vFileext,vDirExt,r[id],(unsigned short)id,vFiledat,vDatFileName,optionflag,backupExtension);
+fld("f");
+				switch (r[id]->type) {
+					case RES_TYPE_LEVEL:
+						ok=ok&&mFormatExportPlv(data,vFileext,size,r[id]->number,vDatFileName,r[id]->name,r[id]->desc,vDatAuthor,optionflag,backupExtension);
+						break;
+					case RES_TYPE_BINARY: /* Binary files */
+					case RES_TYPE_RAW: /* Raw files */
+						ok=ok&&writeData(data,1,vFileext,size,optionflag,backupExtension); /* Ignore checksum */
+						break;
+					case RES_TYPE_PALETTE: /* save and remember palette file */
+						/* This will remember the palette for the next images */
+						r[id]->palAux=getMemory(size);
+						memcpy(r[id]->palAux,data,size);
+						if (!paletteId) { /* In case there is no loaded palettes load immediately the first found palette to clear garbage */
+							mLoadPalette(data,image);
+							paletteId=id;
+						}
+						/* This will export the palette */
+						if (isInThePartialList(r[id]->path,id))  /* If the palette was specified extract it */
+							ok=ok&&mFormatExportPal(data,vFileext,size,optionflag,backupExtension);
+						break;
+					case RES_TYPE_PCSPEAKER: /* save pcs file */
+					case RES_TYPE_MIDI:	/* save midi file */
+printf("a->%d\n",ok);
+						ok=ok&&mFormatExportMid(data,vFileext,size,optionflag,backupExtension);
+printf("b->%d\n",ok);
+						break;
+					case RES_TYPE_WAVE: /* save wav file */
+						ok=ok&&mFormatExportWav(data,vFileext,size,optionflag,backupExtension);
+						break;
+					case RES_TYPE_IMAGE: /* save image */
+						/* Palette handling */
+fld("Z1");
+						if (r[id]->palette!=paletteId) { /* The palette isn't the already loaded */
+							if (r[id]->palette) { /* We need a palette */
+								/*
+									We need a palette and it is not the palette we have loaded in memory
+									So a new palette is going to be loaded.
+								*/
+								if ((r[r[id]->palette]->palAux)!=NULL) { /* If this palette wasn't loaded, it becomes loaded */
+									mLoadPalette(r[r[id]->palette]->palAux,image);
+									paletteId=r[id]->palette; /* sets the new palette loaded */
+								}
+							}
+						}
+						/* Export bitmap */
+fld("Z2");
+						ok=ok&&mFormatExportBmp(data,vFileext,size,image,optionflag,backupExtension);
+fld("Z3");
+						break;
+				}
+				/* Verbose information */
+				if (hasFlag(verbose_flag)) {
+					if (ok) {
+						fprintf(outputStream,PR_TEXT_EXPORT_WORKING,getFileNameFromPath(vFileext));
+					} else {
+						fprintf(outputStream,PR_TEXT_EXPORT_ERROR,getFileNameFromPath(vFileext));
+					}
+				}
+			} else {
+				/* if the dat file is unknown, add it in the xml */
+				getFileName(vFileext,vDirExt,r[id],(unsigned short)id,vFiledat,vDatFileName,optionflag,backupExtension);
+			}
+			/*freeAllocation(data);*/
+		}
+	}
+
+	/* Free allocated resources, dynamic strings and the index */
+	for (id=0;id<MAX_RES_COUNT;id++) {
+		if (r[id]!=NULL) {
+			freeAllocation(r[id]->palAux);
+			freeAllocation(r[id]->desc);
+			freeAllocation(r[id]->name);
+			freeAllocation(r[id]->path);
+			free(r[id]);
+		}
+	}
+	mReadCloseDatFile();
+
+	/* Close unknownXML */
+	endUnknownXml(optionflag,backupExtension);
+	return ok-1;
+}
+