use rcheevos for identifying games

This commit is contained in:
Jamiras 2020-06-07 10:41:03 -06:00
parent dc217b313c
commit 7d488aa200
4 changed files with 472 additions and 939 deletions

File diff suppressed because it is too large Load Diff

View File

@ -317,6 +317,19 @@ static const rc_memory_region_t _rc_memory_regions_megadrive[] = {
};
static const rc_memory_regions_t rc_memory_regions_megadrive = { _rc_memory_regions_megadrive, 2 };
/* ===== MSX ===== */
/* https://www.msx.org/wiki/The_Memory */
/* MSX only has 64KB of addressable RAM, of which 32KB is reserved for the system/BIOS.
* However, the system has up to 512KB of RAM, which is paged into the addressable RAM
* We expect the raw RAM to be exposed, rather than force the devs to worry about the
* paging system. The entire RAM is expected to appear starting at $10000, which is not
* addressable by the system itself.
*/
static const rc_memory_region_t _rc_memory_regions_msx[] = {
{ 0x000000U, 0x07FFFFU, 0x010000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" },
};
static const rc_memory_regions_t rc_memory_regions_msx = { _rc_memory_regions_msx, 1 };
/* ===== Neo Geo Pocket ===== */
/* http://neopocott.emuunlim.com/docs/tech-11.txt */
static const rc_memory_region_t _rc_memory_regions_neo_geo_pocket[] = {
@ -400,7 +413,7 @@ static const rc_memory_regions_t rc_memory_regions_pokemini = { _rc_memory_regio
/* ===== Sega CD ===== */
static const rc_memory_region_t _rc_memory_regions_segacd[] = {
{ 0x000000U, 0x00FFFFU, 0x00FF0000U, RC_MEMORY_TYPE_SYSTEM_RAM, "68000 RAM" },
{ 0x010000U, 0x08FFFFU, 0x80000000U, RC_MEMORY_TYPE_SAVE_RAM, "CD PRG RAM" } /* normally banked into $020000-$03FFFF */
{ 0x010000U, 0x08FFFFU, 0x80020000U, RC_MEMORY_TYPE_SAVE_RAM, "CD PRG RAM" } /* normally banked into $020000-$03FFFF */
};
static const rc_memory_regions_t rc_memory_regions_segacd = { _rc_memory_regions_segacd, 2 };
@ -446,9 +459,10 @@ static const rc_memory_regions_t rc_memory_regions_snes = { _rc_memory_regions_s
/* http://daifukkat.su/docs/wsman/#ovr_memmap */
static const rc_memory_region_t _rc_memory_regions_wonderswan[] = {
/* RAM ends at 0x3FFF for WonderSwan, WonderSwan color uses all 64KB */
{ 0x000000U, 0x00FFFFU, 0x000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }
{ 0x000000U, 0x00FFFFU, 0x000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" },
{ 0x010000U, 0x01FFFFU, 0x000000U, RC_MEMORY_TYPE_SAVE_RAM, "Cartridge RAM" }
};
static const rc_memory_regions_t rc_memory_regions_wonderswan = { _rc_memory_regions_wonderswan, 1 };
static const rc_memory_regions_t rc_memory_regions_wonderswan = { _rc_memory_regions_wonderswan, 2 };
/* ===== Vectrex ===== */
/* https://roadsidethoughts.com/vectrex/vectrex-memory-map.htm */
@ -516,6 +530,9 @@ const rc_memory_regions_t* rc_console_memory_regions(int console_id)
* Genesis, but we currently don't support it. */
return &rc_memory_regions_megadrive;
case RC_CONSOLE_MSX:
return &rc_memory_regions_msx;
case RC_CONSOLE_NEOGEO_POCKET:
return &rc_memory_regions_neo_geo_pocket;

View File

@ -99,7 +99,7 @@ void* rc_file_open(const char* path)
handle = filereader->open(path);
if (handle && verbose_message_callback)
{
char message[2048];
char message[1024];
snprintf(message, sizeof(message), "Opened %s", rc_path_get_filename(path));
verbose_message_callback(message);
}
@ -264,12 +264,12 @@ static const char* rc_path_get_extension(const char* path)
do
{
if (ptr[-1] == '.')
break;
return ptr;
--ptr;
} while (ptr > path);
return ptr;
return path + strlen(path);
}
int rc_path_compare_extension(const char* path, const char* ext)
@ -363,8 +363,8 @@ static int rc_hash_3do(char hash[33], const char* path)
{
if (verbose_message_callback)
{
char message[4096];
snprintf(message, sizeof(message), "Found 3DO CD, title=%s", &buffer[0x28]);
char message[128];
snprintf(message, sizeof(message), "Found 3DO CD, title=%.32s", &buffer[0x28]);
verbose_message_callback(message);
}
@ -414,7 +414,7 @@ static int rc_hash_3do(char hash[33], const char* path)
if (verbose_message_callback)
{
char message[128];
snprintf(message, sizeof(message), "Hashing header (%u bytes) and %s (%u bytes) ", 132, &buffer[offset + 0x20], (unsigned)size);
snprintf(message, sizeof(message), "Hashing header (%u bytes) and %.32s (%u bytes) ", 132, &buffer[offset + 0x20], (unsigned)size);
verbose_message_callback(message);
}
@ -475,9 +475,74 @@ static int rc_hash_3do(char hash[33], const char* path)
static int rc_hash_arcade(char hash[33], const char* path)
{
/* arcade hash is just the hash of the filename (no extension) - the cores are pretty stringent about having the right ROM data */
const char* ptr = rc_path_get_filename(path);
const char* ext = rc_path_get_extension(ptr);
return rc_hash_buffer(hash, (uint8_t*)ptr, ext - ptr - 1);
const char* filename = rc_path_get_filename(path);
const char* ext = rc_path_get_extension(filename);
size_t filename_length = ext - filename - 1;
/* fbneo supports loading subsystems by using specific folder names.
* if one is found, include it in the hash.
* https://github.com/libretro/FBNeo/blob/master/src/burner/libretro/README.md#emulating-consoles
*/
if (filename > path + 1)
{
int include_folder = 0;
const char* folder = filename - 1;
size_t parent_folder_length = 0;
do
{
if (folder[-1] == '/' || folder[-1] == '\\')
break;
--folder;
} while (folder > path);
parent_folder_length = filename - folder - 1;
switch (parent_folder_length)
{
case 3:
if (memcmp(folder, "nes", 3) == 0 ||
memcmp(folder, "fds", 3) == 0 ||
memcmp(folder, "sms", 3) == 0 ||
memcmp(folder, "msx", 3) == 0 ||
memcmp(folder, "ngp", 3) == 0 ||
memcmp(folder, "pce", 3) == 0 ||
memcmp(folder, "sgx", 3) == 0)
include_folder = 1;
break;
case 4:
if (memcmp(folder, "tg16", 4) == 0)
include_folder = 1;
break;
case 6:
if (memcmp(folder, "coleco", 6) == 0 ||
memcmp(folder, "sg1000", 6) == 0)
include_folder = 1;
break;
case 8:
if (memcmp(folder, "gamegear", 8) == 0 ||
memcmp(folder, "megadriv", 8) == 0 ||
memcmp(folder, "spectrum", 8) == 0)
include_folder = 1;
break;
default:
break;
}
if (include_folder)
{
char buffer[128]; /* realistically, this should never need more than ~20 characters */
if (parent_folder_length + filename_length + 1 < sizeof(buffer))
{
memcpy(&buffer[0], folder, parent_folder_length);
buffer[parent_folder_length] = '_';
memcpy(&buffer[parent_folder_length + 1], filename, filename_length);
return rc_hash_buffer(hash, (uint8_t*)&buffer[0], parent_folder_length + filename_length + 1);
}
}
}
return rc_hash_buffer(hash, (uint8_t*)filename, filename_length);
}
static int rc_hash_lynx(char hash[33], uint8_t* buffer, size_t buffer_size)
@ -653,9 +718,9 @@ static int rc_hash_pce_cd(char hash[33], const char* path)
if (verbose_message_callback)
{
char message[4096];
char message[128];
buffer[128] = '\0';
snprintf(message, sizeof(message), "Found PC Engine CD, title=%s", &buffer[106]);
snprintf(message, sizeof(message), "Found PC Engine CD, title=%.22s", &buffer[106]);
verbose_message_callback(message);
}
@ -913,6 +978,7 @@ int rc_hash_generate_from_buffer(char hash[33], int console_id, uint8_t* buffer,
case RC_CONSOLE_INTELLIVISION:
case RC_CONSOLE_MASTER_SYSTEM:
case RC_CONSOLE_MEGA_DRIVE:
case RC_CONSOLE_MSX:
case RC_CONSOLE_NEOGEO_POCKET:
case RC_CONSOLE_NINTENDO_64:
case RC_CONSOLE_ORIC:
@ -1035,12 +1101,37 @@ static int rc_hash_buffered_file(char hash[33], int console_id, const char* path
return result;
}
static int rc_hash_path_is_absolute(const char* path)
{
if (!path[0])
return 0;
/* "/path/to/file" or "\path\to\file" */
if (path[0] == '/' || path[0] == '\\')
return 1;
/* "C:\path\to\file" */
if (path[1] == ':' && path[2] == '\\')
return 1;
/* "scheme:/path/to/file" */
while (*path)
{
if (path[0] == ':' && path[1] == '/')
return 1;
++path;
}
return 0;
}
static const char* rc_hash_get_first_item_from_playlist(const char* path)
{
char buffer[1024];
char* disc_path;
char* ptr, *start;
size_t num_read;
char* ptr, *start, *next;
size_t num_read, path_len, file_len;
void* file_handle;
file_handle = rc_file_open(path);
@ -1056,39 +1147,61 @@ static const char* rc_hash_get_first_item_from_playlist(const char* path)
rc_file_close(file_handle);
ptr = start = buffer;
/* ignore empty and commented lines */
while (*ptr == '#' || *ptr == '\r' || *ptr == '\n')
do
{
/* ignore empty and commented lines */
while (*ptr == '#' || *ptr == '\r' || *ptr == '\n')
{
while (*ptr && *ptr != '\n')
++ptr;
if (*ptr)
++ptr;
}
/* find and extract the current line */
start = ptr;
while (*ptr && *ptr != '\n')
++ptr;
if (*ptr)
++ptr;
start = ptr;
}
next = ptr;
/* find and extract the current line */
while (*ptr && *ptr != '\n')
++ptr;
if (ptr > start && ptr[-1] == '\r')
--ptr;
*ptr = '\0';
/* remove trailing whitespace - especially '\r' */
while (ptr > start && isspace(ptr[-1]))
--ptr;
/* if we found a non-empty line, break out of the loop to process it */
file_len = ptr - start;
if (file_len)
break;
/* did we reach the end of the file? */
if (!*next)
return NULL;
/* if the line only contained whitespace, keep searching */
ptr = next + 1;
} while (1);
if (verbose_message_callback)
{
char message[2048];
snprintf(message, sizeof(message), "Extracted %s from playlist", buffer);
char message[1024];
snprintf(message, sizeof(message), "Extracted %.*s from playlist", (int)file_len, start);
verbose_message_callback(message);
}
ptr = (char*)rc_path_get_filename(path);
num_read = (ptr - path) + strlen(start) + 1;
start[file_len++] = '\0';
if (rc_hash_path_is_absolute(start))
path_len = 0;
else
path_len = rc_path_get_filename(path) - path;
disc_path = (char*)malloc(num_read);
disc_path = (char*)malloc(path_len + file_len + 1);
if (!disc_path)
return NULL;
memcpy(disc_path, path, ptr - path);
strcpy(disc_path + (ptr - path), start);
if (path_len)
memcpy(disc_path, path, path_len);
memcpy(&disc_path[path_len], start, file_len);
return disc_path;
}
@ -1149,6 +1262,14 @@ int rc_hash_generate_from_file(char hash[33], int console_id, const char* path)
/* generic whole-file hash - don't buffer */
return rc_hash_whole_file(hash, console_id, path);
case RC_CONSOLE_MSX:
case RC_CONSOLE_PC8800:
/* generic whole-file hash with m3u support - don't buffer */
if (rc_path_compare_extension(path, "m3u"))
return rc_hash_generate_from_playlist(hash, console_id, path);
return rc_hash_whole_file(hash, console_id, path);
case RC_CONSOLE_ATARI_LYNX:
case RC_CONSOLE_NINTENDO:
case RC_CONSOLE_SUPER_NINTENDO:
@ -1176,12 +1297,6 @@ int rc_hash_generate_from_file(char hash[33], int console_id, const char* path)
return rc_hash_whole_file(hash, console_id, path);
case RC_CONSOLE_PC8800:
if (rc_path_compare_extension(path, "m3u"))
return rc_hash_generate_from_playlist(hash, console_id, path);
return rc_hash_whole_file(hash, console_id, path);
case RC_CONSOLE_PLAYSTATION:
if (rc_path_compare_extension(path, "m3u"))
return rc_hash_generate_from_playlist(hash, console_id, path);
@ -1197,6 +1312,69 @@ int rc_hash_generate_from_file(char hash[33], int console_id, const char* path)
}
}
static void rc_hash_iterator_append_console(struct rc_hash_iterator* iterator, int console_id)
{
int i = 0;
while (iterator->consoles[i] != 0)
{
if (iterator->consoles[i] == console_id)
return;
++i;
}
iterator->consoles[i] = console_id;
}
static void rc_hash_initialize_dsk_iterator(struct rc_hash_iterator* iterator, const char* path)
{
size_t size = iterator->buffer_size;
if (size == 0)
{
/* attempt to use disk size to determine system */
void* file = rc_file_open(path);
if (file)
{
rc_file_seek(file, 0, SEEK_END);
size = rc_file_tell(file);
rc_file_close(file);
}
}
if (size == 512 * 9 * 80) /* 360KB */
{
/* FAT-12 3.5" DD (512 byte sectors, 9 sectors per track, 80 tracks per side */
/* FAT-12 5.25" DD double-sided (512 byte sectors, 9 sectors per track, 80 tracks per side */
iterator->consoles[0] = RC_CONSOLE_MSX;
}
else if (size == 512 * 9 * 80 * 2) /* 720KB */
{
/* FAT-12 3.5" DD double-sided (512 byte sectors, 9 sectors per track, 80 tracks per side */
iterator->consoles[0] = RC_CONSOLE_MSX;
}
else if (size == 512 * 9 * 40) /* 180KB */
{
/* FAT-12 5.25" DD (512 byte sectors, 9 sectors per track, 40 tracks per side */
iterator->consoles[0] = RC_CONSOLE_MSX;
}
else if (size == 256 * 16 * 35) /* 140KB */
{
/* Apple II new format - 256 byte sectors, 16 sectors per track, 35 tracks per side */
iterator->consoles[0] = RC_CONSOLE_APPLE_II;
}
else if (size == 256 * 13 * 35) /* 113.75KB */
{
/* Apple II old format - 256 byte sectors, 13 sectors per track, 35 tracks per side */
iterator->consoles[0] = RC_CONSOLE_APPLE_II;
}
/* once a best guess has been identified, make sure the others are added as fallbacks */
/* check MSX first, as Apple II isn't supported by RetroArch, and RAppleWin won't use the iterator */
rc_hash_iterator_append_console(iterator, RC_CONSOLE_MSX);
rc_hash_iterator_append_console(iterator, RC_CONSOLE_APPLE_II);
}
void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char* path, uint8_t* buffer, size_t buffer_size)
{
int need_path = !buffer;
@ -1210,7 +1388,7 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
do
{
const char* ext = rc_path_get_extension(path);
switch (tolower(*ext--))
switch (tolower(*ext))
{
case 'a':
if (rc_path_compare_extension(ext, "a78"))
@ -1267,12 +1445,16 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
{
iterator->consoles[0] = RC_CONSOLE_COLECOVISION;
}
else if (rc_path_compare_extension(ext, "cas"))
{
iterator->consoles[0] = RC_CONSOLE_MSX;
}
break;
case 'd':
if (rc_path_compare_extension(ext, "dsk"))
{
iterator->consoles[0] = RC_CONSOLE_APPLE_II;
rc_hash_initialize_dsk_iterator(iterator, path);
}
else if (rc_path_compare_extension(ext, "d88"))
{
@ -1337,11 +1519,11 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
if (rc_path_compare_extension(ext, "m3u"))
{
const char* disc_path = rc_hash_get_first_item_from_playlist(path);
if (disc_path)
{
path = iterator->path = disc_path;
continue; /* retry with disc_path */
}
if (!disc_path) /* did not find a disc */
return;
path = iterator->path = disc_path;
continue; /* retry with disc_path */
}
else if (rc_path_compare_extension(ext, "md"))
{
@ -1351,6 +1533,14 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
{
iterator->consoles[0] = RC_CONSOLE_POKEMON_MINI;
}
else if (rc_path_compare_extension(ext, "mx1"))
{
iterator->consoles[0] = RC_CONSOLE_MSX;
}
else if (rc_path_compare_extension(ext, "mx2"))
{
iterator->consoles[0] = RC_CONSOLE_MSX;
}
break;
case 'n':
@ -1379,6 +1569,17 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
}
break;
case 'r':
if (rc_path_compare_extension(ext, "rom"))
{
iterator->consoles[0] = RC_CONSOLE_MSX;
}
if (rc_path_compare_extension(ext, "ri"))
{
iterator->consoles[0] = RC_CONSOLE_MSX;
}
break;
case 's':
if (rc_path_compare_extension(ext, "smc") || rc_path_compare_extension(ext, "sfc"))
{
@ -1413,6 +1614,10 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
{
iterator->consoles[0] = RC_CONSOLE_WONDERSWAN;
}
else if (rc_path_compare_extension(ext, "woz"))
{
iterator->consoles[0] = RC_CONSOLE_APPLE_II;
}
break;
case 'z':

View File

@ -58,6 +58,30 @@ static void cdfs_determine_sector_size(cdfs_track_t* track)
track->stream_sector_size = 2352;
track->stream_sector_header_size = 16;
}
else
{
/* attempt to determine stream_sector_size from file size */
size_t size = intfstream_get_size(track->stream);
if ((size % 2352) == 0)
{
/* raw tracks use all 2352 bytes and have a 24 byte header */
track->stream_sector_size = 2352;
track->stream_sector_header_size = 24;
}
else if ((size % 2048) == 0)
{
/* cooked tracks eliminate all header/footer data */
track->stream_sector_size = 2048;
track->stream_sector_header_size = 0;
}
else if ((size % 2336) == 0)
{
/* MODE 2 format without 16-byte sync data */
track->stream_sector_size = 2336;
track->stream_sector_header_size = 8;
}
}
}
}
@ -540,6 +564,10 @@ struct cdfs_track_t* cdfs_open_track(const char* path,
return cdfs_open_chd_track(path, track_index);
#endif
/* if opening track 1, try opening as a raw track */
if (track_index == 1)
return cdfs_open_raw_track(path);
/* unsupported file type */
return NULL;
}
@ -563,22 +591,39 @@ struct cdfs_track_t* cdfs_open_data_track(const char* path)
cdfs_track_t* cdfs_open_raw_track(const char* path)
{
const char* ext = path_get_extension(path);
cdfs_track_t* track = NULL;
if ( string_is_equal_noncase(ext, "bin") ||
string_is_equal_noncase(ext, "iso"))
return cdfs_wrap_stream(intfstream_open_file(path,
RETRO_VFS_FILE_ACCESS_READ,
RETRO_VFS_FILE_ACCESS_HINT_NONE), 0);
{
intfstream_t* file = intfstream_open_file(path,
RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE);
/* unsupported file type */
return NULL;
track = cdfs_wrap_stream(file, 0);
if (track != NULL && track->stream_sector_size == 0)
{
cdfs_close_track(track);
track = NULL;
}
}
else
{
/* unsupported file type */
}
return track;
}
void cdfs_close_track(cdfs_track_t* track)
{
if (track)
{
intfstream_close(track->stream);
if (track->stream)
{
intfstream_close(track->stream);
free(track->stream);
}
free(track);
}
}