1 #include <stdint.h>
2 #include <sys/stat.h>
3 #include <unistd.h>
4 
5 #include "driver.h"
6 #include "unzip.h"
7 #include "../zlib/zlib.h"
8 #include "shared.h"
9 #include <file/file_path.h>
10 
11 /* Verbose outputs to error.log ? */
12 #define VERBOSE 	0
13 
14 /* Use the file cache ? */
15 #define FILE_CACHE	1
16 
17 #if VERBOSE
18 #define LOG(x)	logerror x
19 #else
20 #define LOG(x)	/* x */
21 #endif
22 
23 char *roms = NULL;
24 char **rompathv = NULL;
25 int rompathc = 0;
26 
27 char *samples = NULL;
28 char **samplepathv = NULL;
29 int samplepathc = 0;
30 
31 char *cfgdir, *nvdir, *hidir, *inpdir, *stadir;
32 char *memcarddir, *artworkdir, *screenshotdir;
33 char *cheatdir;	/* Steph */
34 
35 char *alternate_name;				   /* for "-romdir" */
36 
37 typedef enum
38 {
39 	kPlainFile,
40 	kRAMFile,
41 	kZippedFile
42 }	eFileType;
43 
44 typedef struct
45 {
46 	FILE *file;
47 	unsigned char *data;
48 	unsigned int offset;
49 	unsigned int length;
50 	eFileType type;
51 	unsigned int crc;
52 }	FakeFileHandle;
53 
54 //extern unsigned int crc32 (unsigned int crc, const unsigned char *buf, unsigned int len);
55 static int checksum_file (const char *file, unsigned char **p, unsigned int *size, unsigned int *crc);
56 
57 /*
58  * File stat cache LRU (Last Recently Used)
59  */
60 
61 #if FILE_CACHE
62 struct file_cache_entry
63 {
64 	struct stat stat_buffer;
65 	int result;
66 	char *file;
67 };
68 
69 /* File cache buffer */
70 static struct file_cache_entry **file_cache_map = 0;
71 
72 /* File cache size */
73 static unsigned int file_cache_max = 0;
74 
75 /* AM 980919 */
cache_stat(const char * path,struct stat * statbuf)76 static int cache_stat (const char *path, struct stat *statbuf)
77 {
78    if( file_cache_max )
79    {
80       unsigned i;
81       struct file_cache_entry *entry;
82 
83       /* search in the cache */
84       for( i = 0; i < file_cache_max; ++i )
85       {
86          if( file_cache_map[i]->file && strcmp (file_cache_map[i]->file, path) == 0 )
87          {
88             unsigned j;
89 
90 #if 0
91             /* found */
92             /* LOG(("File cache HIT  for %s\n", path)); */
93             /* store */
94 #endif
95             entry = file_cache_map[i];
96 
97             /* shift */
98             for( j = i; j > 0; --j )
99                file_cache_map[j] = file_cache_map[j - 1];
100 
101             /* set the first entry */
102             file_cache_map[0] = entry;
103 
104             if( entry->result == 0 )
105                memcpy (statbuf, &entry->stat_buffer, sizeof (struct stat));
106 
107             return entry->result;
108          }
109       }
110 
111 #if 0
112       LOG(("File cache FAIL for %s\n", path));
113 #endif
114 
115       /* oldest entry */
116       entry = file_cache_map[file_cache_max - 1];
117       free(entry->file);
118 
119       /* shift */
120       for( i = file_cache_max - 1; i > 0; --i )
121          file_cache_map[i] = file_cache_map[i - 1];
122 
123       /* set the first entry */
124       file_cache_map[0] = entry;
125 
126       /* file */
127       entry->file = (char *) malloc(strlen (path) + 1);
128       strcpy (entry->file, path);
129 
130       /* result and stat */
131       entry->result = stat (path, &entry->stat_buffer);
132 
133       if( entry->result == 0 )
134          memcpy (statbuf, &entry->stat_buffer, sizeof (struct stat));
135 
136       return entry->result;
137    }
138 
139    return stat (path, statbuf);
140 }
141 
142 /* AM 980919 */
cache_allocate(unsigned entries)143 static void cache_allocate (unsigned entries)
144 {
145 	if( entries )
146 	{
147 		unsigned i;
148 
149 		file_cache_max = entries;
150 		file_cache_map = (struct file_cache_entry **) malloc(file_cache_max * sizeof (struct file_cache_entry *));
151 
152 		for( i = 0; i < file_cache_max; ++i )
153 		{
154 			file_cache_map[i] = (struct file_cache_entry *) malloc(sizeof (struct file_cache_entry));
155 			memset (file_cache_map[i], 0, sizeof (struct file_cache_entry));
156 		}
157 		LOG(("File cache allocated for %d entries\n", file_cache_max));
158 	}
159 }
160 #else
161 
162 #define cache_stat(a,b) stat(a,b)
163 
164 #endif
165 
166 /* This function can be called several times with different parameters,
167  * for example by "mame -verifyroms *". */
decompose_rom_sample_path(char * rompath,char * samplepath)168 void decompose_rom_sample_path (char *rompath, char *samplepath)
169 {
170 	char *token;
171 
172 	/* start with zero path components */
173 	rompathc = samplepathc = 0;
174 
175 	if (!roms)
176 		roms = (char*)malloc( strlen(rompath) + 1);
177 	else
178 		roms = (char*)realloc( roms, strlen(rompath) + 1);
179 
180 	if (!samples)
181 		samples = (char*)malloc( strlen(samplepath) + 1);
182 	else
183 		samples = (char*)realloc( samples, strlen(samplepath) + 1);
184 
185 	if( !roms || !samples )
186 	{
187 		logerror("decompose_rom_sample_path: failed to malloc!\n");
188 #ifdef HAVE_SIGNALS
189 		raise(SIGABRT);
190 #endif
191 	}
192 
193 	strcpy (roms, rompath);
194 	token = strtok (roms, ";");
195 	while( token )
196 	{
197 		if( rompathc )
198 			rompathv = (char**)realloc(rompathv, (rompathc + 1) * sizeof(char *));
199 		else
200 			rompathv = (char**)malloc(sizeof(char *));
201 		if( !rompathv )
202 			break;
203 		rompathv[rompathc++] = token;
204 		token = strtok (NULL, ";");
205 	}
206 
207 	strcpy (samples, samplepath);
208 	token = strtok (samples, ";");
209 	while( token )
210 	{
211 		if( samplepathc )
212 			samplepathv = (char**)realloc(samplepathv, (samplepathc + 1) * sizeof(char *));
213 		else
214 			samplepathv = (char**)malloc(sizeof(char *));
215 		if( !samplepathv )
216 			break;
217 		samplepathv[samplepathc++] = token;
218 		token = strtok (NULL, ";");
219 	}
220 
221 #if FILE_CACHE
222     /* AM 980919 */
223     if( file_cache_max == 0 )
224     {
225         /* (rom path directories + 1 buffer)==rompathc+1 */
226         /* (dir + .zip + .zif)==3 */
227         /* (clone+parent)==2 */
228         cache_allocate ((rompathc + 1) * 3 * 2);
229     }
230 #endif
231 
232 }
233 
234 /*
235  * file handling routines
236  *
237  * gamename holds the driver name, filename is only used for ROMs and samples.
238  * if 'write' is not 0, the file is opened for write. Otherwise it is opened
239  * for read.
240  */
241 
242 /*
243  * check if roms/samples for a game exist at all
244  * return index+1 of the path vector component on success, otherwise 0
245  */
osd_faccess(const char * newfilename,int filetype)246 int osd_faccess (const char *newfilename, int filetype)
247 {
248    static int indx;
249    static const char *filename;
250    char name[256];
251    char **pathv;
252    int pathc;
253    char *dir_name;
254 
255 	/* if filename == NULL, continue the search */
256 	if( newfilename != NULL )
257 	{
258 		indx = 0;
259 		filename = newfilename;
260 	}
261 	else
262 		indx++;
263 
264 #ifdef MESS
265 	if(
266          filetype == OSD_FILETYPE_ROM ||
267          filetype == OSD_FILETYPE_IMAGE_R ||
268          filetype == OSD_FILETYPE_IMAGE_RW )
269 #else
270 	if( filetype == OSD_FILETYPE_ROM )
271 #endif
272 	{
273 		pathv = rompathv;
274 		pathc = rompathc;
275 	}
276 	else
277 	if( filetype == OSD_FILETYPE_SAMPLE )
278 	{
279 		pathv = samplepathv;
280 		pathc = samplepathc;
281 	}
282 	else
283 	if( filetype == OSD_FILETYPE_SCREENSHOT )
284 	{
285 		void *f = NULL;
286 		sprintf (name, "%s/%s.png", screenshotdir, newfilename);
287 		f = fopen (name, "rb");
288 		if( f )
289 		{
290 			fclose ((FILE*)f);
291 			return 1;
292 		}
293 
294       return 0;
295 	}
296 	else
297 		return 0;
298 
299 	for( ; indx < pathc; indx++ )
300 	{
301 		struct stat stat_buffer;
302 
303 		dir_name = pathv[indx];
304 
305 		/* does such a directory (or file) exist? */
306 		sprintf (name, "%s/%s", dir_name, filename);
307 		if( cache_stat (name, &stat_buffer) == 0 )
308 			return indx + 1;
309 
310 		/* try again with a .zip extension */
311 		sprintf (name, "%s/%s.zip", dir_name, filename);
312 		if( cache_stat (name, &stat_buffer) == 0 )
313 			return indx + 1;
314 
315 		/* try again with a .zif extension */
316 		sprintf (name, "%s/%s.zif", dir_name, filename);
317 		if( cache_stat (name, &stat_buffer) == 0 )
318 			return indx + 1;
319 	}
320 
321 	/* no match */
322 	return 0;
323 }
324 
325 
326 extern char slash;
327 #define PATHSEPCH slash
328 #define NO_ERROR (0)
329 
create_path_recursive(char * path)330 UINT32 create_path_recursive(char *path)
331 {
332 	char *sep = strrchr(path, PATHSEPCH);
333 	UINT32 filerr;
334 	struct stat st;
335 
336 	// if there's still a separator, and it's not the root, nuke it and recurse
337 	if (sep != NULL && sep > path && sep[0] != ':' && sep[-1] != PATHSEPCH)
338 	{
339 		*sep = 0;
340 		filerr = create_path_recursive(path);
341 		*sep = PATHSEPCH;
342 		if (filerr != NO_ERROR)
343 			return filerr;
344 	}
345 
346 	// if the path already exists, we're done
347 	if (!stat(path, &st))
348 		return NO_ERROR;
349 
350 	//printf("mkd(%s)\n",path);
351 	// create the path
352 	if (path_mkdir(path) != 1)
353 /*
354 	#ifdef WIN32
355 	if (mkdir(path) != 0)
356 	#else
357 	if (mkdir(path, 0777) != 0)
358 	#endif
359 */
360 		return -1;//errno;
361 
362 	return NO_ERROR;
363 }
364 
365 /* JB 980920 update */
366 /* AM 980919 update */
osd_fopen(const char * game,const char * filename,int filetype,int _write)367 void *osd_fopen (const char *game, const char *filename, int filetype, int _write)
368 {
369 	char name[256];
370 	char *gamename;
371 	int found = 0;
372 	int indx;
373 	struct stat stat_buffer;
374 	int pathc;
375 	char **pathv;
376 	FakeFileHandle *f = (FakeFileHandle *) malloc(sizeof (FakeFileHandle));
377 
378 	if( !f )
379 	{
380 		logerror("osd_fopen: failed to mallocFakeFileHandle!\n");
381         return 0;
382 	}
383 	memset (f, 0, sizeof (FakeFileHandle));
384 
385 	gamename = (char *) game;
386 
387 	/* Support "-romdir" yuck. */
388 	if( alternate_name )
389 	{
390 		LOG(("osd_fopen: -romdir overrides '%s' by '%s'\n", gamename, alternate_name));
391         gamename = alternate_name;
392 	}
393 
394 	switch( filetype )
395    {
396       case OSD_FILETYPE_ROM:
397       case OSD_FILETYPE_SAMPLE:
398 
399          /* only for reading */
400          if( _write )
401          {
402             logerror("osd_fopen: type %02x write not supported\n",filetype);
403             break;
404          }
405 
406          if( filetype == OSD_FILETYPE_SAMPLE )
407          {
408             LOG(("osd_fopen: using samplepath\n"));
409             pathc = samplepathc;
410             pathv = samplepathv;
411          }
412          else
413          {
414             LOG(("osd_fopen: using rompath\n"));
415             pathc = rompathc;
416             pathv = rompathv;
417          }
418 
419          for( indx = 0; indx < pathc && !found; ++indx )
420          {
421             const char *dir_name = pathv[indx];
422 
423             if( !found )
424             {
425                sprintf (name, "%s/%s", dir_name, gamename);
426                LOG(("Trying %s\n", name));
427                if( cache_stat (name, &stat_buffer) == 0 && (stat_buffer.st_mode & S_IFDIR) )
428                {
429                   sprintf (name, "%s/%s/%s", dir_name, gamename, filename);
430                   if( filetype == OSD_FILETYPE_ROM )
431                   {
432                      if( checksum_file (name, &f->data, &f->length, &f->crc) == 0 )
433                      {
434                         f->type = kRAMFile;
435                         f->offset = 0;
436                         found = 1;
437                      }
438                   }
439                   else
440                   {
441                      f->type = kPlainFile;
442                      f->file = fopen (name, "rb");
443                      found = f->file != 0;
444                   }
445                }
446             }
447 
448             if( !found )
449             {
450                /* try with a .zip extension */
451                sprintf (name, "%s/%s.zip", dir_name, gamename);
452                LOG(("Trying %s file\n", name));
453                if( cache_stat (name, &stat_buffer) == 0 )
454                {
455                   if( load_zipped_file (name, filename, &f->data, &f->length) == 0 )
456                   {
457                      LOG(("Using (osd_fopen) zip file for %s\n", filename));
458                      f->type = kZippedFile;
459                      f->offset = 0;
460                      f->crc = crc32 (0L, f->data, f->length);
461                      found = 1;
462                   }
463                }
464             }
465 
466             if( !found )
467             {
468                /* try with a .zip directory (if ZipMagic is installed) */
469                sprintf (name, "%s/%s.zip", dir_name, gamename);
470                LOG(("Trying %s directory\n", name));
471                if( cache_stat (name, &stat_buffer) == 0 && (stat_buffer.st_mode & S_IFDIR) )
472                {
473                   sprintf (name, "%s/%s.zip/%s", dir_name, gamename, filename);
474                   if( filetype == OSD_FILETYPE_ROM )
475                   {
476                      if( checksum_file (name, &f->data, &f->length, &f->crc) == 0 )
477                      {
478                         f->type = kRAMFile;
479                         f->offset = 0;
480                         found = 1;
481                      }
482                   }
483                   else
484                   {
485                      f->type = kPlainFile;
486                      f->file = fopen (name, "rb");
487                      found = f->file != 0;
488                   }
489                }
490             }
491          }
492 
493          break;
494 
495 #ifdef MESS
496       case OSD_FILETYPE_IMAGE_R:
497 
498          /* only for reading */
499          if( _write )
500          {
501             logerror("osd_fopen: type %02x write not supported\n",filetype);
502             break;
503          }
504          else
505          {
506             LOG(("osd_fopen: using rompath\n"));
507             pathc = rompathc;
508             pathv = rompathv;
509          }
510 
511          LOG(("Open IMAGE_R '%s' for %s\n", filename, game));
512          for( indx = 0; indx < pathc && !found; ++indx )
513          {
514             const char *dir_name = pathv[indx];
515 
516             /* this section allows exact path from .cfg */
517             if( !found )
518             {
519                sprintf(name,"%s",dir_name);
520                if( cache_stat(name,&stat_buffer) == 0 && (stat_buffer.st_mode & S_IFDIR) )
521                {
522                   sprintf(name,"%s/%s",dir_name,filename);
523                   if( filetype == OSD_FILETYPE_ROM )
524                   {
525                      if( checksum_file (name, &f->data, &f->length, &f->crc) == 0 )
526                      {
527                         f->type = kRAMFile;
528                         f->offset = 0;
529                         found = 1;
530                      }
531                   }
532                   else
533                   {
534                      f->type = kPlainFile;
535                      f->file = fopen(name,"rb");
536                      found = f->file!=0;
537                   }
538                }
539             }
540 
541             if( !found )
542             {
543                sprintf (name, "%s/%s", dir_name, gamename);
544                LOG(("Trying %s directory\n", name));
545                if( cache_stat (name, &stat_buffer) == 0 && (stat_buffer.st_mode & S_IFDIR) )
546                {
547                   sprintf (name, "%s/%s/%s", dir_name, gamename, filename);
548                   LOG(("Trying %s file\n", name));
549                   if( filetype == OSD_FILETYPE_ROM )
550                   {
551                      if( checksum_file(name, &f->data, &f->length, &f->crc) == 0 )
552                      {
553                         f->type = kRAMFile;
554                         f->offset = 0;
555                         found = 1;
556                      }
557                   }
558                   else
559                   {
560                      f->type = kPlainFile;
561                      f->file = fopen (name, "rb");
562                      found = f->file != 0;
563                   }
564                }
565             }
566 
567             /* Zip cart support for MESS */
568             if( !found && filetype == OSD_FILETYPE_IMAGE_R )
569             {
570                char *extension = strrchr (name, '.');    /* find extension */
571                if( extension )
572                   strcpy (extension, ".zip");
573                else
574                   strcat (name, ".zip");
575                LOG(("Trying %s file\n", name));
576                if( cache_stat(name, &stat_buffer) == 0 )
577                {
578                   if( load_zipped_file(name, filename, &f->data, &f->length) == 0 )
579                   {
580                      LOG(("Using (osd_fopen) zip file for %s\n", filename));
581                      f->type = kZippedFile;
582                      f->offset = 0;
583                      f->crc = crc32 (0L, f->data, f->length);
584                      found = 1;
585                   }
586                }
587             }
588 
589             if( !found )
590             {
591                /* try with a .zip extension */
592                sprintf (name, "%s/%s.zip", dir_name, gamename);
593                LOG(("Trying %s file\n", name));
594                if( cache_stat(name, &stat_buffer) == 0 )
595                {
596                   if( load_zipped_file(name, filename, &f->data, &f->length) == 0 )
597                   {
598                      LOG(("Using (osd_fopen) zip file for %s\n", filename));
599                      f->type = kZippedFile;
600                      f->offset = 0;
601                      f->crc = crc32 (0L, f->data, f->length);
602                      found = 1;
603                   }
604                }
605             }
606          }
607          break; /* end of IMAGE_R */
608 
609       case OSD_FILETYPE_IMAGE_RW:
610          {
611             static char *write_modes[] = {"rb","wb","r+b","r+b","w+b"};
612             char file[256];
613             char *extension;
614 
615             LOG(("Open IMAGE_RW '%s' for %s mode '%s'\n", filename, game, write_modes[_write]));
616             strcpy (file, filename);
617 
618             do
619             {
620                /* 29-05-00 Lee Ward: Reversed the search order. */
621                for (indx=rompathc-1; indx>=0; --indx)
622                {
623                   const char *dir_name = rompathv[indx];
624 
625                   /* Exact path support */
626 
627                   /* 29-05-00 Lee Ward: Changed the search order to prevent new files
628                      being created in the application root as default */
629 
630                   if( !found )
631                   {
632                      sprintf (name, "%s/%s", dir_name, gamename);
633                      LOG(("Trying %s directory\n", name));
634                      if( cache_stat(name, &stat_buffer) == 0 && (stat_buffer.st_mode & S_IFDIR) )
635                      {
636                         sprintf (name, "%s/%s/%s", dir_name, gamename, file);
637                         LOG(("Trying %s file\n", name));
638                         f->file = fopen (name, write_modes[_write]);
639                         found = f->file != 0;
640                         if( !found && _write == 3 )
641                         {
642                            f->file = fopen(name, write_modes[4]);
643                            found = f->file != 0;
644                         }
645                      }
646                   }
647 
648                   /* Steph - Zip disk images support for MESS */
649                   if( !found && !_write )
650                   {
651                      extension = strrchr (name, '.');    /* find extension */
652                      /* add .zip for zipfile */
653                      if( extension )
654                         strcpy(extension, ".zip");
655                      else
656                         strcat(extension, ".zip");
657                      LOG(("Trying %s file\n", name));
658                      if( cache_stat(name, &stat_buffer) == 0 )
659                      {
660                         if( load_zipped_file(name, filename, &f->data, &f->length) == 0 )
661                         {
662                            LOG(("Using (osd_fopen) zip file for %s\n", filename));
663                            f->type = kZippedFile;
664                            f->offset = 0;
665                            f->crc = crc32(0L, f->data, f->length);
666                            found = 1;
667                         }
668                      }
669                   }
670 
671                   if (!found)
672                   {
673                      sprintf(name, "%s", dir_name);
674                      LOG(("Trying %s directory\n", name));
675                      if( cache_stat(name,&stat_buffer) == 0 && (stat_buffer.st_mode & S_IFDIR) )
676                      {
677                         sprintf(name,"%s/%s", dir_name, file);
678                         LOG(("Trying %s file\n", name));
679                         f->file = fopen(name, write_modes[_write]);
680                         found = f->file != 0;
681                         if( !found && _write == 3 )
682                         {
683                            f->file = fopen(name, write_modes[4]);
684                            found = f->file != 0;
685                         }
686                      }
687                   }
688 
689                   if( !found && !_write )
690                   {
691                      extension = strrchr (name, '.');    /* find extension */
692                      /* add .zip for zipfile */
693                      if( extension )
694                         strcpy(extension, ".zip");
695                      else
696                         strcat(extension, ".zip");
697                      LOG(("Trying %s file\n", name));
698                      if( cache_stat(name, &stat_buffer) == 0 )
699                      {
700                         if( load_zipped_file(name, filename, &f->data, &f->length) == 0 )
701                         {
702                            LOG(("Using (osd_fopen) zip file for %s\n", filename));
703                            f->type = kZippedFile;
704                            f->offset = 0;
705                            f->crc = crc32(0L, f->data, f->length);
706                            found = 1;
707                         }
708                      }
709                   }
710 
711                   if( !found && !_write )
712                   {
713                      /* try with a .zip extension */
714                      sprintf (name, "%s/%s.zip", dir_name, gamename);
715                      LOG(("Trying %s file\n", name));
716                      if( cache_stat (name, &stat_buffer) == 0 )
717                      {
718                         if( load_zipped_file (name, file, &f->data, &f->length) == 0 )
719                         {
720                            LOG(("Using (osd_fopen) zip file for %s\n", filename));
721                            f->type = kZippedFile;
722                            f->offset = 0;
723                            f->crc = crc32 (0L, f->data, f->length);
724                            found = 1;
725                         }
726                      }
727                   }
728 
729                   if( !found )
730                   {
731                      /* try with a .zip directory (if ZipMagic is installed) */
732                      sprintf (name, "%s/%s.zip", dir_name, gamename);
733                      LOG(("Trying %s ZipMagic directory\n", name));
734                      if( cache_stat (name, &stat_buffer) == 0 && (stat_buffer.st_mode & S_IFDIR) )
735                      {
736                         sprintf (name, "%s/%s.zip/%s", dir_name, gamename, file);
737                         LOG(("Trying %s\n", name));
738                         f->file = fopen (name, write_modes[_write]);
739                         found = f->file != 0;
740                         if( !found && _write == 3 )
741                         {
742                            f->file = fopen(name, write_modes[4]);
743                            found = f->file != 0;
744                         }
745                      }
746                   }
747                   if( found )
748                      LOG(("IMAGE_RW %s FOUND in %s!\n", file, name));
749                }
750 
751                extension = strrchr (file, '.');
752                if( extension )
753                   *extension = '\0';
754             } while( !found && extension );
755          }
756          break;
757 #endif	/* MESS */
758 
759 
760       case OSD_FILETYPE_NVRAM:
761          if( !found )
762          {
763             sprintf (name, "%s/%s.nv", nvdir, gamename);
764             f->type = kPlainFile;
765             f->file = fopen (name, _write ? "wb" : "rb");
766             found = f->file != 0;
767          }
768 
769          if( !found )
770          {
771             /* try with a .zip directory (if ZipMagic is installed) */
772             sprintf (name, "%s.zip/%s.nv", nvdir, gamename);
773             f->type = kPlainFile;
774             f->file = fopen (name, _write ? "wb" : "rb");
775             found = f->file != 0;
776          }
777 
778          if( !found )
779          {
780             /* try with a .zif directory (if ZipFolders is installed) */
781             sprintf (name, "%s.zif/%s.nv", nvdir, gamename);
782             f->type = kPlainFile;
783             f->file = fopen (name, _write ? "wb" : "rb");
784             found = f->file != 0;
785          }
786          break;
787 
788       case OSD_FILETYPE_HIGHSCORE:
789          if( mame_highscore_enabled () )
790          {
791             if( !found )
792             {
793                sprintf (name, "%s/%s.hi", hidir, gamename);
794                f->type = kPlainFile;
795                f->file = fopen (name, _write ? "wb" : "rb");
796                found = f->file != 0;
797             }
798 
799             if( !found )
800             {
801                /* try with a .zip directory (if ZipMagic is installed) */
802                sprintf (name, "%s.zip/%s.hi", hidir, gamename);
803                f->type = kPlainFile;
804                f->file = fopen (name, _write ? "wb" : "rb");
805                found = f->file != 0;
806             }
807 
808             if( !found )
809             {
810                /* try with a .zif directory (if ZipFolders is installed) */
811                sprintf (name, "%s.zif/%s.hi", hidir, gamename);
812                f->type = kPlainFile;
813                f->file = fopen (name, _write ? "wb" : "rb");
814                found = f->file != 0;
815             }
816          }
817          break;
818 
819       case OSD_FILETYPE_CONFIG:
820          sprintf (name, "%s/%s.cfg", cfgdir, gamename);
821          f->type = kPlainFile;
822          f->file = fopen (name, _write ? "wb" : "rb");
823          found = f->file != 0;
824 
825          if( !found )
826          {
827             /* try with a .zip directory (if ZipMagic is installed) */
828             sprintf (name, "%s.zip/%s.cfg", cfgdir, gamename);
829             f->type = kPlainFile;
830             f->file = fopen (name, _write ? "wb" : "rb");
831             found = f->file != 0;
832          }
833 
834          if( !found )
835          {
836             /* try with a .zif directory (if ZipFolders is installed) */
837             sprintf (name, "%s.zif/%s.cfg", cfgdir, gamename);
838             f->type = kPlainFile;
839             f->file = fopen (name, _write ? "wb" : "rb");
840             found = f->file != 0;
841          }
842          break;
843 
844       case OSD_FILETYPE_INPUTLOG:
845          sprintf (name, "%s/%s.inp", inpdir, gamename);
846          f->type = kPlainFile;
847          f->file = fopen (name, _write ? "wb" : "rb");
848          found = f->file != 0;
849 
850          if( !found )
851          {
852             /* try with a .zip directory (if ZipMagic is installed) */
853             sprintf (name, "%s.zip/%s.cfg", inpdir, gamename);
854             f->type = kPlainFile;
855             f->file = fopen (name, _write ? "wb" : "rb");
856             found = f->file != 0;
857          }
858 
859          if( !found )
860          {
861             /* try with a .zif directory (if ZipFolders is installed) */
862             sprintf (name, "%s.zif/%s.cfg", inpdir, gamename);
863             f->type = kPlainFile;
864             f->file = fopen (name, _write ? "wb" : "rb");
865             found = f->file != 0;
866          }
867 
868          if( !_write )
869          {
870             char file[256];
871             sprintf (file, "%s.inp", gamename);
872             sprintf (name, "%s/%s.zip", inpdir, gamename);
873             LOG(("Trying %s in %s\n", file, name));
874             if( cache_stat (name, &stat_buffer) == 0 )
875             {
876                if( load_zipped_file (name, file, &f->data, &f->length) == 0 )
877                {
878                   LOG(("Using (osd_fopen) zip file %s for %s\n", name, file));
879                   f->type = kZippedFile;
880                   f->offset = 0;
881                   found = 1;
882                }
883             }
884          }
885 
886          break;
887 
888       case OSD_FILETYPE_STATE:
889          sprintf (name, "%s/%s.sta", stadir, gamename);
890          f->file = fopen (name, _write ? "wb" : "rb");
891          found = !(f->file == 0);
892          if( !found )
893          {
894             /* try with a .zip directory (if ZipMagic is installed) */
895             sprintf (name, "%s.zip/%s.sta", stadir, gamename);
896             f->file = fopen (name, _write ? "wb" : "rb");
897             found = !(f->file == 0);
898          }
899          if( !found )
900          {
901             /* try with a .zif directory (if ZipFolders is installed) */
902             sprintf (name, "%s.zif/%s.sta", stadir, gamename);
903             f->file = fopen (name, _write ? "wb" : "rb");
904             found = !(f->file == 0);
905          }
906          break;
907 
908       case OSD_FILETYPE_ARTWORK:
909          /* only for reading */
910          if( _write )
911          {
912             logerror("osd_fopen: type %02x write not supported\n",filetype);
913             break;
914          }
915          sprintf (name, "%s/%s", artworkdir, filename);
916          f->type = kPlainFile;
917          f->file = fopen (name, _write ? "wb" : "rb");
918          found = f->file != 0;
919          if( !found )
920          {
921             /* try with a .zip directory (if ZipMagic is installed) */
922             sprintf (name, "%s.zip/%s.png", artworkdir, filename);
923             f->type = kPlainFile;
924             f->file = fopen (name, _write ? "wb" : "rb");
925             found = f->file != 0;
926          }
927 
928          if( !found )
929          {
930             /* try with a .zif directory (if ZipFolders is installed) */
931             sprintf (name, "%s.zif/%s.png", artworkdir, filename);
932             f->type = kPlainFile;
933             f->file = fopen (name, _write ? "wb" : "rb");
934             found = f->file != 0;
935          }
936 
937          if( !found )
938          {
939             char file[256], *extension;
940             sprintf(file, "%s", filename);
941             sprintf(name, "%s/%s", artworkdir, filename);
942             extension = strrchr(name, '.');
943             if( extension )
944                strcpy (extension, ".zip");
945             else
946                strcat (name, ".zip");
947             LOG(("Trying %s in %s\n", file, name));
948             if( cache_stat (name, &stat_buffer) == 0 )
949             {
950                if( load_zipped_file (name, file, &f->data, &f->length) == 0 )
951                {
952                   LOG(("Using (osd_fopen) zip file %s\n", name));
953                   f->type = kZippedFile;
954                   f->offset = 0;
955                   found = 1;
956                }
957             }
958             if( !found )
959             {
960                sprintf(name, "%s/%s.zip", artworkdir, game);
961                LOG(("Trying %s in %s\n", file, name));
962                if( cache_stat (name, &stat_buffer) == 0 )
963                {
964                   if( load_zipped_file (name, file, &f->data, &f->length) == 0 )
965                   {
966                      LOG(("Using (osd_fopen) zip file %s\n", name));
967                      f->type = kZippedFile;
968                      f->offset = 0;
969                      found = 1;
970                   }
971                }
972             }
973          }
974          break;
975 
976       case OSD_FILETYPE_MEMCARD:
977          sprintf (name, "%s/%s", memcarddir, filename);
978          f->type = kPlainFile;
979          f->file = fopen (name, _write ? "wb" : "rb");
980          found = f->file != 0;
981          break;
982 
983       case OSD_FILETYPE_SCREENSHOT:
984          /* only for writing */
985          if( !_write )
986          {
987             logerror("osd_fopen: type %02x read not supported\n",filetype);
988             break;
989          }
990 
991          sprintf (name, "%s/%s.png", screenshotdir, filename);
992          f->type = kPlainFile;
993          f->file = fopen (name, _write ? "wb" : "rb");
994          found = f->file != 0;
995          break;
996 
997       case OSD_FILETYPE_HIGHSCORE_DB:
998       case OSD_FILETYPE_HISTORY:
999          /* only for reading */
1000          sprintf (name, "%s/%s", IMAMEBASEPATH, filename);//FIX Seleuco
1001          if( _write )
1002          {
1003             logerror("osd_fopen: type %02x write not supported\n",filetype);
1004             break;
1005          }
1006          f->type = kPlainFile;
1007          /* open as ASCII files, not binary like the others */
1008          f->file = fopen (name/*filename*/, _write ? "w" : "r");//FIX Seleuco
1009          found = f->file != 0;
1010          break;
1011 
1012          /* Steph */
1013       case OSD_FILETYPE_CHEAT:
1014          sprintf (name, "%s/%s", cheatdir, filename);
1015          f->type = kPlainFile;
1016          /* open as ASCII files, not binary like the others */
1017          f->file = fopen (/*filename*/name, _write ? "a" : "r");//FIX Seleuco
1018          found = f->file != 0;
1019          break;
1020 
1021       case OSD_FILETYPE_LANGUAGE:
1022          /* only for reading */
1023          if( _write )
1024          {
1025             logerror("osd_fopen: type %02x write not supported\n",filetype);
1026             break;
1027          }
1028          sprintf (name, "%s.lng", filename);
1029          f->type = kPlainFile;
1030          /* open as ASCII files, not binary like the others */
1031          f->file = fopen (name, _write ? "w" : "r");
1032          found = f->file != 0;
1033          logerror("fopen %s = %08x\n",name,(intptr_t)f->file);
1034          break;
1035 
1036       default:
1037          logerror("osd_fopen(): unknown filetype %02x\n",filetype);
1038    }
1039 
1040 	if( !found )
1041 	{
1042 		free(f);
1043 		return 0;
1044 	}
1045 
1046 	return f;
1047 }
1048 
1049 /* JB 980920 update */
osd_fread(void * file,void * buffer,int length)1050 int osd_fread (void *file, void *buffer, int length)
1051 {
1052    FakeFileHandle *f = (FakeFileHandle *) file;
1053 
1054    switch( f->type )
1055    {
1056       case kPlainFile:
1057          return fread (buffer, 1, length, f->file);
1058       case kZippedFile:
1059       case kRAMFile:
1060          /* reading from the RAM image of a file */
1061          if( f->data )
1062          {
1063             if( length + f->offset > f->length )
1064                length = f->length - f->offset;
1065             memcpy (buffer, f->offset + f->data, length);
1066             f->offset += length;
1067             return length;
1068          }
1069          break;
1070    }
1071 
1072    return 0;
1073 }
1074 
osd_fread_swap(void * file,void * buffer,int length)1075 int osd_fread_swap (void *file, void *buffer, int length)
1076 {
1077 	int i;
1078 	unsigned char temp;
1079 	int res = osd_fread (file, buffer, length);
1080 	unsigned char *buf = (unsigned char*)buffer;
1081 
1082 	for( i = 0; i < length; i += 2 )
1083 	{
1084 		temp = buf[i];
1085 		buf[i] = buf[i + 1];
1086 		buf[i + 1] = temp;
1087 	}
1088 
1089 	return res;
1090 }
1091 
1092 
1093 /* AM 980919 update */
osd_fwrite(void * file,const void * buffer,int length)1094 int osd_fwrite (void *file, const void *buffer, int length)
1095 {
1096 	FakeFileHandle *f = (FakeFileHandle *) file;
1097 
1098 	switch( f->type )
1099    {
1100       case kPlainFile:
1101          return fwrite (buffer, 1, length, ((FakeFileHandle *) file)->file);
1102       default:
1103          break;
1104    }
1105 
1106    return 0;
1107 }
1108 
osd_fwrite_swap(void * file,const void * buffer,int length)1109 int osd_fwrite_swap (void *file, const void *buffer, int length)
1110 {
1111 	int i;
1112 	int res;
1113 	unsigned char temp;
1114 	unsigned char *buf = (unsigned char *) buffer;
1115 
1116 	for( i = 0; i < length; i += 2 )
1117 	{
1118 		temp = buf[i];
1119 		buf[i] = buf[i + 1];
1120 		buf[i + 1] = temp;
1121 	}
1122 
1123 	res = osd_fwrite (file, buffer, length);
1124 
1125 	for( i = 0; i < length; i += 2 )
1126 	{
1127 		temp = buf[i];
1128 		buf[i] = buf[i + 1];
1129 		buf[i + 1] = temp;
1130 	}
1131 
1132 	return res;
1133 }
1134 
osd_fread_scatter(void * file,void * buffer,int length,int increment)1135 int osd_fread_scatter (void *file, void *buffer, int length, int increment)
1136 {
1137 	unsigned char *buf = (unsigned char*)buffer;
1138 	FakeFileHandle *f = (FakeFileHandle *) file;
1139 	unsigned char tempbuf[4096];
1140 	int totread, r, i;
1141 
1142 	switch( f->type )
1143    {
1144       case kPlainFile:
1145          totread = 0;
1146          while (length)
1147          {
1148             r = length;
1149             if( r > 4096 )
1150                r = 4096;
1151             r = fread (tempbuf, 1, r, f->file);
1152             if( r == 0 )
1153                return totread;		   /* error */
1154             for( i = 0; i < r; i++ )
1155             {
1156                *buf = tempbuf[i];
1157                buf += increment;
1158             }
1159             totread += r;
1160             length -= r;
1161          }
1162          return totread;
1163       case kZippedFile:
1164       case kRAMFile:
1165          /* reading from the RAM image of a file */
1166          if( f->data )
1167          {
1168             if( length + f->offset > f->length )
1169                length = f->length - f->offset;
1170             for( i = 0; i < length; i++ )
1171             {
1172                *buf = f->data[f->offset + i];
1173                buf += increment;
1174             }
1175             f->offset += length;
1176             return length;
1177          }
1178          break;
1179    }
1180 
1181 	return 0;
1182 }
1183 
1184 
1185 /* JB 980920 update */
osd_fseek(void * file,int offset,int whence)1186 int osd_fseek (void *file, int offset, int whence)
1187 {
1188 	FakeFileHandle *f = (FakeFileHandle *) file;
1189 	int err = 0;
1190 
1191 	switch( f->type )
1192    {
1193       case kPlainFile:
1194          return fseek (f->file, offset, whence);
1195       case kZippedFile:
1196       case kRAMFile:
1197          /* seeking within the RAM image of a file */
1198          switch( whence )
1199          {
1200             case SEEK_SET:
1201                f->offset = offset;
1202                break;
1203             case SEEK_CUR:
1204                f->offset += offset;
1205                break;
1206             case SEEK_END:
1207                f->offset = f->length + offset;
1208                break;
1209          }
1210          break;
1211    }
1212 
1213 	return err;
1214 }
1215 
1216 /* JB 980920 update */
osd_fclose(void * file)1217 void osd_fclose (void *file)
1218 {
1219    FakeFileHandle *f = (FakeFileHandle *) file;
1220 
1221    switch( f->type )
1222    {
1223       case kPlainFile:
1224          fclose (f->file);
1225          break;
1226       case kZippedFile:
1227       case kRAMFile:
1228          if( f->data )
1229             free(f->data);
1230          break;
1231    }
1232    free(f);
1233 }
1234 
1235 /* JB 980920 update */
1236 /* AM 980919 */
checksum_file(const char * file,unsigned char ** p,unsigned int * size,unsigned int * crc)1237 static int checksum_file (const char *file, unsigned char **p, unsigned int *size, unsigned int *crc)
1238 {
1239    int length;
1240    unsigned char *data;
1241    FILE *f = fopen (file, "rb");
1242 
1243    if( !f )
1244       return -1;
1245 
1246    /* determine length of file */
1247    if( fseek (f, 0L, SEEK_END) != 0 )
1248    {
1249       fclose (f);
1250       return -1;
1251    }
1252 
1253    length = ftell (f);
1254    if( length == -1L )
1255    {
1256       fclose (f);
1257       return -1;
1258    }
1259 
1260    /* allocate space for entire file */
1261    data = (unsigned char *) malloc(length);
1262    if( !data )
1263    {
1264       fclose (f);
1265       return -1;
1266    }
1267 
1268    /* read entire file into memory */
1269    if( fseek (f, 0L, SEEK_SET) != 0 )
1270    {
1271       free(data);
1272       fclose (f);
1273       return -1;
1274    }
1275 
1276    if( fread (data, sizeof (unsigned char), length, f) != length )
1277    {
1278       free(data);
1279       fclose (f);
1280       return -1;
1281    }
1282 
1283    *size = length;
1284    *crc = crc32 (0L, data, length);
1285    if( p )
1286       *p = data;
1287    else
1288       free(data);
1289 
1290    fclose (f);
1291 
1292    return 0;
1293 }
1294 
1295 /* JB 980920 updated */
1296 /* AM 980919 updated */
osd_fchecksum(const char * game,const char * filename,unsigned int * length,unsigned int * sum)1297 int osd_fchecksum (const char *game, const char *filename, unsigned int *length, unsigned int *sum)
1298 {
1299 	char name[256];
1300 	int indx;
1301 	struct stat stat_buffer;
1302 	int found = 0;
1303 	const char *gamename = game;
1304 
1305 	/* Support "-romdir" yuck. */
1306 	if( alternate_name )
1307 		gamename = alternate_name;
1308 
1309 	for( indx = 0; indx < rompathc && !found; ++indx )
1310 	{
1311 		const char *dir_name = rompathv[indx];
1312 
1313 		if( !found )
1314 		{
1315 			sprintf (name, "%s/%s", dir_name, gamename);
1316 			if( cache_stat (name, &stat_buffer) == 0 && (stat_buffer.st_mode & S_IFDIR) )
1317 			{
1318 				sprintf (name, "%s/%s/%s", dir_name, gamename, filename);
1319 				if( checksum_file (name, 0, length, sum) == 0 )
1320                 {
1321 					found = 1;
1322                 }
1323 			}
1324 		}
1325 
1326 		if( !found )
1327 		{
1328 			/* try with a .zip extension */
1329 			sprintf (name, "%s/%s.zip", dir_name, gamename);
1330 			if( cache_stat (name, &stat_buffer) == 0 )
1331 			{
1332 				if( checksum_zipped_file (name, filename, length, sum) == 0 )
1333 				{
1334 					LOG(("Using (osd_fchecksum) zip file for %s\n", filename));
1335 					found = 1;
1336 				}
1337 			}
1338 		}
1339 
1340 		if( !found )
1341 		{
1342 			/* try with a .zif directory (if ZipFolders is installed) */
1343 			sprintf (name, "%s/%s.zif", dir_name, gamename);
1344 			if( cache_stat (name, &stat_buffer) == 0 )
1345 			{
1346 				sprintf (name, "%s/%s.zif/%s", dir_name, gamename, filename);
1347 				if( checksum_file (name, 0, length, sum) == 0 )
1348 				{
1349 					found = 1;
1350 				}
1351 			}
1352 		}
1353 	}
1354 
1355 	if( !found )
1356 		return -1;
1357 
1358 	return 0;
1359 }
1360 
1361 /* JB 980920 */
osd_fsize(void * file)1362 int osd_fsize (void *file)
1363 {
1364 	FakeFileHandle *f = (FakeFileHandle *) file;
1365 
1366 	if( f->type == kRAMFile || f->type == kZippedFile )
1367 		return f->length;
1368 
1369 	if( f->file )
1370 	{
1371 		int size;
1372 		int offs = ftell( f->file );
1373 
1374 		fseek( f->file, 0, SEEK_END );
1375 		size = ftell( f->file );
1376 		fseek( f->file, offs, SEEK_SET );
1377 		return size;
1378 	}
1379 
1380     return 0;
1381 }
1382 
1383 /* JB 980920 */
osd_fcrc(void * file)1384 unsigned int osd_fcrc (void *file)
1385 {
1386 	FakeFileHandle *f = (FakeFileHandle *) file;
1387 
1388 	return f->crc;
1389 }
1390 
osd_fgetc(void * file)1391 int osd_fgetc(void *file)
1392 {
1393 	FakeFileHandle *f = (FakeFileHandle *) file;
1394 
1395 	if (f->type == kPlainFile && f->file)
1396 		return fgetc(f->file);
1397 
1398    return EOF;
1399 }
1400 
osd_ungetc(int c,void * file)1401 int osd_ungetc(int c, void *file)
1402 {
1403 	FakeFileHandle *f = (FakeFileHandle *) file;
1404 
1405 	if (f->type == kPlainFile && f->file)
1406 		return ungetc(c,f->file);
1407 
1408    return EOF;
1409 }
1410 
osd_fgets(char * s,int n,void * file)1411 char *osd_fgets(char *s, int n, void *file)
1412 {
1413 	FakeFileHandle *f = (FakeFileHandle *) file;
1414 
1415 	if (f->type == kPlainFile && f->file)
1416 		return fgets(s,n,f->file);
1417 
1418    return NULL;
1419 }
1420 
osd_feof(void * file)1421 int osd_feof(void *file)
1422 {
1423 	FakeFileHandle *f = (FakeFileHandle *) file;
1424 
1425 	if (f->type == kPlainFile && f->file)
1426 		return feof(f->file);
1427 
1428    return 1;
1429 }
1430 
osd_ftell(void * file)1431 int osd_ftell(void *file)
1432 {
1433 	FakeFileHandle *f = (FakeFileHandle *) file;
1434 
1435 	if (f->type == kPlainFile && f->file)
1436 		return ftell(f->file);
1437 
1438    return -1L;
1439 }
1440 
1441 
1442 /* called while loading ROMs. It is called a last time with name == 0 to signal */
1443 /* that the ROM loading process is finished. */
1444 /* return non-zero to abort loading */
osd_display_loading_rom_message(const char * name,int current,int total)1445 int osd_display_loading_rom_message (const char *name, int current, int total)
1446 {
1447 	if( name )
1448 		printf ("loading %-12s\n", name);
1449 	else
1450 		printf ("             \n");
1451 	fflush (stdout);
1452 
1453 	if( keyboard_pressed (KEYCODE_LCONTROL) && keyboard_pressed (KEYCODE_C) )
1454 		return 1;
1455 
1456 	return 0;
1457 }
1458