Upgraded to Pr 1.0 beta
[fp-git.git] / PR / src / lib / layers / autodetect.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 resources.c: Princed Resources : Resource Handler
23 ¯¯¯¯¯¯¯¯¯¯¯
24  Copyright 2003 Princed Development Team
25   Created: 24 Aug 2003
26
27   Author: Enrique Calot <ecalot.cod@princed.com.ar>
28   Version: 1.01 (2003-Oct-23)
29
30  Note:
31   DO NOT remove this copyright notice
32 */
33
34 /***************************************************************\
35 |                  I M P L E M E N T A T I O N                  |
36 \***************************************************************/
37
38 /* Includes */
39 #include <stdio.h>
40 #include <string.h>
41 #include <stdlib.h>
42 #include "pr.h"
43 #include "xmlparse.h"
44 #include "xmlsearch.h"
45 #include "disk.h"
46 #include "memory.h"
47 #include "resources.h"
48 #include "compress.h"
49
50 extern FILE* outputStream;
51
52 /***************************************************************\
53 |                       Item Type Detector                      |
54 \***************************************************************/
55
56 int verifyLevelHeader(const unsigned char *array, int size) {
57         return (((size==2306)||(size==2305))&&!(array[1698]&0x0F)&&!(array[1700]&0x0F)&&!(array[1702]&0x0F));
58 }
59
60 int verifyImageHeader(const unsigned char *array, int size) {
61         unsigned char imageBitRate;
62         imageBitRate=((unsigned char)array[6]&0xF0);
63         return (size>7) && (!array[5]) && ((imageBitRate==0xB0));
64         /* return (size>7) && (!array[5]) && ((imageBitRate==0xB0)||(imageBitRate==0x00)); */
65 }
66
67 int verifyPaletteHeader(const unsigned char *array, int size) {
68         return ((size==101)&&(!array[2])&&(!array[3])&&(array[4]==0x10));
69 }
70
71 int verifyMidiHeader(const unsigned char *array, int size) {
72         return
73                 (size>6) &&
74                 (array[1]==0x02) &&
75                 (array[2]=='M') &&
76                 (array[3]=='T') &&
77                 (array[4]=='h') &&
78                 (array[5]=='d')
79         ;
80 }
81
82 int verifyWaveHeader(const unsigned char *array, int size) {
83         return
84                 (size>1)&&(array[1]==0x01)
85         ;
86 }
87
88 int verifySpeakerHeader(const unsigned char *array, int size) {
89         return
90                 (size>2)&&(array[1]==0x00) /* &&!(size%3) */
91         ;
92 }
93
94 int verifyHeader(const unsigned char *array, int size) {
95         if (verifyLevelHeader  (array,size)) return RES_TYPE_LEVEL;
96         if (verifyMidiHeader   (array,size)) return RES_TYPE_MIDI;
97         if (verifyImageHeader  (array,size)) return RES_TYPE_IMAGE;
98         if (verifyPaletteHeader(array,size)) return RES_TYPE_PALETTE;
99         if (verifyWaveHeader   (array,size)) return RES_TYPE_WAVE;
100         if (verifySpeakerHeader(array,size)) return RES_TYPE_PCSPEAKER;
101         return RES_TYPE_BINARY;
102 }
103
104 const char* getExtDesc(int type) {
105         static const char* extarraydesc[]=RES_FILE_TYPES;
106         return extarraydesc[type];
107 }
108
109 /***************************************************************\
110 |                Partial Resource List Functions                |
111 \***************************************************************/
112
113 static tResIdList partialList;
114
115 void parseGivenPath(char* path) {
116         /*
117                 PRE:  partialList.list was not allocated
118                 POST:
119                  partialList.count=0 and partialList.list=NULL if all resources
120                  path was trimed in the "@"
121         */
122
123         int i;
124         int separator=0;
125         int resourceValue;
126         int j=0;
127         unsigned char n;
128
129         /* Check if the variable wasn't initialized before */
130         if (partialList.count!=0) return;
131         partialList.list=NULL;
132
133         /* Validates the NULL path */
134         if (path==NULL) return;
135
136         /* Locate the string separation */
137         while (path[separator]&&path[separator]!='@') separator++;
138
139         /* If no separation */
140         if (!path[separator]) return; /* There was no separator */
141
142         /* Count values, separate them with '\0' and alloc memory */
143         partialList.count=1;
144         path[separator]=0; /* Trim the path to the separator */
145         i=++separator;
146         while(path[i]) {
147                 if (path[i]==',') {
148                         partialList.count++;
149                         path[i]=0;
150                 }
151                 i++;
152         }
153         partialList.list=(tResIdListItem*)malloc(sizeof(tResIdListItem)*partialList.count);
154
155         /* Parse values and save them in the list */
156         resourceValue=0;
157         for(i=separator;j!=partialList.count;i++) {
158                 n=path[i];
159                 if ((0x2F<n)&&(n<0x3A)) {
160                         resourceValue=resourceValue*10+(n-'0');
161                 } else {
162                         if (n) {
163                                 partialList.list[j].idType=eString;
164                                 partialList.list[j].value=(char*)strallocandcopy(repairFolders(path+separator));
165                                 while (path[i]) i++;
166                         } else {
167                                 partialList.list[j].idType=eValue;
168                                 partialList.list[j].value=(void*)resourceValue;
169                         }
170                         resourceValue=0;
171                         separator=i+1;
172                         j++;
173                 }
174         }
175 }
176
177 int isInThePartialList(const char* vFile, int value) {
178         /*
179                 Cases:
180                         "path/path@"                    all files are false
181                         "path/path"                     all files are true
182                         "path/path@12file/jjj.bmp,777"  only file "12file/jjj.bmp" and id 777 are true
183                         "path/path@1,2,3"               only ids 1, 2 and 3 are true
184         */
185         int i;
186         char* file;
187
188         if (!partialList.count) return 1;
189         file=(char*)repairFolders(vFile);
190
191         for (i=0;i<partialList.count;i++) {
192                 if (partialList.list[i].idType==eValue) {
193                         if (value==(int)partialList.list[i].value) return 1;
194                 } else {
195                         if (file)
196                                 if (equalsIgnoreCase(file,(char*)partialList.list[i].value)) return 1;
197                 }
198         }
199         return 0;
200 }
201
202 void freePartialList() {
203         int i;
204         for (i=0;i<partialList.count;i++) {
205                 if (partialList.list[i].idType==eString)
206                         free(partialList.list[i].value);
207         }
208         partialList.count=0;
209 }
210
211 /***************************************************************\
212 |                       Checksum handling                       |
213 \***************************************************************/
214
215 int checkSum(unsigned char* data,int size) {
216         unsigned char  checksum = 1;
217
218         /* calculates the checksum */
219         while (size--) checksum+=*(data++);
220         return !checksum;
221 }
222
223 /***************************************************************\
224 |                     Parsing resource file                     |
225 \***************************************************************/
226
227 /* Initializes the resource table */
228 void emptyTable(tResource* r[]) {
229         int i=MAX_RES_COUNT;
230         while (i--) *(r++)=NULL;
231 }
232
233 /* Resources input xml tree. Private+abstract variable */
234 static tTag* xmlStructure=NULL; /* Keeping the parsed file structure in memory will save a lot of time */
235
236 int parseStructure(const char* vFile) {
237         static const char defaultXmlFile[]=RES_XML_RESOURC_XML;
238         int error=0;
239
240         /* Generate xml structure if doesn't exist */
241         if (xmlStructure==NULL) {
242                 /* Set default values */
243                 if (vFile==NULL) vFile=defaultXmlFile;
244                 xmlStructure=parseXmlFile(vFile,&error);
245         }
246         if (error) xmlStructure=NULL;
247         return error;
248 }
249
250 /* parse file */
251 int parseFile(const char* vFile, const char* datFile, tResource* r[]) {
252         /* Declare error variable */
253         int error;
254         tPassWork pass;
255
256         /* Generate xml structure if doesn't exist */
257         if ((error=(parseStructure(vFile)))) return error;
258
259         /* Use the xml structure to Generate the resource structure of the file */
260         emptyTable(r);
261         pass.datFile=datFile;
262         pass.r=r;
263         workTree(xmlStructure,&pass,workTag);
264
265         /* All done */
266         return 0;
267 }
268
269 void freeParsedStructure() {
270         /* Free if exist */
271         if (xmlStructure!=NULL) freeTagStructure(xmlStructure);
272         /* Reinitializes the variable */
273         xmlStructure=NULL;
274 }
275
276 /***************************************************************\
277 |                     Unknown.xml primitives                    |
278 \***************************************************************/
279
280 /* Resources output to xml functions. Private+abstract variable */
281 static FILE* unknownXmlFile=NULL;
282
283 void AddToUnknownXml(const char* vFiledatWithPath,unsigned short id,const char* ext,char type,const char* vDirExt,unsigned short pal,const char* vFiledat,int optionflag,int count) {
284         /* Open file if not open */
285         if (unknownXmlFile==NULL) {
286                 char xmlFile[MAX_FILENAME_SIZE];
287                 sprintf(xmlFile,RES_XML_UNKNOWN_PATH""RES_XML_UNKNOWN_XML,vDirExt,vFiledatWithPath);
288
289                 /* Open file */
290                 if (!writeOpen(xmlFile,&unknownXmlFile,optionflag)) return;
291
292                 /* Save headers */
293                 if (type==6) pal=id;
294                 fprintf(unknownXmlFile,RES_XML_UNKNOWN_START,
295                         vFiledat,vFiledatWithPath,pal
296                 );
297         }
298
299         /* Write item */
300         fprintf(unknownXmlFile,RES_XML_UNKNOWN_ITEM,
301                 id,getExtDesc(type),count,ext,getExtDesc(type),getExtDesc(type),count
302         ); /* To the xml output */
303 }
304
305 static unsigned int typeCount[RES_TYPECOUNT]; /* initialized in 0 */
306
307 void endUnknownXml(int optionflag, const char* backupExtension) {
308         if (unknownXmlFile!=NULL) {
309                 int i;
310                 fprintf(unknownXmlFile,RES_XML_UNKNOWN_END);
311                 writeCloseOk(unknownXmlFile,optionflag,backupExtension);
312                 unknownXmlFile=NULL;
313                 for (i=0;i<RES_TYPECOUNT;i++) typeCount[i]=0;
314         }
315 }
316
317 /***************************************************************\
318 |                   Resources extra functions                   |
319 \***************************************************************/
320
321 void getFileName(char* vFileext,const char* vDirExt,tResource* r,unsigned short id,const char* vFiledat, const char* vDatFileName,int optionflag, const char* backupExtension) {
322         static const char* extarray[]=RES_FILE_EXTENSIONS;
323         int pos;
324
325         if (r->path==NULL) {
326                 pos=((r->type<RES_TYPECOUNT)&&(r->type>=0))?r->type:RES_TYPE_BINARY;
327                 typeCount[pos]++;
328
329                 /* set filename */
330                 sprintf(vFileext,RES_XML_UNKNOWN_PATH""RES_XML_UNKNOWN_FILES,vDirExt,vDatFileName,getExtDesc(pos),typeCount[pos],extarray[pos]);
331                 AddToUnknownXml(vDatFileName,id,extarray[pos],r->type,vDirExt,r->palette,vFiledat,optionflag,typeCount[pos]);
332         } else {
333                 /* set filename */
334                 sprintf(vFileext,"%s/%s",vDirExt,r->path);
335         }
336 }
337
338 /* Search files for the Import feature */
339 int importDir(const char* directory, const char* vResFile, int pOption, const char* backupExtension,const char* vDatDirectory, FILE* output) {
340         /* Declare error variable */
341         int error=0;
342         char* datfile;
343         char* recursive;
344         int sizeOfPath;
345         int sizeOfFile;
346         int result;
347
348         /* Generate xml structure if doesn't exist */
349         if ((error=(parseStructure(vResFile)))) return error;
350
351         /* Use the xml structure to Generate the file list */
352         workTree(xmlStructure,NULL,addFileToList);
353
354         while(datfile=getFileFromList()) {
355                 sizeOfPath=strlen(vDatDirectory);
356                 sizeOfFile=strlen(datfile);
357
358                 /* Generate full vDatDirectory/datfile path */
359                 recursive=(char*)malloc(sizeOfPath+sizeOfFile+2);
360                 memcpy(recursive,vDatDirectory,sizeOfPath);
361                 recursive[sizeOfPath]=DIR_SEPARATOR;
362                 memcpy(recursive+sizeOfPath+1,datfile,sizeOfFile+1);
363
364                 /* Run program */
365                 result=prMain(pOption, backupExtension,directory,vResFile,recursive,datfile,NULL,output);
366                 /* Free memory */
367                 free(datfile);
368                 free(recursive);
369         }
370
371         /* All done */
372         return result;
373 }
374
375 int isntADatFile(const char* testFile, const char* vResFile) {
376         /*
377                 Results:
378                         0  Is a dat file
379                         1  It isn't a dat file
380                         -1 Parse error
381                         -2 No memory
382                         -3 Attribute not recognized
383                         -4 File not found
384         */
385
386         /* Declare result variable */
387         int result;
388         char* gottenFile;
389
390         /* Generate xml structure if doesn't exist */
391         if ((result=(parseStructure(vResFile)))) return result;
392
393         /* Use the xml structure to Generate the file list */
394         workTree(xmlStructure,NULL,addFileToList);
395         while((gottenFile=(getFileFromList()))) {
396                 result=result||equalsIgnoreCase(gottenFile,testFile);
397                 free(gottenFile);
398         }
399
400         /* All done */
401         return !result;
402 }
403
404 /***************************************************************\
405 |                Resource tree browsing for DLL                 |
406 \***************************************************************/
407
408 #ifdef DLL
409
410 tTag* resourceTreeGetRoot () {
411         return xmlStructure;
412 }
413
414 tTag* resourceTreeGetNext (tTag* whereAmI) {
415         return whereAmI->next;
416 }
417
418 tTag* resourceTreeGetChild(tTag* whereAmI) {
419         return whereAmI->child;
420 }
421
422 int   resourceTreeGetInfo (tTag* whereAmI,      char** tag, char** desc, char** path, char** file, char** itemtype, char** name, char** palette, char** type, char** value, char** version, char** number) {
423         if (whereAmI==NULL) return 0;
424         *tag=whereAmI->tag;
425         *desc=whereAmI->desc;
426         *path=whereAmI->path;
427         *file=whereAmI->file;
428         *itemtype=whereAmI->itemtype;
429         *name=whereAmI->name;
430         *palette=whereAmI->palette;
431         *type=whereAmI->type;
432         *value=whereAmI->value;
433         *version=whereAmI->version;
434         *number=whereAmI->number;
435         return 1;
436 }
437
438 #endif
439