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 | |
37 | static void *desctable[8]={0,0,0,0,0,0,0,0}; |
38 | static int x; |
39 | |
892b1f6c |
40 | /* |
41 | typedef struct { |
42 | uint8 *data; |
43 | uint32 size; |
44 | uint32 location; |
45 | } MEMWRAP; |
46 | */ |
c62d2810 |
47 | typedef struct { |
48 | uint8 *data; |
49 | uint32 size; |
50 | uint32 location; |
51 | } ZIPWRAP; |
892b1f6c |
52 | #define MEMWRAP ZIPWRAP |
53 | |
54 | void 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 | |
159 | void *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 | |
192 | int 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 |
286 | int 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 |
323 | int 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 | |
348 | size_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 | |
386 | size_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 | |
402 | int 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 | |
431 | long 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 | |
447 | void 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 | |
467 | int 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 | |
505 | int 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 | |
523 | long 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 | |
549 | int FASTAPASS(1) FCEU_fisarchive(int stream) |
550 | { |
551 | #ifdef ZLIB |
552 | if(stream&0x8000) |
553 | return 1; |
554 | #endif |
555 | return 0; |
556 | } |