1 /***********************************************************************************
2 Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3
4 (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com),
5 Jerremy Koot (jkoot@snes9x.com)
6
7 (c) Copyright 2002 - 2004 Matthew Kendora
8
9 (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org)
10
11 (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
12
13 (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net)
14
15 (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca),
16 Kris Bleakley (codeviolation@hotmail.com)
17
18 (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
19 Nach (n-a-c-h@users.sourceforge.net),
20
21 (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
22
23 (c) Copyright 2006 - 2007 nitsuja
24
25 (c) Copyright 2009 - 2016 BearOso,
26 OV2
27
28
29 BS-X C emulator code
30 (c) Copyright 2005 - 2006 Dreamer Nom,
31 zones
32
33 C4 x86 assembler and some C emulation code
34 (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com),
35 Nach,
36 zsKnight (zsknight@zsnes.com)
37
38 C4 C++ code
39 (c) Copyright 2003 - 2006 Brad Jorsch,
40 Nach
41
42 DSP-1 emulator code
43 (c) Copyright 1998 - 2006 _Demo_,
44 Andreas Naive (andreasnaive@gmail.com),
45 Gary Henderson,
46 Ivar (ivar@snes9x.com),
47 John Weidman,
48 Kris Bleakley,
49 Matthew Kendora,
50 Nach,
51 neviksti (neviksti@hotmail.com)
52
53 DSP-2 emulator code
54 (c) Copyright 2003 John Weidman,
55 Kris Bleakley,
56 Lord Nightmare (lord_nightmare@users.sourceforge.net),
57 Matthew Kendora,
58 neviksti
59
60 DSP-3 emulator code
61 (c) Copyright 2003 - 2006 John Weidman,
62 Kris Bleakley,
63 Lancer,
64 z80 gaiden
65
66 DSP-4 emulator code
67 (c) Copyright 2004 - 2006 Dreamer Nom,
68 John Weidman,
69 Kris Bleakley,
70 Nach,
71 z80 gaiden
72
73 OBC1 emulator code
74 (c) Copyright 2001 - 2004 zsKnight,
75 pagefault (pagefault@zsnes.com),
76 Kris Bleakley
77 Ported from x86 assembler to C by sanmaiwashi
78
79 SPC7110 and RTC C++ emulator code used in 1.39-1.51
80 (c) Copyright 2002 Matthew Kendora with research by
81 zsKnight,
82 John Weidman,
83 Dark Force
84
85 SPC7110 and RTC C++ emulator code used in 1.52+
86 (c) Copyright 2009 byuu,
87 neviksti
88
89 S-DD1 C emulator code
90 (c) Copyright 2003 Brad Jorsch with research by
91 Andreas Naive,
92 John Weidman
93
94 S-RTC C emulator code
95 (c) Copyright 2001 - 2006 byuu,
96 John Weidman
97
98 ST010 C++ emulator code
99 (c) Copyright 2003 Feather,
100 John Weidman,
101 Kris Bleakley,
102 Matthew Kendora
103
104 Super FX x86 assembler emulator code
105 (c) Copyright 1998 - 2003 _Demo_,
106 pagefault,
107 zsKnight
108
109 Super FX C emulator code
110 (c) Copyright 1997 - 1999 Ivar,
111 Gary Henderson,
112 John Weidman
113
114 Sound emulator code used in 1.5-1.51
115 (c) Copyright 1998 - 2003 Brad Martin
116 (c) Copyright 1998 - 2006 Charles Bilyue'
117
118 Sound emulator code used in 1.52+
119 (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
120
121 S-SMP emulator code used in 1.54+
122 (c) Copyright 2016 byuu
123
124 SH assembler code partly based on x86 assembler code
125 (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
126
127 2xSaI filter
128 (c) Copyright 1999 - 2001 Derek Liauw Kie Fa
129
130 HQ2x, HQ3x, HQ4x filters
131 (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
132
133 NTSC filter
134 (c) Copyright 2006 - 2007 Shay Green
135
136 GTK+ GUI code
137 (c) Copyright 2004 - 2016 BearOso
138
139 Win32 GUI code
140 (c) Copyright 2003 - 2006 blip,
141 funkyass,
142 Matthew Kendora,
143 Nach,
144 nitsuja
145 (c) Copyright 2009 - 2016 OV2
146
147 Mac OS GUI code
148 (c) Copyright 1998 - 2001 John Stiles
149 (c) Copyright 2001 - 2011 zones
150
151
152 Specific ports contains the works of other authors. See headers in
153 individual files.
154
155
156 Snes9x homepage: http://www.snes9x.com/
157
158 Permission to use, copy, modify and/or distribute Snes9x in both binary
159 and source form, for non-commercial purposes, is hereby granted without
160 fee, providing that this license information and copyright notice appear
161 with all copies and any derived work.
162
163 This software is provided 'as-is', without any express or implied
164 warranty. In no event shall the authors be held liable for any damages
165 arising from the use of this software or it's derivatives.
166
167 Snes9x is freeware for PERSONAL USE only. Commercial users should
168 seek permission of the copyright holders first. Commercial use includes,
169 but is not limited to, charging money for Snes9x or software derived from
170 Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
171 using Snes9x as a promotion for your commercial product.
172
173 The copyright holders request that bug fixes and improvements to the code
174 should be forwarded to them so everyone can benefit from the modifications
175 in future versions.
176
177 Super NES and Super Nintendo Entertainment System are trademarks of
178 Nintendo Co., Limited and its subsidiary companies.
179 ***********************************************************************************/
180
181 /***********************************************************************************
182 SNES9X for Mac OS (c) Copyright John Stiles
183
184 Snes9x for Mac OS X
185
186 (c) Copyright 2001 - 2011 zones
187 (c) Copyright 2002 - 2005 107
188 (c) Copyright 2002 PB1400c
189 (c) Copyright 2004 Alexander and Sander
190 (c) Copyright 2004 - 2005 Steven Seeger
191 (c) Copyright 2005 Ryan Vogt
192 ***********************************************************************************/
193
194
195 #include "snes9x.h"
196 #include "memmap.h"
197 #include "movie.h"
198 #include "display.h"
199
200 #include <libgen.h>
201
202 #include "mac-prefix.h"
203 #include "mac-dialog.h"
204 #include "mac-os.h"
205 #include "mac-stringtools.h"
206 #include "mac-file.h"
207
208 static void AddFolderIcon (FSRef *, const char *);
209 static OSStatus FindSNESFolder (FSRef *, char *, const char *);
210 static OSStatus FindApplicationSupportFolder (FSRef *, char *, const char *);
211 static OSStatus FindCustomFolder (FSRef *, char *, const char *);
212
213
CheckSaveFolder(FSRef * cartRef)214 void CheckSaveFolder (FSRef *cartRef)
215 {
216 OSStatus err;
217 Boolean r;
218 FSCatalogInfo finfo;
219 FSVolumeInfo vinfo;
220 FSRef ref;
221 CFURLRef burl, purl;
222 char s[PATH_MAX + 1];
223
224 switch (saveInROMFolder)
225 {
226 case 0: // Snes9x folder
227 burl = CFBundleCopyBundleURL(CFBundleGetMainBundle());
228 purl = CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, burl);
229 r = CFURLGetFSRef(purl, &ref);
230 CFRelease(purl);
231 CFRelease(burl);
232 break;
233
234 case 1: // ROM folder
235 err = FSGetCatalogInfo(cartRef, kFSCatInfoNone, NULL, NULL, NULL, &ref);
236 break;
237
238 case 2: // Application Support folder
239 return;
240
241 case 4: // Custom folder
242 if (saveFolderPath == NULL)
243 {
244 saveInROMFolder = 2;
245 return;
246 }
247
248 r = CFStringGetCString(saveFolderPath, s, PATH_MAX, kCFStringEncodingUTF8);
249 err = FSPathMakeRef((unsigned char *) s, &ref, NULL);
250 if (err)
251 {
252 AppearanceAlert(kAlertCautionAlert, kS9xMacAlertFolderNotFound, kS9xMacAlertFolderNotFoundHint);
253 saveInROMFolder = 2;
254 return;
255 }
256
257 break;
258 }
259
260 err = FSGetCatalogInfo(&ref, kFSCatInfoUserPrivs | kFSCatInfoVolume, &finfo, NULL, NULL, NULL);
261 if (err == noErr)
262 {
263 if (finfo.userPrivileges & kioACUserNoMakeChangesMask)
264 {
265 AppearanceAlert(kAlertCautionAlert, kS9xMacAlertFolderFailToCreate, kS9xMacAlertFolderFailToCreateHint);
266 saveInROMFolder = 2;
267 return;
268 }
269
270 err = FSGetVolumeInfo(finfo.volume, 0, NULL, kFSVolInfoFlags, &vinfo, NULL, NULL);
271 if (err == noErr)
272 {
273 if ((vinfo.flags & kFSVolFlagHardwareLockedMask) || (vinfo.flags & kFSVolFlagSoftwareLockedMask))
274 {
275 AppearanceAlert(kAlertCautionAlert, kS9xMacAlertFolderFailToCreate, kS9xMacAlertFolderFailToCreateHint);
276 saveInROMFolder = 2;
277 return;
278 }
279 }
280 }
281
282 if (err)
283 saveInROMFolder = 2;
284 }
285
FindSNESFolder(FSRef * folderRef,char * folderPath,const char * folderName)286 static OSStatus FindSNESFolder (FSRef *folderRef, char *folderPath, const char *folderName)
287 {
288 OSStatus err;
289 CFURLRef burl, purl;
290 CFStringRef fstr;
291 FSRef pref;
292 UniChar buffer[PATH_MAX + 1];
293 Boolean r;
294
295 fstr = CFStringCreateWithCString(kCFAllocatorDefault, folderName, CFStringGetSystemEncoding());
296 CFStringGetCharacters(fstr, CFRangeMake(0, CFStringGetLength(fstr)), buffer);
297
298 burl = CFBundleCopyBundleURL(CFBundleGetMainBundle());
299 purl = CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, burl);
300 r = CFURLGetFSRef(purl, &pref);
301
302 err = FSMakeFSRefUnicode(&pref, CFStringGetLength(fstr), buffer, kTextEncodingUnicodeDefault, folderRef);
303 if (err == dirNFErr || err == fnfErr)
304 {
305 err = FSCreateDirectoryUnicode(&pref, CFStringGetLength(fstr), buffer, kFSCatInfoNone, NULL, folderRef, NULL, NULL);
306 if (err == noErr)
307 AddFolderIcon(folderRef, folderName);
308 }
309
310 if (err == noErr)
311 err = FSRefMakePath(folderRef, (unsigned char *) folderPath, PATH_MAX);
312
313 CFRelease(purl);
314 CFRelease(burl);
315 CFRelease(fstr);
316
317 return (err);
318 }
319
FindApplicationSupportFolder(FSRef * folderRef,char * folderPath,const char * folderName)320 static OSStatus FindApplicationSupportFolder (FSRef *folderRef, char *folderPath, const char *folderName)
321 {
322 OSStatus err;
323 FSRef p2ref, p1ref;
324 CFStringRef fstr;
325 UniChar buffer[PATH_MAX + 1];
326 UniChar s9xfolder[6] = { 'S', 'n', 'e', 's', '9', 'x' },
327 oldfolder[6] = { 'S', 'N', 'E', 'S', '9', 'X' };
328
329 err = FSFindFolder(kUserDomain, kApplicationSupportFolderType, kCreateFolder, &p2ref);
330 if (err)
331 return (err);
332
333 err = FSMakeFSRefUnicode(&p2ref, 6, s9xfolder, kTextEncodingUnicodeDefault, &p1ref);
334 if (err == dirNFErr || err == fnfErr)
335 {
336 err = FSMakeFSRefUnicode(&p2ref, 6, oldfolder, kTextEncodingUnicodeDefault, &p1ref);
337 if (err == dirNFErr || err == fnfErr)
338 err = FSCreateDirectoryUnicode(&p2ref, 6, s9xfolder, kFSCatInfoNone, NULL, &p1ref, NULL, NULL);
339 }
340
341 if (err)
342 return (err);
343
344 fstr = CFStringCreateWithCString(kCFAllocatorDefault, folderName, CFStringGetSystemEncoding());
345 CFStringGetCharacters(fstr, CFRangeMake(0, CFStringGetLength(fstr)), buffer);
346
347 err = FSMakeFSRefUnicode(&p1ref, CFStringGetLength(fstr), buffer, kTextEncodingUnicodeDefault, folderRef);
348 if (err == dirNFErr || err == fnfErr)
349 {
350 err = FSCreateDirectoryUnicode(&p1ref, CFStringGetLength(fstr), buffer, kFSCatInfoNone, NULL, folderRef, NULL, NULL);
351 if (err == noErr)
352 AddFolderIcon(folderRef, folderName);
353 }
354
355 if (err == noErr)
356 err = FSRefMakePath(folderRef, (unsigned char *) folderPath, PATH_MAX);
357
358 CFRelease(fstr);
359
360 return (err);
361 }
362
FindCustomFolder(FSRef * folderRef,char * folderPath,const char * folderName)363 static OSStatus FindCustomFolder (FSRef *folderRef, char *folderPath, const char *folderName)
364 {
365 OSStatus err;
366 CFStringRef fstr;
367 FSRef pref;
368 UniChar buffer[PATH_MAX + 1];
369 char s[PATH_MAX + 1];
370
371 if (saveFolderPath == NULL)
372 return (-1);
373
374 err = CFStringGetCString(saveFolderPath, s, PATH_MAX, kCFStringEncodingUTF8) ? noErr : -1;
375 if (err == noErr)
376 err = FSPathMakeRef((unsigned char *) s, &pref, NULL);
377
378 if (err)
379 return (err);
380
381 fstr = CFStringCreateWithCString(kCFAllocatorDefault, folderName, CFStringGetSystemEncoding());
382 CFStringGetCharacters(fstr, CFRangeMake(0, CFStringGetLength(fstr)), buffer);
383
384 err = FSMakeFSRefUnicode(&pref, CFStringGetLength(fstr), buffer, kTextEncodingUnicodeDefault, folderRef);
385 if (err == dirNFErr || err == fnfErr)
386 {
387 err = FSCreateDirectoryUnicode(&pref, CFStringGetLength(fstr), buffer, kFSCatInfoNone, NULL, folderRef, NULL, NULL);
388 if (err == noErr)
389 AddFolderIcon(folderRef, folderName);
390 }
391
392 if (err == noErr)
393 err = FSRefMakePath(folderRef, (unsigned char *) folderPath, PATH_MAX);
394
395 CFRelease(fstr);
396
397 return (err);
398 }
399
ChangeTypeAndCreator(const char * path,OSType type,OSType creator)400 void ChangeTypeAndCreator (const char *path, OSType type, OSType creator)
401 {
402 OSStatus err;
403 FSRef ref;
404
405 err = FSPathMakeRef((unsigned char *) path, &ref, NULL);
406 if (err == noErr)
407 {
408 FSCatalogInfo catinfo;
409
410 err = FSGetCatalogInfo(&ref, kFSCatInfoFinderInfo, &catinfo, NULL, NULL, NULL);
411 if (err == noErr)
412 {
413 ((FileInfo *) &catinfo.finderInfo)->fileCreator = creator;
414 ((FileInfo *) &catinfo.finderInfo)->fileType = type;
415
416 err = FSSetCatalogInfo(&ref, kFSCatInfoFinderInfo, &catinfo);
417 }
418 }
419 }
420
AddFolderIcon(FSRef * fref,const char * folderName)421 static void AddFolderIcon (FSRef *fref, const char *folderName)
422 {
423 OSStatus err;
424 FSCatalogInfo fcat, icat;
425 FSRef bref, iref;
426 CFStringRef str;
427 CFURLRef url;
428 IconFamilyHandle family;
429 IconRef icon;
430 HFSUniStr255 fork;
431 Boolean r;
432 SInt16 resf;
433 char name[64];
434 UniChar iconName[5] = { 'I', 'c', 'o', 'n', '\r' };
435
436 strcpy(name, "folder_");
437 strcat(name, folderName);
438
439 str = CFStringCreateWithCString(kCFAllocatorDefault, name, CFStringGetSystemEncoding());
440 if (str)
441 {
442 url = CFBundleCopyResourceURL(CFBundleGetMainBundle(), str, CFSTR("icns"), NULL);
443 if (url)
444 {
445 r = CFURLGetFSRef(url, &bref);
446 if (r)
447 {
448 err = RegisterIconRefFromFSRef('~9X~', 'TEMP', &bref, &icon);
449 if (err == noErr)
450 {
451 err = FSGetResourceForkName(&fork);
452 if (err == noErr)
453 {
454 err = FSCreateResourceFile(fref, 5, iconName, kFSCatInfoNone, NULL, fork.length, fork.unicode, &iref, NULL);
455 if (err == noErr)
456 {
457 err = FSOpenResourceFile(&iref, fork.length, fork.unicode, fsWrPerm, &resf);
458 if (err == noErr)
459 {
460 err = IconRefToIconFamily(icon, kSelectorAllAvailableData, &family);
461 if (err == noErr)
462 {
463 AddResource((Handle) family, 'icns', -16455, "\p");
464 WriteResource((Handle) family);
465 ReleaseResource((Handle) family);
466
467 err = FSGetCatalogInfo(&iref, kFSCatInfoFinderInfo, &icat, NULL, NULL, NULL);
468 ((FileInfo *) &icat.finderInfo)->finderFlags |= kIsInvisible;
469 ((FileInfo *) &icat.finderInfo)->fileCreator = 'MACS';
470 ((FileInfo *) &icat.finderInfo)->fileType = 'icon';
471 err = FSSetCatalogInfo(&iref, kFSCatInfoFinderInfo, &icat);
472
473 err = FSGetCatalogInfo(fref, kFSCatInfoFinderInfo, &fcat, NULL, NULL, NULL);
474 ((FolderInfo *) &fcat.finderInfo)->finderFlags |= kHasCustomIcon;
475 ((FolderInfo *) &fcat.finderInfo)->finderFlags &= ~kHasBeenInited;
476 err = FSSetCatalogInfo(fref, kFSCatInfoFinderInfo, &fcat);
477 }
478
479 CloseResFile(resf);
480 }
481 }
482 }
483
484 err = UnregisterIconRef('~9X~', 'TEMP');
485 }
486 }
487
488 CFRelease(url);
489 }
490
491 CFRelease(str);
492 }
493 }
494
S9xGetFilename(const char * inExt,enum s9x_getdirtype dirtype)495 const char * S9xGetFilename (const char *inExt, enum s9x_getdirtype dirtype)
496 {
497 static int index = 0;
498 static char filePath[4][PATH_MAX + 1];
499
500 OSStatus err;
501 FSRef ref;
502 uint32 type;
503 char folderName[16];
504 char drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], fname[_MAX_FNAME + 1], ext[_MAX_EXT + 1];
505 const char *p;
506
507 index++;
508 if (index > 3)
509 index = 0;
510
511 folderName[0] = filePath[index][0] = 0;
512
513 if (strlen(inExt) < 4)
514 return (filePath[index]);
515
516 p = inExt + strlen(inExt) - 4;
517 type = ((uint32) p[0] << 24) + ((uint32) p[1] << 16) + ((uint32) p[2] << 8) + (uint32) p[3];
518
519 switch (type)
520 {
521 case '.srm':
522 case '.rtc':
523 strcpy(folderName, "SRAMs");
524 break;
525
526 case '.frz':
527 strcpy(folderName, "Freezes");
528 break;
529
530 case '.spc':
531 strcpy(folderName, "SPCs");
532 break;
533
534 case '.cht':
535 strcpy(folderName, "Cheats");
536 break;
537
538 case '.ups':
539 case '.ips':
540 strcpy(folderName, "Patches");
541 break;
542
543 case '.png':
544 strcpy(folderName, "Screenshots");
545 break;
546
547 case '.dat':
548 case '.out':
549 case '.log':
550 strcpy(folderName, "Logs");
551 break;
552
553 case '.bio': // dummy
554 strcpy(folderName, "BIOSes");
555 break;
556 }
557
558 if (folderName[0] && (saveInROMFolder != 1))
559 {
560 char s[PATH_MAX + 1];
561
562 s[0] = 0;
563 err = -1;
564
565 if (saveInROMFolder == 0)
566 {
567 err = FindSNESFolder(&ref, s, folderName);
568 if (err)
569 saveInROMFolder = 2;
570 }
571
572 if (saveInROMFolder == 4)
573 {
574 err = FindCustomFolder(&ref, s, folderName);
575 if (err)
576 saveInROMFolder = 2;
577
578 }
579
580 if (saveInROMFolder == 2)
581 err = FindApplicationSupportFolder(&ref, s, folderName);
582
583 if (err == noErr)
584 {
585 _splitpath(Memory.ROMFilename, drive, dir, fname, ext);
586 snprintf(filePath[index], PATH_MAX + 1, "%s%s%s%s", s, MAC_PATH_SEPARATOR, fname, inExt);
587 }
588 else
589 {
590 _splitpath(Memory.ROMFilename, drive, dir, fname, ext);
591 _makepath(filePath[index], drive, dir, fname, inExt);
592 }
593 }
594 else
595 {
596 _splitpath(Memory.ROMFilename, drive, dir, fname, ext);
597 _makepath(filePath[index], drive, dir, fname, inExt);
598 }
599
600 return (filePath[index]);
601 }
602
S9xGetSPCFilename(void)603 const char * S9xGetSPCFilename (void)
604 {
605 char spcExt[16];
606
607 sprintf(spcExt, ".%03d.spc", (int) spcFileCount);
608
609 spcFileCount++;
610 if (spcFileCount == 1000)
611 spcFileCount = 0;
612
613 return (S9xGetFilename(spcExt, SPC_DIR));
614 }
615
S9xGetPNGFilename(void)616 const char * S9xGetPNGFilename (void)
617 {
618 char pngExt[16];
619
620 sprintf(pngExt, ".%03d.png", (int) pngFileCount);
621
622 pngFileCount++;
623 if (pngFileCount == 1000)
624 pngFileCount = 0;
625
626 return (S9xGetFilename(pngExt, SCREENSHOT_DIR));
627 }
628
S9xGetFreezeFilename(int which)629 const char * S9xGetFreezeFilename (int which)
630 {
631 char frzExt[16];
632
633 sprintf(frzExt, ".%03d.frz", which);
634
635 return (S9xGetFilename(frzExt, SNAPSHOT_DIR));
636 }
637
S9xGetFilenameInc(const char * inExt,enum s9x_getdirtype dirtype)638 const char * S9xGetFilenameInc (const char *inExt, enum s9x_getdirtype dirtype)
639 {
640 uint32 type;
641 const char *p;
642
643 if (strlen(inExt) < 4)
644 return (NULL);
645
646 p = inExt + strlen(inExt) - 4;
647 type = ((uint32) p[0] << 24) + ((uint32) p[1] << 16) + ((uint32) p[2] << 8) + (uint32) p[3];
648
649 switch (type)
650 {
651 case '.spc':
652 return (S9xGetSPCFilename());
653
654 case '.png':
655 return (S9xGetPNGFilename());
656 }
657
658 return (NULL);
659 }
660
S9xChooseFilename(bool8 read_only)661 const char * S9xChooseFilename (bool8 read_only)
662 {
663 return (NULL);
664 }
665
S9xChooseMovieFilename(bool8 read_only)666 const char * S9xChooseMovieFilename (bool8 read_only)
667 {
668 return (NULL);
669 }
670
S9xOpenSnapshotFile(const char * fname,bool8 read_only,STREAM * file)671 bool8 S9xOpenSnapshotFile (const char *fname, bool8 read_only, STREAM *file)
672 {
673 if (read_only)
674 {
675 if (0 != (*file = OPEN_STREAM(fname, "rb")))
676 return (true);
677 }
678 else
679 {
680 if (0 != (*file = OPEN_STREAM(fname, "wb")))
681 return (true);
682 }
683
684 return (false);
685 }
686
S9xCloseSnapshotFile(STREAM file)687 void S9xCloseSnapshotFile (STREAM file)
688 {
689 CLOSE_STREAM(file);
690 }
691
S9xBasename(const char * in)692 const char * S9xBasename (const char *in)
693 {
694 static char s[PATH_MAX + 1];
695
696 strncpy(s, in, PATH_MAX + 1);
697 s[PATH_MAX] = 0;
698
699 size_t l = strlen(s);
700
701 for (unsigned int i = 0; i < l; i++)
702 {
703 if (s[i] < 32 || s[i] >= 127)
704 s[i] = '_';
705 }
706
707 return (basename(s));
708 }
709
S9xGetDirectory(enum s9x_getdirtype dirtype)710 const char * S9xGetDirectory (enum s9x_getdirtype dirtype)
711 {
712 static int index = 0;
713 static char path[4][PATH_MAX + 1];
714
715 char inExt[16];
716 char drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], fname[_MAX_FNAME + 1], ext[_MAX_EXT + 1];
717
718 index++;
719 if (index > 3)
720 index = 0;
721
722 switch (dirtype)
723 {
724 case SNAPSHOT_DIR: strcpy(inExt, ".frz"); break;
725 case SRAM_DIR: strcpy(inExt, ".srm"); break;
726 case SCREENSHOT_DIR: strcpy(inExt, ".png"); break;
727 case SPC_DIR: strcpy(inExt, ".spc"); break;
728 case CHEAT_DIR: strcpy(inExt, ".cht"); break;
729 case BIOS_DIR: strcpy(inExt, ".bio"); break;
730 case LOG_DIR: strcpy(inExt, ".log"); break;
731 default: strcpy(inExt, ".xxx"); break;
732 }
733
734 _splitpath(S9xGetFilename(inExt, dirtype), drive, dir, fname, ext);
735 _makepath(path[index], drive, dir, "", "");
736
737 int l = strlen(path[index]);
738 if (l > 1)
739 path[index][l - 1] = 0;
740
741 return (path[index]);
742 }
743
_splitpath(const char * path,char * drive,char * dir,char * fname,char * ext)744 void _splitpath (const char *path, char *drive, char *dir, char *fname, char *ext)
745 {
746 drive[0] = 0;
747 fname[0] = 0;
748 ext[0] = 0;
749 dir[0] = 0;
750
751 int x;
752
753 x = strlen(path) - 1;
754 if (x < 0)
755 return;
756
757 while (x && (path[x] != MAC_PATH_SEP_CHAR))
758 x--;
759
760 if (x)
761 {
762 strcpy(dir, path);
763 dir[x + 1] = 0;
764
765 strcpy(fname, path + x + 1);
766 }
767 else
768 strcpy(fname, path);
769
770 x = strlen(fname);
771 while (x && (fname[x] != '.'))
772 x--;
773
774 if (x)
775 {
776 strcpy(ext, fname + x);
777 fname[x] = 0;
778 }
779 }
780
_makepath(char * path,const char * drive,const char * dir,const char * fname,const char * ext)781 void _makepath (char *path, const char *drive, const char *dir, const char *fname, const char *ext)
782 {
783 static const char emp[] = "", dot[] = ".";
784
785 const char *d, *f, *e, *p;
786
787 d = dir ? dir : emp;
788 f = fname ? fname : emp;
789 e = ext ? ext : emp;
790 p = (e[0] && e[0] != '.') ? dot : emp;
791
792 snprintf(path, PATH_MAX + 1, "%s%s%s%s", d, f, p, e);
793 }
794