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