098 renderer added
[fceu.git] / file.c
CommitLineData
c62d2810 1/* FCE Ultra - NES/Famicom Emulator
2 *
3 * Copyright notice for this file:
4 * Copyright (C) 2002 Ben Parnell
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24
25#ifdef ZLIB
26 #include <zlib.h>
27 #include "zlib/unzip.h"
28#endif
29
30#include "types.h"
31#include "file.h"
32#include "endian.h"
33#include "memory.h"
34#include "driver.h"
892b1f6c 35#include "svga.h"
c62d2810 36
37static void *desctable[8]={0,0,0,0,0,0,0,0};
38static int x;
39
892b1f6c 40/*
41typedef struct {
42 uint8 *data;
43 uint32 size;
44 uint32 location;
45} MEMWRAP;
46*/
c62d2810 47typedef struct {
48 uint8 *data;
49 uint32 size;
50 uint32 location;
51} ZIPWRAP;
892b1f6c 52#define MEMWRAP ZIPWRAP
53
54void ApplyIPS(FILE *ips, int destf)
55{
56 uint8 header[5];
57 uint32 count=0;
58 MEMWRAP *dest;
59
60 FCEU_printf(" Applying IPS...\n");
61 if(!(destf&0x8000))
62 {
63 FCEU_printf("failed (bad destf).\n");
64 return;
65 }
66
67 dest=(MEMWRAP*)desctable[(destf&255)-1];
68
69 if(fread(header,1,5,ips)!=5)
70 {
71 FCEU_printf("failed (bad header).\n");
72 fclose(ips);
73 return;
74 }
75 if(memcmp(header,"PATCH",5))
76 {
77 FCEU_printf("failed (bad header).\n");
78 fclose(ips);
79 return;
80 }
81
82 while(fread(header,1,3,ips)==3)
83 {
84 uint32 offset=(header[0]<<16)|(header[1]<<8)|header[2];
85 uint16 size;
86
87 if(!memcmp(header,"EOF",3))
88 {
89 FCEU_printf(" IPS EOF: Did %d patches\n\n",count);
90 fclose(ips);
91 return;
92 }
93
94 size=fgetc(ips)<<8;
95 size|=fgetc(ips);
96 if(!size) /* RLE */
97 {
98 uint8 *start;
99 uint8 b;
100 size=fgetc(ips)<<8;
101 size|=fgetc(ips);
102
103 //FCEU_printf(" Offset: %8d Size: %5d RLE\n",offset,size);
104
105 if((offset+size)>dest->size)
106 {
107 uint8 *tmp;
108
109 // Probably a little slow.
110 tmp=(uint8 *)realloc(dest->data,offset+size);
111 if(!tmp)
112 {
113 FCEU_printf(" Oops. IPS patch %d(type RLE) goes beyond end of file. Could not allocate memory.\n",count);
114 fclose(ips);
115 return;
116 }
117 dest->size=offset+size;
118 dest->data=tmp;
119 memset(dest->data+dest->size,0,offset+size-dest->size);
120 }
121 b=fgetc(ips);
122 start=dest->data+offset;
123 do
124 {
125 *start=b;
126 start++;
127 } while(--size);
128 }
129 else /* Normal patch */
130 {
131 //FCEU_printf(" Offset: %8d Size: %5d\n",offset,size);
132 if((offset+size)>dest->size)
133 {
134 uint8 *tmp;
135
136 // Probably a little slow.
137 tmp=(uint8 *)realloc(dest->data,offset+size);
138 if(!tmp)
139 {
140 FCEU_printf(" Oops. IPS patch %d(type normal) goes beyond end of file. Could not allocate memory.\n",count);
141 fclose(ips);
142 return;
143 }
144 dest->data=tmp;
145 memset(dest->data+dest->size,0,offset+size-dest->size);
146 }
147 fread(dest->data+offset,1,size,ips);
148 }
149 count++;
150 }
151 fclose(ips);
152 FCEU_printf(" Hard IPS end!\n");
153}
154
155
156#ifdef ZLIB
157
c62d2810 158
159void *MakeZipWrap(void *tz)
160{
161 unz_file_info ufo;
162 ZIPWRAP *tmp;
163
164 if(!(tmp=FCEU_malloc(sizeof(ZIPWRAP))))
165 goto doret;
c4980f9e 166
167 unzGetCurrentFileInfo(tz,&ufo,0,0,0,0,0,0);
c62d2810 168
169 tmp->location=0;
170 tmp->size=ufo.uncompressed_size;
171 if(!(tmp->data=FCEU_malloc(ufo.uncompressed_size)))
172 {
173 tmp=0;
174 goto doret;
175 }
176
177 unzReadCurrentFile(tz,tmp->data,ufo.uncompressed_size);
178
179 doret:
180
181 unzCloseCurrentFile(tz);
182 unzClose(tz);
c4980f9e 183
c62d2810 184 return tmp;
185}
186#endif
187
188#ifndef __GNUC__
189 #define strcasecmp strcmp
190#endif
191
192int FASTAPASS(2) FCEU_fopen(char *path, char *mode)
193{
194 void *t;
195
196 #ifdef ZLIB
197 unzFile tz;
198 if((tz=unzOpen(path))) // If it's not a zip file, use regular file handlers.
199 // Assuming file type by extension usually works,
200 // but I don't like it. :)
201 {
202 if(unzGoToFirstFile(tz)==UNZ_OK)
203 {
204 for(;;)
205 {
206 char tempu[512]; // Longer filenames might be possible, but I don't
207 // think people would name files that long in zip files...
208 unzGetCurrentFileInfo(tz,0,tempu,512,0,0,0,0);
209 tempu[511]=0;
210 if(strlen(tempu)>=4)
211 {
212 char *za=tempu+strlen(tempu)-4;
213 if(!strcasecmp(za,".nes") || !strcasecmp(za,".fds") ||
214 !strcasecmp(za,".nsf") || !strcasecmp(za,".unf") ||
215 !strcasecmp(za,".nez"))
216 break;
217 }
218 if(strlen(tempu)>=5)
219 {
220 if(!strcasecmp(tempu+strlen(tempu)-5,".unif"))
221 break;
222 }
223 if(unzGoToNextFile(tz)!=UNZ_OK)
c4980f9e 224 {
c62d2810 225 if(unzGoToFirstFile(tz)!=UNZ_OK) goto zpfail;
c4980f9e 226 break;
c62d2810 227 }
228 }
229 if(unzOpenCurrentFile(tz)!=UNZ_OK)
c4980f9e 230 goto zpfail;
c62d2810 231 }
232 else
233 {
234 zpfail:
235 unzClose(tz);
236 return 0;
237 }
238
239 for(x=0;x<8;x++)
240 if(!desctable[x])
241 {
242 if(!(desctable[x]=MakeZipWrap(tz)))
243 return(0);
244 return((x+1)|0x8000);
245 }
246 }
247#endif
248
249 #ifdef ZLIB
250 if((t=fopen(path,"rb")))
251 {
252 uint32 magic;
253
254 magic=fgetc(t);
255 magic|=fgetc(t)<<8;
256 magic|=fgetc(t)<<16;
257
258 fclose(t);
259
260 if(magic==0x088b1f)
261 {
262 if((t=gzopen(path,mode)))
263 for(x=0;x<8;x++)
264 if(!desctable[x])
265 {
266 desctable[x]=t;
267 return((x+1)|0x4000);
268 }
269 }
270 }
271 #endif
272
273 if((t=fopen(path,mode)))
274 {
275 fseek(t,0,SEEK_SET);
276 for(x=0;x<8;x++)
277 if(!desctable[x])
278 {
279 desctable[x]=t;
280 return(x+1);
281 }
282 }
283 return 0;
284}
285
892b1f6c 286int FASTAPASS(1) FCEU_fopen_forcemem(char *path)
287{
288 MEMWRAP *tmp;
289 long size;
290 int fp;
291
292 fp=FCEU_fopen(path, "rb");
293 if (!fp) return 0;
294
295 if (fp&0x8000) return fp;
296
297 if (!(tmp=FCEU_malloc(sizeof(*tmp))))
298 goto retr;
299
300 size=FCEU_fgetsize(fp);
301 if (size <= 0) goto retr;
302 tmp->size=size;
303 tmp->data=FCEU_malloc(size);
304 if (!tmp->data) goto retr;
305 FCEU_fread(tmp->data, 1, size, fp);
306 FCEU_fclose(fp); fp=0;
307 tmp->location=0;
308
309 for(x=0;x<8;x++)
310 if(!desctable[x])
311 {
312 desctable[x]=tmp;
313 return (x+1)|0x8000;
314 }
315
316 retr:
317 if (fp) FCEU_fclose(fp);
318 if (tmp && tmp->data) FCEU_free(tmp->data);
319 if (tmp) FCEU_free(tmp);
320 return 0;
321}
322
c62d2810 323int FASTAPASS(1) FCEU_fclose(int stream)
324{
325 #ifdef ZLIB
326 if(stream&0x4000)
327 {
328 gzclose(desctable[(stream&255)-1]);
329 desctable[(stream&255)-1]=0;
330 }
331 else if(stream&0x8000)
332 {
333 free(((ZIPWRAP*)desctable[(stream&255)-1])->data);
334 free(desctable[(stream&255)-1]);
335 desctable[(stream&255)-1]=0;
336 }
337 else // close zip file
338 {
339 #endif
340 fclose(desctable[stream-1]);
341 desctable[stream-1]=0;
342 #ifdef ZLIB
343 }
344 #endif
345 return 1;
346}
347
348size_t FASTAPASS(3) FCEU_fread(void *ptr, size_t size, size_t nmemb, int stream)
349{
350 #ifdef ZLIB
351 if(stream&0x4000)
352 {
353 return gzread(desctable[(stream&255)-1],ptr,size*nmemb);
354 }
355 else if(stream&0x8000)
c4980f9e 356 {
c62d2810 357 ZIPWRAP *wz;
358 uint32 total=size*nmemb;
359
360 wz=(ZIPWRAP*)desctable[(stream&255)-1];
361 if(wz->location>=wz->size) return 0;
362
363 if((wz->location+total)>wz->size)
364 {
365 int ak=wz->size-wz->location;
366 memcpy((uint8*)ptr,wz->data+wz->location,ak);
367 wz->location=wz->size;
368 return(ak/size);
369 }
370 else
371 {
372 memcpy((uint8*)ptr,wz->data+wz->location,total);
373 wz->location+=total;
374 return nmemb;
375 }
376 }
377 else
378 {
379 #endif
380 return fread(ptr,size,nmemb,desctable[stream-1]);
381 #ifdef ZLIB
382 }
383 #endif
384}
385
386size_t FASTAPASS(3) FCEU_fwrite(void *ptr, size_t size, size_t nmemb, int stream)
387{
388 #ifdef ZLIB
389 if(stream&0x4000)
390 {
391 return gzwrite(desctable[(stream&255)-1],ptr,size*nmemb);
392 }
393 else if(stream&0x8000)
c4980f9e 394 {
c62d2810 395 return 0;
396 }
397 else
398 #endif
399 return fwrite(ptr,size,nmemb,desctable[stream-1]);
400}
401
402int FASTAPASS(3) FCEU_fseek(int stream, long offset, int whence)
403{
404 #ifdef ZLIB
405 if(stream&0x4000)
406 {
407 return gzseek(desctable[(stream&255)-1],offset,whence);
c4980f9e 408 }
c62d2810 409 else if(stream&0x8000)
410 {
411 ZIPWRAP *wz;
412 wz=(ZIPWRAP*)desctable[(stream&255)-1];
413
414 switch(whence)
415 {
416 case SEEK_SET:if(offset>=wz->size)
417 return(-1);
418 wz->location=offset;break;
419 case SEEK_CUR:if(offset+wz->location>wz->size)
420 return (-1);
421 wz->location+=offset;
422 break;
c4980f9e 423 }
c62d2810 424 return 0;
425 }
426 else
427 #endif
428 return fseek(desctable[stream-1],offset,whence);
429}
430
431long FASTAPASS(1) FCEU_ftell(int stream)
432{
433 #ifdef ZLIB
434 if(stream&0x4000)
435 {
436 return gztell(desctable[(stream&255)-1]);
437 }
438 else if(stream&0x8000)
c4980f9e 439 {
440 return (((ZIPWRAP *)desctable[(stream&255)-1])->location);
c62d2810 441 }
442 else
443 #endif
444 return ftell(desctable[stream-1]);
445}
446
447void FASTAPASS(1)FCEU_rewind(int stream)
448{
449 #ifdef ZLIB
450 if(stream&0x4000)
451 {
452 gzrewind(desctable[(stream&255)-1]);
453 }
454 else if(stream&0x8000)
455 {
456 ((ZIPWRAP *)desctable[(stream&255)-1])->location=0;
457 }
458 else
459 #endif
460 #ifdef _WIN32_WCE
461 fseek(desctable[stream-1],0,SEEK_SET);
462 #else
463 rewind(desctable[stream-1]);
c4980f9e 464 #endif
c62d2810 465}
466
467int FASTAPASS(2) FCEU_read32(void *Bufo, int stream)
468{
469 #ifdef ZLIB
470 if(stream&0xC000)
c4980f9e 471 {
472 uint32 t;
c62d2810 473 #ifndef LSB_FIRST
474 uint8 x[4];
475 #endif
476 if(stream&0x8000)
c4980f9e 477 {
c62d2810 478 ZIPWRAP *wz;
479 wz=(ZIPWRAP*)desctable[(stream&255)-1];
480 if(wz->location+4>wz->size)
481 {return 0;}
c4980f9e 482 memcpy(&t, wz->data+wz->location, 4);
c62d2810 483 wz->location+=4;
484 }
485 else if(stream&0x4000)
486 gzread(desctable[(stream&255)-1],&t,4);
487 #ifndef LSB_FIRST
488 x[0]=t[3];
489 x[1]=t[2];
490 x[2]=t[1];
491 x[3]=t[0];
492 *(uint32*)Bufo=*(uint32*)x;
493 #else
c4980f9e 494 memcpy(Bufo, &t, 4);
c62d2810 495 #endif
496 return 1;
497 }
498 else
499 #endif
500 {
501 return read32(Bufo,desctable[stream-1]);
502 }
503}
504
505int FASTAPASS(1) FCEU_fgetc(int stream)
506{
507 #ifdef ZLIB
508 if(stream&0x4000)
c4980f9e 509 return gzgetc(desctable[(stream&255)-1]);
c62d2810 510 else if(stream&0x8000)
511 {
512 ZIPWRAP *wz;
513 wz=(ZIPWRAP*)desctable[(stream&255)-1];
514 if(wz->location<wz->size)
515 return wz->data[wz->location++];
516 return EOF;
517 }
518 else
519#endif
520 return fgetc(desctable[stream-1]);
521}
522
523long FASTAPASS(1) FCEU_fgetsize(int stream)
524{
525 #ifdef ZLIB
526 if(stream&0x4000)
527 {
528 int x,t;
529 t=gztell(desctable[(stream&255)-1]);
530 gzrewind(desctable[(stream&255)-1]);
531 for(x=0;gzgetc(desctable[(stream&255)-1]) != EOF; x++);
532 gzseek(desctable[(stream&255)-1],t,SEEK_SET);
533 return(x);
534 }
535 else if(stream&0x8000)
536 return ((ZIPWRAP*)desctable[(stream&255)-1])->size;
537 else
538 #endif
539 {
540 long t,r;
541 t=ftell(desctable[stream-1]);
542 fseek(desctable[stream-1],0,SEEK_END);
543 r=ftell(desctable[stream-1]);
544 fseek(desctable[stream-1],t,SEEK_SET);
545 return r;
546 }
547}
548
549int FASTAPASS(1) FCEU_fisarchive(int stream)
550{
551 #ifdef ZLIB
552 if(stream&0x8000)
553 return 1;
554 #endif
555 return 0;
556}