Upgraded to Pr 1.0 beta
[fp-git.git] / PR / src / lib / layers / disk.c
1 /*  Princed V3 - Prince of Persia Level Editor for PC Version
2     Copyright (C) 2003 Princed Development Team
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
18     The authors of this program may be contacted at http://forum.princed.com.ar
19 */
20
21 /*
22 disk.c: Princed Resources : Disk Access & File handling functions
23 ¯¯¯¯¯¯
24  Copyright 2003 Princed Development Team
25   Created: 29 Oct 2003
26
27   Author: Enrique Calot <ecalot.cod@princed.com.ar>
28   Version: 1.00 (2003-Oct-29)
29
30   Modified by: Enrique Calot <ecalot.cod@princed.com.ar>
31   Version: 1.10 (2003-Dec-03)
32   Modified by: Santiago Zamora <drkzight@users.sourceforge.net>
33   Version: 1.20 (2004-Jan-06)
34
35  Note:
36   DO NOT remove this copyright notice
37 */
38
39 /* Defines */
40 #include "memory.h"
41 #include <string.h>
42 #include "pr.h"
43 #include "disk.h"
44 #include "xmlparse.h" /* equalsIgnoreCase */
45
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 extern FILE* outputStream;
49 #ifdef UNIX
50         #define defmkdir(a) mkdir (a,(mode_t)0755)
51         #include <dirent.h>
52         #include <termios.h>
53         //#include <curses.h>
54         #include <unistd.h>
55         #include <fcntl.h>
56         #define osIndepGetCharacter() getchar()
57 #else
58         #include <direct.h>
59         #include "direntwin.h"
60         #define defmkdir(a) mkdir (a)
61         #include <conio.h>
62         #define osIndepGetCharacter() getche()
63 #endif
64
65 /***************************************************************\
66 |              Disk Access & File handling functions            |
67 \***************************************************************/
68
69 /* Repair folders */
70 const char *repairFolders(const char* a) {
71         int i,k;
72         static char result[MAX_FILENAME_SIZE];
73
74         for (i=0,k=0;a[i]&&(k<MAX_FILENAME_SIZE);) {
75                 if (isDirSep(a,i)) {
76                         result[k]=DIR_SEPARATOR;
77                         i++;
78                         while (isDirSep(a,i)) i++;
79                 } else {
80                         result[k]=a[i];
81                         i++;
82                 }
83                 k++;
84         }
85         result[k]=0;
86         return result;
87 }
88
89
90 /* Create base directory of a file */
91 int makebase(const char* p) {
92         /*
93                 Creates the base directory of the given file "p"
94                 Returns 0 if created
95                 Returns -1 if an error occurred
96
97                 Note: if the base directory already exists it will return -1!
98         */
99
100         /* Declare variables */
101         static char old[MAX_FILENAME_SIZE];
102         int i,a,equal=1;
103         int size;
104         char* aux;
105
106         /* Initialize variables */
107         size=(strlen(p)+1);
108         aux=(char*)malloc(size);
109
110         /* Make directories */
111         for (i=0;i<size;i++) {
112                 aux[i]=0;
113                 equal=equal&&(old[i]==p[i]);
114                 if ((!equal)&&(p[i]==DIR_SEPARATOR)) a=defmkdir(aux);
115                 old[i]=p[i];
116                 aux[i]=p[i];
117         }
118
119         free(aux);
120         return a;
121 }
122
123 static tOpenFiles* openFilesList=NULL;
124
125 void addFileToOpenFilesList(const char* fileName,int hasBackup) {
126         /*
127                 Add a recently safe open file to the file pointer dynamic table
128                 using the LIFO philosophy.
129         */
130
131         tOpenFiles* newNode;
132
133         /* Create the new node and fill in the fields */
134         newNode=(tOpenFiles*)malloc(sizeof(tOpenFiles));
135         newNode->next=openFilesList;
136         newNode->name=strallocandcopy(fileName);
137         if (hasBackup) {
138                 newNode->size=mLoadFileArray(fileName,&(newNode->content));
139         } else {
140                 newNode->size=0;
141         }
142         openFilesList=newNode;
143 }
144
145 void addPointerToOpenFilesList(FILE* fp) { /* TODO: use a define */
146         openFilesList->file=fp;
147 }
148
149 int getFromOpenFilesList(FILE* fp, char** fileName, unsigned char** content, unsigned long int *size) {
150         tOpenFiles* currentNode;
151         tOpenFiles* priorNode=NULL;
152
153         /* Search using FILE* file as key */
154         if (openFilesList==NULL) return 0; /* Empty list */
155         currentNode=openFilesList;
156         while ((currentNode->file!=fp)&&(currentNode->next!=NULL)) {
157                 priorNode=currentNode;
158                 currentNode=currentNode->next;
159         }
160         if (currentNode->file!=fp) return 0; /* Not found */
161
162         /* Return results */
163         *fileName=currentNode->name;
164         *content=currentNode->content;
165         *size=currentNode->size;
166
167         /* free node and set prior pointer to the next */
168         if (priorNode==NULL) {
169                 openFilesList=currentNode->next;
170         } else {
171                 priorNode->next=currentNode->next;
172         }
173         free(currentNode);
174
175         return 1;
176 }
177
178 int writeClose(FILE* fp,int dontSave,int optionflag,const char* backupExtension) {
179         unsigned char* content;
180         char* fileName;
181         unsigned long int size;
182
183         if (getFromOpenFilesList(fp,&fileName,&content,&size)) {
184                 if (dontSave) {
185                         fclose(fp);
186                         if (size) {
187                                 fp=fopen(fileName,"wb");
188                                 if (fp==NULL) return -1;
189                                 fwrite(content,1,size,fp);
190                         } else {
191                                 remove(fileName);
192                         }
193                 } else {
194                         /* File Existed before and we need to back it up */
195                         if (hasFlag(backup_flag)) {
196                                 char aux[MAX_FILENAME_SIZE];
197                                 static const char defaultbackupExtension[]=DEFAULT_BACKUP_EXTENSION;
198                                 /* Set default values if there isn't */
199                                 if (backupExtension==NULL) backupExtension=defaultbackupExtension;
200                                 /* generate the file name */
201                                 sprintf(aux,"%s.%s",fileName, backupExtension);
202                                 fclose(fp);
203                                 fp=fopen(aux,"wb");
204                                 if (fp==NULL) return -2;
205                                 fwrite(content,1,size,fp);
206                         }
207                 }
208
209                 free(fileName);
210                 if (size) free(content);
211         }
212
213         return fclose(fp);
214 }
215
216 int writeOpen(const char* vFileext, FILE* *fp, int optionflag) {
217         /*
218                 Opens vFileext for write access
219                  if the path doesn't exist it is created
220                  if the file doesn't exist it is created
221                  if the file does exist it is overwritten
222
223                 Sets the file pointer and returns 1 if Ok or 0 if error
224
225                 Returns
226                  0 if error
227                  1 if ok
228         */
229         const char* file;
230         whatIs fileType;
231         static int all=0;
232         int result;
233
234 #ifdef UNIX
235 #ifndef IGNORE_TERM_CHANGE
236         /* This will eliminate the enter after the input */
237         struct termios term;
238         struct termios termOld;
239
240         tcgetattr (STDIN_FILENO, &term);
241         tcgetattr (STDIN_FILENO, &termOld); /* save original proprieties */
242         term.c_lflag &= ~(ICANON);
243         tcsetattr (STDIN_FILENO, TCSANOW, &term);
244 #endif
245 #endif
246
247         /* Create base directory and save file */
248         file=repairFolders(vFileext);
249
250         /* Verify if file already exists. */
251         fileType=isDir(vFileext);
252         if (fileType==eDirectory) return 0;
253
254         if (fileType==eFile) {
255                 /* File exists. We need to ask */
256                 if ((!(hasFlag(force_flag)))&&(!all)) {
257                         char answer;
258                         printf(PR_TEXT_DISK_REPLACE,getFileNameFromPath(file));
259                         answer=osIndepGetCharacter();
260                         printf("\n");
261                         if (charToUpper(answer)==PR_DISK_REPLACE_NO)  return 0;
262                         if (charToUpper(answer)==PR_DISK_REPLACE_ALL) all=1;
263                 }
264         } else {
265                 makebase(file);
266         }
267
268 #ifdef UNIX
269 #ifndef IGNORE_TERM_CHANGE
270         /* restoring previous terminal options */
271         term=termOld;
272         tcsetattr (STDIN_FILENO, TCSANOW, &termOld);
273 #endif
274 #endif
275         /*
276                 If the file exists, we need to remember the old content in memory
277                 if not, we need to know the name in case we need to delete it
278         */
279
280         addFileToOpenFilesList(file,hasFlag(backup_flag));
281         if ((result=((*fp=fopen(file,"wb"))!=NULL))) addPointerToOpenFilesList(*fp);
282         return result;
283 }
284
285
286 int writeData(const unsigned char* data, int ignoreChars, char* vFileext, int size, int optionflag,const char* backupExtension) {
287         /*
288                 Creates vFileext and saves data in it. In case the directory doesn't
289                 exist it will be created.
290
291                 Data is read from ignoreChars to size.
292                 Example:
293                         if data="123456789", ignoreChars=3, size=8
294                         saved file will contain "45678"
295
296                 Returns
297                  0 if error
298                  1 if ok
299         */
300
301         /* Declare variables */
302         FILE* target;
303         char  ok;
304
305         /* Verify parameters */
306         size-=ignoreChars;
307         if (size<=0) return 0;
308
309         /* Save file */
310         ok=writeOpen(vFileext,&target,optionflag);
311         ok=ok&&fwrite(data+ignoreChars,size,1,target);
312         ok=ok&&(!writeCloseOk(target,optionflag,backupExtension));
313         return ok;
314 }
315
316 int mLoadFileArray(const char* vFile,unsigned char** array) {
317         /*
318                 Using the string in vFile, it opens the file and returns the
319                 number of bytes in it and the content of the file in array.
320                 In case the file couldn't be open or memory allocated returns 0.
321         */
322
323         /* declare variables */
324         FILE *fp;
325         int  aux;
326
327         /* Open the file */
328         if ((fp=fopen(repairFolders(vFile),"rb"))==NULL) {
329                 return 0;
330         } else {
331                 /* get file size */
332                 fseek(fp,0,SEEK_END);
333                 aux=ftell(fp);
334                 if ( !aux || (aux>SIZE_OF_FILE) || ( ((*array=(unsigned char*)malloc(sizeof(char)*aux))==NULL) ) ) {
335                         /* if the file was null or bigger than the max size or couldn't allocate the file in memory */
336                         fclose(fp);
337                         return 0;
338                 } else {
339                         /* if the file was successfully open */
340                         fseek(fp,0,SEEK_SET);
341                         aux=fread (*array,1,aux,fp);
342                         fclose(fp);
343                         return aux;
344                 }
345         }
346 }
347
348 #ifdef PR_FUTURE_CODE
349 int mDiskVealidateFileHeader(unsigned char* text, int size, FILE* fp) {
350         /*
351                 Validates if the file contains the following text in the stream.
352                 1 if it does
353                 0 if error or doesn't
354
355                 Moves the file pointer to the next position
356         */
357
358         /* Declare variables */
359         int i;
360         unsigned char* readText;
361
362         /* Reserves memory to allocate the read bytes */
363         readText=getMemory(size);
364         if (readText==NULL) return 0; /* memory error, abort */
365
366         /* Read the file and move the file pointer */
367         if (!fread(readText,size,1,fp)) {
368                 free(readText);
369                 return 0;
370         }
371
372         /* Make the binary compare */
373         for (i=0;(i<size)&&(readText[i]==text[i]);i++);
374
375         /* Frees memory and returns the result */
376         free(readText);
377         return (i==size); /* 0 if the compare for was stopped before end reached */
378 }
379 #endif
380
381 const char* getFileNameFromPath(const char* path) {
382         /*
383                 If you give a path you get the filename,
384                 if you give a filename, you get the same filename
385         */
386         int size;
387         size=strlen(path);
388         while (size) {
389                 if (isDirSep(path,size)) {
390                         return path+size+1;
391                 }
392                 size--;
393         }
394         return path;
395 }
396
397 whatIs isDir(const char *path) {
398         /*
399                 eDirectory if path is a directory
400                 eNotFound if path isn't a directory or doesn't exist
401                 eFile if it is a file
402         */
403         struct stat buf;
404
405         if(stat(path,&buf)==-1) return eNotFound;
406         return (S_IFDIR&buf.st_mode)?eDirectory:eFile;
407 }
408
409 #ifndef IGNORERECURSIVEFUNCTIONS
410
411 int recurseDirectory(const char* path,int optionflag, const char* extension,const char* dirName,const char* resFile, const char* datfilename,const char* datAuthor,FILE* output) {
412         /*
413                 Search for all .dat files in the directory
414                 if recursive flag is set search over the subdirectories
415                 if verbose flag is set shows some messages in the screen
416                 when .dat files are found it runs prMain form each of them
417         */
418
419         /* Declare variables */
420         char*          recursive;
421         struct dirent* directoryStructure;
422         DIR*           dir;
423
424         /* Opens directory */
425         if ((dir = opendir(path))==NULL) {
426                 return 0;
427         }
428
429         /* Shows some messages */
430         if ((hasFlag(recursive_flag))&&(hasFlag(verbose_flag))) { /* Only recourse if recursive and verbose flags are set */
431                 fprintf(outputStream,PR_TEXT_DISK_PROCESSING,path);
432         }
433
434         /* Main loop: while there are still more files left */
435         while ((directoryStructure = readdir(dir))!=NULL) {
436                 if /* Don't look over the system directories */
437                         (
438                                 strcmp(directoryStructure->d_name,".")&&
439                                 strcmp(directoryStructure->d_name,"..")
440                 ) {
441                         /* Declare variables */
442                         int sizeOfPath=strlen(path);
443                         int sizeOfFile=strlen(directoryStructure->d_name);
444
445                         /* Generate recursive path */
446                         recursive=(char*)malloc(sizeOfPath+2+sizeOfFile);
447                         memcpy(recursive,path,sizeOfPath);
448                         recursive[sizeOfPath]=DIR_SEPARATOR;
449                         memcpy(recursive+sizeOfPath+1,directoryStructure->d_name,sizeOfFile+1);
450
451                         /*
452                                 If recursive path is a directory and recursive flag is set recourse into it
453                                 if recursive path is a directory and recursive flag wasn't set, just ignore
454                                 if recursive path is not a directory and is a dat file, do prMain
455                                 if recursive path is not a directory and is not a dat file, ignore
456                         */
457                         if (isDir(recursive)==eDirectory) {
458                                 if (hasFlag(recursive_flag)) { /* Only recourse if recursive flag is set */
459                                         recurseDirectory(recursive,optionflag,extension,dirName,resFile,datfilename,datAuthor,output);
460                                 }
461                         } else {
462                                 char aux[]=".dat";
463                                 if (sizeOfFile>4) {
464                                         if (equalsIgnoreCase(aux,directoryStructure->d_name+sizeOfFile-4)) {
465                                                 prMain(optionflag,extension,dirName,resFile,recursive,directoryStructure->d_name,datAuthor,output);
466                                         }
467                                 }
468                         }
469                         /* Free all allocated memory */
470                         free(recursive);
471                 }
472         }
473         return 1;
474 }
475
476 #endif
477