minor adjustments
[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"
35
36static void *desctable[8]={0,0,0,0,0,0,0,0};
37static int x;
38
39#ifdef ZLIB
40
41typedef struct {
42 uint8 *data;
43 uint32 size;
44 uint32 location;
45} ZIPWRAP;
46
47void *MakeZipWrap(void *tz)
48{
49 unz_file_info ufo;
50 ZIPWRAP *tmp;
51
52 if(!(tmp=FCEU_malloc(sizeof(ZIPWRAP))))
53 goto doret;
c4980f9e 54
55 unzGetCurrentFileInfo(tz,&ufo,0,0,0,0,0,0);
c62d2810 56
57 tmp->location=0;
58 tmp->size=ufo.uncompressed_size;
59 if(!(tmp->data=FCEU_malloc(ufo.uncompressed_size)))
60 {
61 tmp=0;
62 goto doret;
63 }
64
65 unzReadCurrentFile(tz,tmp->data,ufo.uncompressed_size);
66
67 doret:
68
69 unzCloseCurrentFile(tz);
70 unzClose(tz);
c4980f9e 71
c62d2810 72 return tmp;
73}
74#endif
75
76#ifndef __GNUC__
77 #define strcasecmp strcmp
78#endif
79
80int FASTAPASS(2) FCEU_fopen(char *path, char *mode)
81{
82 void *t;
83
84 #ifdef ZLIB
85 unzFile tz;
86 if((tz=unzOpen(path))) // If it's not a zip file, use regular file handlers.
87 // Assuming file type by extension usually works,
88 // but I don't like it. :)
89 {
90 if(unzGoToFirstFile(tz)==UNZ_OK)
91 {
92 for(;;)
93 {
94 char tempu[512]; // Longer filenames might be possible, but I don't
95 // think people would name files that long in zip files...
96 unzGetCurrentFileInfo(tz,0,tempu,512,0,0,0,0);
97 tempu[511]=0;
98 if(strlen(tempu)>=4)
99 {
100 char *za=tempu+strlen(tempu)-4;
101 if(!strcasecmp(za,".nes") || !strcasecmp(za,".fds") ||
102 !strcasecmp(za,".nsf") || !strcasecmp(za,".unf") ||
103 !strcasecmp(za,".nez"))
104 break;
105 }
106 if(strlen(tempu)>=5)
107 {
108 if(!strcasecmp(tempu+strlen(tempu)-5,".unif"))
109 break;
110 }
111 if(unzGoToNextFile(tz)!=UNZ_OK)
c4980f9e 112 {
c62d2810 113 if(unzGoToFirstFile(tz)!=UNZ_OK) goto zpfail;
c4980f9e 114 break;
c62d2810 115 }
116 }
117 if(unzOpenCurrentFile(tz)!=UNZ_OK)
c4980f9e 118 goto zpfail;
c62d2810 119 }
120 else
121 {
122 zpfail:
123 unzClose(tz);
124 return 0;
125 }
126
127 for(x=0;x<8;x++)
128 if(!desctable[x])
129 {
130 if(!(desctable[x]=MakeZipWrap(tz)))
131 return(0);
132 return((x+1)|0x8000);
133 }
134 }
135#endif
136
137 #ifdef ZLIB
138 if((t=fopen(path,"rb")))
139 {
140 uint32 magic;
141
142 magic=fgetc(t);
143 magic|=fgetc(t)<<8;
144 magic|=fgetc(t)<<16;
145
146 fclose(t);
147
148 if(magic==0x088b1f)
149 {
150 if((t=gzopen(path,mode)))
151 for(x=0;x<8;x++)
152 if(!desctable[x])
153 {
154 desctable[x]=t;
155 return((x+1)|0x4000);
156 }
157 }
158 }
159 #endif
160
161 if((t=fopen(path,mode)))
162 {
163 fseek(t,0,SEEK_SET);
164 for(x=0;x<8;x++)
165 if(!desctable[x])
166 {
167 desctable[x]=t;
168 return(x+1);
169 }
170 }
171 return 0;
172}
173
174int FASTAPASS(1) FCEU_fclose(int stream)
175{
176 #ifdef ZLIB
177 if(stream&0x4000)
178 {
179 gzclose(desctable[(stream&255)-1]);
180 desctable[(stream&255)-1]=0;
181 }
182 else if(stream&0x8000)
183 {
184 free(((ZIPWRAP*)desctable[(stream&255)-1])->data);
185 free(desctable[(stream&255)-1]);
186 desctable[(stream&255)-1]=0;
187 }
188 else // close zip file
189 {
190 #endif
191 fclose(desctable[stream-1]);
192 desctable[stream-1]=0;
193 #ifdef ZLIB
194 }
195 #endif
196 return 1;
197}
198
199size_t FASTAPASS(3) FCEU_fread(void *ptr, size_t size, size_t nmemb, int stream)
200{
201 #ifdef ZLIB
202 if(stream&0x4000)
203 {
204 return gzread(desctable[(stream&255)-1],ptr,size*nmemb);
205 }
206 else if(stream&0x8000)
c4980f9e 207 {
c62d2810 208 ZIPWRAP *wz;
209 uint32 total=size*nmemb;
210
211 wz=(ZIPWRAP*)desctable[(stream&255)-1];
212 if(wz->location>=wz->size) return 0;
213
214 if((wz->location+total)>wz->size)
215 {
216 int ak=wz->size-wz->location;
217 memcpy((uint8*)ptr,wz->data+wz->location,ak);
218 wz->location=wz->size;
219 return(ak/size);
220 }
221 else
222 {
223 memcpy((uint8*)ptr,wz->data+wz->location,total);
224 wz->location+=total;
225 return nmemb;
226 }
227 }
228 else
229 {
230 #endif
231 return fread(ptr,size,nmemb,desctable[stream-1]);
232 #ifdef ZLIB
233 }
234 #endif
235}
236
237size_t FASTAPASS(3) FCEU_fwrite(void *ptr, size_t size, size_t nmemb, int stream)
238{
239 #ifdef ZLIB
240 if(stream&0x4000)
241 {
242 return gzwrite(desctable[(stream&255)-1],ptr,size*nmemb);
243 }
244 else if(stream&0x8000)
c4980f9e 245 {
c62d2810 246 return 0;
247 }
248 else
249 #endif
250 return fwrite(ptr,size,nmemb,desctable[stream-1]);
251}
252
253int FASTAPASS(3) FCEU_fseek(int stream, long offset, int whence)
254{
255 #ifdef ZLIB
256 if(stream&0x4000)
257 {
258 return gzseek(desctable[(stream&255)-1],offset,whence);
c4980f9e 259 }
c62d2810 260 else if(stream&0x8000)
261 {
262 ZIPWRAP *wz;
263 wz=(ZIPWRAP*)desctable[(stream&255)-1];
264
265 switch(whence)
266 {
267 case SEEK_SET:if(offset>=wz->size)
268 return(-1);
269 wz->location=offset;break;
270 case SEEK_CUR:if(offset+wz->location>wz->size)
271 return (-1);
272 wz->location+=offset;
273 break;
c4980f9e 274 }
c62d2810 275 return 0;
276 }
277 else
278 #endif
279 return fseek(desctable[stream-1],offset,whence);
280}
281
282long FASTAPASS(1) FCEU_ftell(int stream)
283{
284 #ifdef ZLIB
285 if(stream&0x4000)
286 {
287 return gztell(desctable[(stream&255)-1]);
288 }
289 else if(stream&0x8000)
c4980f9e 290 {
291 return (((ZIPWRAP *)desctable[(stream&255)-1])->location);
c62d2810 292 }
293 else
294 #endif
295 return ftell(desctable[stream-1]);
296}
297
298void FASTAPASS(1)FCEU_rewind(int stream)
299{
300 #ifdef ZLIB
301 if(stream&0x4000)
302 {
303 gzrewind(desctable[(stream&255)-1]);
304 }
305 else if(stream&0x8000)
306 {
307 ((ZIPWRAP *)desctable[(stream&255)-1])->location=0;
308 }
309 else
310 #endif
311 #ifdef _WIN32_WCE
312 fseek(desctable[stream-1],0,SEEK_SET);
313 #else
314 rewind(desctable[stream-1]);
c4980f9e 315 #endif
c62d2810 316}
317
318int FASTAPASS(2) FCEU_read32(void *Bufo, int stream)
319{
320 #ifdef ZLIB
321 if(stream&0xC000)
c4980f9e 322 {
323 uint32 t;
c62d2810 324 #ifndef LSB_FIRST
325 uint8 x[4];
326 #endif
327 if(stream&0x8000)
c4980f9e 328 {
c62d2810 329 ZIPWRAP *wz;
330 wz=(ZIPWRAP*)desctable[(stream&255)-1];
331 if(wz->location+4>wz->size)
332 {return 0;}
c4980f9e 333 memcpy(&t, wz->data+wz->location, 4);
c62d2810 334 wz->location+=4;
335 }
336 else if(stream&0x4000)
337 gzread(desctable[(stream&255)-1],&t,4);
338 #ifndef LSB_FIRST
339 x[0]=t[3];
340 x[1]=t[2];
341 x[2]=t[1];
342 x[3]=t[0];
343 *(uint32*)Bufo=*(uint32*)x;
344 #else
c4980f9e 345 memcpy(Bufo, &t, 4);
c62d2810 346 #endif
347 return 1;
348 }
349 else
350 #endif
351 {
352 return read32(Bufo,desctable[stream-1]);
353 }
354}
355
356int FASTAPASS(1) FCEU_fgetc(int stream)
357{
358 #ifdef ZLIB
359 if(stream&0x4000)
c4980f9e 360 return gzgetc(desctable[(stream&255)-1]);
c62d2810 361 else if(stream&0x8000)
362 {
363 ZIPWRAP *wz;
364 wz=(ZIPWRAP*)desctable[(stream&255)-1];
365 if(wz->location<wz->size)
366 return wz->data[wz->location++];
367 return EOF;
368 }
369 else
370#endif
371 return fgetc(desctable[stream-1]);
372}
373
374long FASTAPASS(1) FCEU_fgetsize(int stream)
375{
376 #ifdef ZLIB
377 if(stream&0x4000)
378 {
379 int x,t;
380 t=gztell(desctable[(stream&255)-1]);
381 gzrewind(desctable[(stream&255)-1]);
382 for(x=0;gzgetc(desctable[(stream&255)-1]) != EOF; x++);
383 gzseek(desctable[(stream&255)-1],t,SEEK_SET);
384 return(x);
385 }
386 else if(stream&0x8000)
387 return ((ZIPWRAP*)desctable[(stream&255)-1])->size;
388 else
389 #endif
390 {
391 long t,r;
392 t=ftell(desctable[stream-1]);
393 fseek(desctable[stream-1],0,SEEK_END);
394 r=ftell(desctable[stream-1]);
395 fseek(desctable[stream-1],t,SEEK_SET);
396 return r;
397 }
398}
399
400int FASTAPASS(1) FCEU_fisarchive(int stream)
401{
402 #ifdef ZLIB
403 if(stream&0x8000)
404 return 1;
405 #endif
406 return 0;
407}