rel stuff
[fceu.git] / file.c
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
36 static void *desctable[8]={0,0,0,0,0,0,0,0};
37 static int x;
38
39 #ifdef ZLIB
40
41 typedef struct {
42            uint8 *data;
43            uint32 size;
44            uint32 location;
45 } ZIPWRAP;
46
47 void *MakeZipWrap(void *tz)
48 {
49  unz_file_info ufo;
50  ZIPWRAP *tmp;
51
52  if(!(tmp=FCEU_malloc(sizeof(ZIPWRAP))))
53   goto doret;
54  
55  unzGetCurrentFileInfo(tz,&ufo,0,0,0,0,0,0);  
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);
71  
72  return tmp;
73 }
74 #endif
75
76 #ifndef __GNUC__
77  #define strcasecmp strcmp
78 #endif
79
80 int 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)
112      { 
113       if(unzGoToFirstFile(tz)!=UNZ_OK) goto zpfail;
114       break;     
115      }
116     }
117     if(unzOpenCurrentFile(tz)!=UNZ_OK)
118      goto zpfail;       
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
174 int 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
199 size_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)
207  { 
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
237 size_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)
245  { 
246   return 0;
247  }
248  else
249  #endif
250   return fwrite(ptr,size,nmemb,desctable[stream-1]);
251 }
252
253 int 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);
259  } 
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;
274   }    
275   return 0;
276  }
277  else
278  #endif
279   return fseek(desctable[stream-1],offset,whence);
280 }
281
282 long 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)
290  { 
291   return (((ZIPWRAP *)desctable[(stream&255)-1])->location);  
292  }
293  else
294  #endif
295   return ftell(desctable[stream-1]);
296 }
297
298 void 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]);
315  #endif 
316 }
317
318 int FASTAPASS(2) FCEU_read32(void *Bufo, int stream)
319 {
320  #ifdef ZLIB
321  if(stream&0xC000)
322  { 
323   uint8 t[4];
324   #ifndef LSB_FIRST
325   uint8 x[4];
326   #endif
327   if(stream&0x8000)
328   { 
329    ZIPWRAP *wz;
330    wz=(ZIPWRAP*)desctable[(stream&255)-1];
331    if(wz->location+4>wz->size)
332     {return 0;}
333    *(uint32 *)t=*(uint32 *)(wz->data+wz->location);
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
345   *(uint32*)Bufo=*(uint32*)t;
346   #endif
347   return 1;
348  }
349  else
350  #endif
351  {
352   return read32(Bufo,desctable[stream-1]);
353  }
354 }
355
356 int FASTAPASS(1) FCEU_fgetc(int stream)
357 {
358  #ifdef ZLIB
359  if(stream&0x4000)
360   return gzgetc(desctable[(stream&255)-1]); 
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
374 long 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
400 int FASTAPASS(1) FCEU_fisarchive(int stream)
401 {
402  #ifdef ZLIB
403  if(stream&0x8000)
404   return 1;
405  #endif
406  return 0;
407 }