dep: Bump rcheevos to 3af1e2fc5188d6e932ee379942f4049ea877e648

This commit is contained in:
Stenzek
2023-08-09 19:39:42 +10:00
parent 56ac3d6c32
commit 5d750a8803
41 changed files with 9440 additions and 564 deletions

View File

@@ -48,7 +48,13 @@ static struct rc_hash_filereader* filereader = NULL;
static void* filereader_open(const char* path)
{
#if defined(__STDC_WANT_SECURE_LIB__)
FILE* fp;
fopen_s(&fp, path, "rb");
return fp;
#else
return fopen(path, "rb");
#endif
}
static void filereader_seek(void* file_handle, int64_t offset, int origin)
@@ -223,12 +229,17 @@ static uint32_t rc_cd_find_file_sector(void* track_handle, const char* path, uns
{
uint8_t buffer[2048], *tmp;
int sector;
unsigned num_sectors = 0;
size_t filename_length;
const char* slash;
if (!track_handle)
return 0;
/* we start at the root. don't need to explicitly find it */
if (*path == '\\')
++path;
filename_length = strlen(path);
slash = strrchr(path, '\\');
if (slash)
@@ -247,6 +258,8 @@ static uint32_t rc_cd_find_file_sector(void* track_handle, const char* path, uns
}
else
{
unsigned logical_block_size;
/* find the cd information */
if (!rc_cd_read_sector(track_handle, rc_cd_first_track_sector(track_handle) + 16, buffer, 256))
return 0;
@@ -255,6 +268,15 @@ static uint32_t rc_cd_find_file_sector(void* track_handle, const char* path, uns
* https://www.cdroller.com/htm/readdata.html
*/
sector = buffer[156 + 2] | (buffer[156 + 3] << 8) | (buffer[156 + 4] << 16);
/* if the table of contents spans more than one sector, it's length of section will exceed it's logical block size */
logical_block_size = (buffer[128] | (buffer[128 + 1] << 8)); /* logical block size */
if (logical_block_size == 0) {
num_sectors = 1;
} else {
num_sectors = (buffer[156 + 10] | (buffer[156 + 11] << 8) | (buffer[156 + 12] << 16) | (buffer[156 + 13] << 24)); /* length of section */
num_sectors /= logical_block_size;
}
}
/* fetch and process the directory record */
@@ -262,21 +284,34 @@ static uint32_t rc_cd_find_file_sector(void* track_handle, const char* path, uns
return 0;
tmp = buffer;
while (tmp < buffer + sizeof(buffer))
do
{
if (!*tmp)
return 0;
if (tmp >= buffer + sizeof(buffer) || !*tmp)
{
/* end of this path table block. if the path table spans multiple sectors, keep scanning */
if (num_sectors > 1)
{
--num_sectors;
if (rc_cd_read_sector(track_handle, ++sector, buffer, sizeof(buffer)))
{
tmp = buffer;
continue;
}
}
break;
}
/* filename is 33 bytes into the record and the format is "FILENAME;version" or "DIRECTORY" */
if ((tmp[33 + filename_length] == ';' || tmp[33 + filename_length] == '\0') &&
if ((tmp[32] == filename_length || tmp[33 + filename_length] == ';') &&
strncasecmp((const char*)(tmp + 33), path, filename_length) == 0)
{
sector = tmp[2] | (tmp[3] << 8) | (tmp[4] << 16);
if (verbose_message_callback)
{
snprintf((char*)buffer, sizeof(buffer), "Found %s at sector %d", path, sector);
verbose_message_callback((const char*)buffer);
char message[128];
snprintf(message, sizeof(message), "Found %s at sector %d", path, sector);
verbose_message_callback(message);
}
if (size)
@@ -287,7 +322,7 @@ static uint32_t rc_cd_find_file_sector(void* track_handle, const char* path, uns
/* the first byte of the record is the length of the record */
tmp += *tmp;
}
} while (1);
return 0;
}
@@ -347,6 +382,34 @@ int rc_path_compare_extension(const char* path, const char* ext)
/* ===================================================== */
static void rc_hash_byteswap16(uint8_t* buffer, const uint8_t* stop)
{
uint32_t* ptr = (uint32_t*)buffer;
const uint32_t* stop32 = (const uint32_t*)stop;
while (ptr < stop32)
{
uint32_t temp = *ptr;
temp = (temp & 0xFF00FF00) >> 8 |
(temp & 0x00FF00FF) << 8;
*ptr++ = temp;
}
}
static void rc_hash_byteswap32(uint8_t* buffer, const uint8_t* stop)
{
uint32_t* ptr = (uint32_t*)buffer;
const uint32_t* stop32 = (const uint32_t*)stop;
while (ptr < stop32)
{
uint32_t temp = *ptr;
temp = (temp & 0xFF000000) >> 24 |
(temp & 0x00FF0000) >> 8 |
(temp & 0x0000FF00) << 8 |
(temp & 0x000000FF) << 24;
*ptr++ = temp;
}
}
static int rc_hash_finalize(md5_state_t* md5, char hash[33])
{
md5_byte_t digest[16];
@@ -415,6 +478,9 @@ static int rc_hash_cd_file(md5_state_t* md5, void* track_handle, uint32_t sector
verbose_message_callback(message);
}
if (size < (unsigned)num_read)
size = (unsigned)num_read;
do
{
md5_append(md5, buffer, (int)num_read);
@@ -684,6 +750,142 @@ static int rc_hash_text(char hash[33], const uint8_t* buffer, size_t buffer_size
return rc_hash_finalize(&md5, hash);
}
/* helper variable only used for testing */
const char* _rc_hash_jaguar_cd_homebrew_hash = NULL;
static int rc_hash_jaguar_cd(char hash[33], const char* path)
{
uint8_t buffer[2352];
char message[128];
void* track_handle;
md5_state_t md5;
int byteswapped = 0;
unsigned size = 0;
unsigned offset = 0;
unsigned sector = 0;
unsigned remaining;
unsigned i;
/* Jaguar CD header is in the first sector of the first data track OF THE SECOND SESSION.
* The first track must be an audio track, but may be a warning message or actual game audio */
track_handle = rc_cd_open_track(path, RC_HASH_CDTRACK_FIRST_OF_SECOND_SESSION);
if (!track_handle)
return rc_hash_error("Could not open track");
/* The header is an unspecified distance into the first sector, but usually two bytes in.
* It consists of 64 bytes of "TAIR" or "ATRI" repeating, depending on whether or not the data
* is byteswapped. Then another 32 byte that reads "ATARI APPROVED DATA HEADER ATRI "
* (possibly byteswapped). Then a big-endian 32-bit value for the address where the boot code
* should be loaded, and a second big-endian 32-bit value for the size of the boot code. */
sector = rc_cd_first_track_sector(track_handle);
rc_cd_read_sector(track_handle, sector, buffer, sizeof(buffer));
for (i = 64; i < sizeof(buffer) - 32 - 4 * 3; i++)
{
if (memcmp(&buffer[i], "TARA IPARPVODED TA AEHDAREA RT I", 32) == 0)
{
byteswapped = 1;
offset = i + 32 + 4;
size = (buffer[offset] << 16) | (buffer[offset + 1] << 24) | (buffer[offset + 2]) | (buffer[offset + 3] << 8);
break;
}
else if (memcmp(&buffer[i], "ATARI APPROVED DATA HEADER ATRI ", 32) == 0)
{
byteswapped = 0;
offset = i + 32 + 4;
size = (buffer[offset] << 24) | (buffer[offset + 1] << 16) | (buffer[offset + 2] << 8) | (buffer[offset + 3]);
break;
}
}
if (size == 0) /* did not see ATARI APPROVED DATA HEADER */
{
rc_cd_close_track(track_handle);
return rc_hash_error("Not a Jaguar CD");
}
i = 0; /* only loop once */
do
{
md5_init(&md5);
offset += 4;
if (verbose_message_callback)
{
snprintf(message, sizeof(message), "Hashing boot executable (%u bytes starting at %u bytes into sector %u)", size, offset, sector);
rc_hash_verbose(message);
}
if (size > MAX_BUFFER_SIZE)
size = MAX_BUFFER_SIZE;
do
{
if (byteswapped)
rc_hash_byteswap16(buffer, &buffer[sizeof(buffer)]);
remaining = sizeof(buffer) - offset;
if (remaining >= size)
{
md5_append(&md5, &buffer[offset], size);
size = 0;
break;
}
md5_append(&md5, &buffer[offset], remaining);
size -= remaining;
offset = 0;
} while (rc_cd_read_sector(track_handle, ++sector, buffer, sizeof(buffer)) == sizeof(buffer));
rc_cd_close_track(track_handle);
if (size > 0)
return rc_hash_error("Not enough data");
rc_hash_finalize(&md5, hash);
/* homebrew games all seem to have the same boot executable and store the actual game code in track 2.
* if we generated something other than the homebrew hash, return it. assume all homebrews are byteswapped. */
if (strcmp(hash, "254487b59ab21bc005338e85cbf9fd2f") != 0 || !byteswapped) {
if (_rc_hash_jaguar_cd_homebrew_hash == NULL || strcmp(hash, _rc_hash_jaguar_cd_homebrew_hash) != 0)
return 1;
}
/* if we've already been through the loop a second time, just return the hash */
if (i == 1)
return 1;
++i;
if (verbose_message_callback)
{
snprintf(message, sizeof(message), "Potential homebrew at sector %u, checking for KART data in track 2", sector);
rc_hash_verbose(message);
}
track_handle = rc_cd_open_track(path, 2);
if (!track_handle)
return rc_hash_error("Could not open track");
/* track 2 of the homebrew code has the 64 bytes or ATRI followed by 32 bytes of "ATARI APPROVED DATA HEADER ATRI!",
* then 64 bytes of KART repeating. */
sector = rc_cd_first_track_sector(track_handle);
rc_cd_read_sector(track_handle, sector, buffer, sizeof(buffer));
if (memcmp(&buffer[0x5E], "RT!IRTKA", 8) != 0)
return rc_hash_error("Homebrew executable not found in track 2");
/* found KART data*/
if (verbose_message_callback)
{
snprintf(message, sizeof(message), "Found KART data in track 2");
rc_hash_verbose(message);
}
offset = 0xA6;
size = (buffer[offset] << 16) | (buffer[offset + 1] << 24) | (buffer[offset + 2]) | (buffer[offset + 3] << 8);
} while (1);
}
static int rc_hash_lynx(char hash[33], const uint8_t* buffer, size_t buffer_size)
{
/* if the file contains a header, ignore it */
@@ -698,6 +900,70 @@ static int rc_hash_lynx(char hash[33], const uint8_t* buffer, size_t buffer_size
return rc_hash_buffer(hash, buffer, buffer_size);
}
static int rc_hash_neogeo_cd(char hash[33], const char* path)
{
char buffer[1024], *ptr;
void* track_handle;
uint32_t sector;
unsigned size;
md5_state_t md5;
track_handle = rc_cd_open_track(path, 1);
if (!track_handle)
return rc_hash_error("Could not open track");
/* https://wiki.neogeodev.org/index.php?title=IPL_file, https://wiki.neogeodev.org/index.php?title=PRG_file
* IPL file specifies data to be loaded before the game starts. PRG files are the executable code
*/
sector = rc_cd_find_file_sector(track_handle, "IPL.TXT", &size);
if (!sector)
{
rc_cd_close_track(track_handle);
return rc_hash_error("Not a NeoGeo CD game disc");
}
if (rc_cd_read_sector(track_handle, sector, buffer, sizeof(buffer)) == 0)
{
rc_cd_close_track(track_handle);
return 0;
}
md5_init(&md5);
buffer[sizeof(buffer) - 1] = '\0';
ptr = &buffer[0];
do
{
char* start = ptr;
while (*ptr && *ptr != '.')
++ptr;
if (strncasecmp(ptr, ".PRG", 4) == 0)
{
ptr += 4;
*ptr++ = '\0';
sector = rc_cd_find_file_sector(track_handle, start, &size);
if (!sector || !rc_hash_cd_file(&md5, track_handle, sector, NULL, size, start))
{
char error[128];
rc_cd_close_track(track_handle);
snprintf(error, sizeof(error), "Could not read %.16s", start);
return rc_hash_error(error);
}
}
while (*ptr && *ptr != '\n')
++ptr;
if (*ptr != '\n')
break;
++ptr;
} while (*ptr != '\0' && *ptr != '\x1a');
rc_cd_close_track(track_handle);
return rc_hash_finalize(&md5, hash);
}
static int rc_hash_nes(char hash[33], const uint8_t* buffer, size_t buffer_size)
{
/* if the file contains a header, ignore it */
@@ -719,34 +985,6 @@ static int rc_hash_nes(char hash[33], const uint8_t* buffer, size_t buffer_size)
return rc_hash_buffer(hash, buffer, buffer_size);
}
static void rc_hash_v64_to_z64(uint8_t* buffer, const uint8_t* stop)
{
uint32_t* ptr = (uint32_t*)buffer;
const uint32_t* stop32 = (const uint32_t*)stop;
while (ptr < stop32)
{
uint32_t temp = *ptr;
temp = (temp & 0xFF00FF00) >> 8 |
(temp & 0x00FF00FF) << 8;
*ptr++ = temp;
}
}
static void rc_hash_n64_to_z64(uint8_t* buffer, const uint8_t* stop)
{
uint32_t* ptr = (uint32_t*)buffer;
const uint32_t* stop32 = (const uint32_t*)stop;
while (ptr < stop32)
{
uint32_t temp = *ptr;
temp = (temp & 0xFF000000) >> 24 |
(temp & 0x00FF0000) >> 8 |
(temp & 0x0000FF00) << 8 |
(temp & 0x000000FF) << 24;
*ptr++ = temp;
}
}
static int rc_hash_n64(char hash[33], const char* path)
{
uint8_t* buffer;
@@ -787,6 +1025,9 @@ static int rc_hash_n64(char hash[33], const char* path)
rc_hash_verbose("converting n64 to z64");
is_n64 = 1;
}
else if (buffer[0] == 0xE8 || buffer[0] == 0x22) /* ndd format (don't byteswap) */
{
}
else
{
free(buffer);
@@ -818,9 +1059,9 @@ static int rc_hash_n64(char hash[33], const char* path)
rc_file_read(file_handle, buffer, (int)buffer_size);
if (is_v64)
rc_hash_v64_to_z64(buffer, stop);
rc_hash_byteswap16(buffer, stop);
else if (is_n64)
rc_hash_n64_to_z64(buffer, stop);
rc_hash_byteswap32(buffer, stop);
md5_append(&md5, buffer, (int)buffer_size);
remaining -= buffer_size;
@@ -832,9 +1073,9 @@ static int rc_hash_n64(char hash[33], const char* path)
stop = buffer + remaining;
if (is_v64)
rc_hash_v64_to_z64(buffer, stop);
rc_hash_byteswap16(buffer, stop);
else if (is_n64)
rc_hash_n64_to_z64(buffer, stop);
rc_hash_byteswap32(buffer, stop);
md5_append(&md5, buffer, (int)remaining);
}
@@ -957,6 +1198,121 @@ static int rc_hash_nintendo_ds(char hash[33], const char* path)
return rc_hash_finalize(&md5, hash);
}
static int rc_hash_gamecube(char hash[33], const char* path)
{
md5_state_t md5;
void* file_handle;
const uint32_t BASE_HEADER_SIZE = 0x2440;
const uint32_t MAX_HEADER_SIZE = 1024 * 1024;
uint32_t apploader_header_size, apploader_body_size, apploader_trailer_size, header_size;
uint8_t quad_buffer[4];
uint8_t addr_buffer[0xD8];
uint8_t* buffer;
uint32_t dol_offset;
uint32_t dol_offsets[18];
uint32_t dol_sizes[18];
uint32_t dol_buf_size = 0;
uint32_t ix;
file_handle = rc_file_open(path);
if (!file_handle)
return rc_hash_error("Could not open file");
/* Verify Gamecube */
rc_file_seek(file_handle, 0x1c, SEEK_SET);
rc_file_read(file_handle, quad_buffer, 4);
if (quad_buffer[0] != 0xC2|| quad_buffer[1] != 0x33 || quad_buffer[2] != 0x9F || quad_buffer[3] != 0x3D)
{
rc_file_close(file_handle);
return rc_hash_error("Not a Gamecube disc");
}
/* GetApploaderSize */
rc_file_seek(file_handle, BASE_HEADER_SIZE + 0x14, SEEK_SET);
apploader_header_size = 0x20;
rc_file_read(file_handle, quad_buffer, 4);
apploader_body_size =
(quad_buffer[0] << 24) | (quad_buffer[1] << 16) | (quad_buffer[2] << 8) | quad_buffer[3];
rc_file_read(file_handle, quad_buffer, 4);
apploader_trailer_size =
(quad_buffer[0] << 24) | (quad_buffer[1] << 16) | (quad_buffer[2] << 8) | quad_buffer[3];
header_size = BASE_HEADER_SIZE + apploader_header_size + apploader_body_size + apploader_trailer_size;
if (header_size > MAX_HEADER_SIZE) header_size = MAX_HEADER_SIZE;
/* Hash headers */
buffer = (uint8_t*)malloc(header_size);
if (!buffer)
{
rc_file_close(file_handle);
return rc_hash_error("Could not allocate temporary buffer");
}
rc_file_seek(file_handle, 0, SEEK_SET);
rc_file_read(file_handle, buffer, header_size);
md5_init(&md5);
if (verbose_message_callback)
{
char message[128];
snprintf(message, sizeof(message), "Hashing %u byte header", header_size);
verbose_message_callback(message);
}
md5_append(&md5, buffer, header_size);
/* GetBootDOLOffset
* Base header size is guaranteed larger than 0x423 therefore buffer contains dol_offset right now
*/
dol_offset = (buffer[0x420] << 24) | (buffer[0x421] << 16) | (buffer[0x422] << 8) | buffer[0x423];
free(buffer);
/* Find offsetsand sizes for the 7 main.dol code segments and 11 main.dol data segments */
rc_file_seek(file_handle, dol_offset, SEEK_SET);
rc_file_read(file_handle, addr_buffer, 0xD8);
for (ix = 0; ix < 18; ix++)
{
dol_offsets[ix] =
(addr_buffer[0x0 + ix * 4] << 24) |
(addr_buffer[0x1 + ix * 4] << 16) |
(addr_buffer[0x2 + ix * 4] << 8) |
addr_buffer[0x3 + ix * 4];
dol_sizes[ix] =
(addr_buffer[0x90 + ix * 4] << 24) |
(addr_buffer[0x91 + ix * 4] << 16) |
(addr_buffer[0x92 + ix * 4] << 8) |
addr_buffer[0x93 + ix * 4];
dol_buf_size = (dol_sizes[ix] > dol_buf_size) ? dol_sizes[ix] : dol_buf_size;
}
/* Iterate through the 18 main.dol segments and hash each */
buffer = (uint8_t*)malloc(dol_buf_size);
if (!buffer)
{
rc_file_close(file_handle);
return rc_hash_error("Could not allocate temporary buffer");
}
for (ix = 0; ix < 18; ix++)
{
if (dol_sizes[ix] == 0)
continue;
rc_file_seek(file_handle, dol_offsets[ix], SEEK_SET);
rc_file_read(file_handle, buffer, dol_sizes[ix]);
if (verbose_message_callback)
{
char message[128];
if (ix < 7)
snprintf(message, sizeof(message), "Hashing %u byte main.dol code segment %u", dol_sizes[ix], ix);
else
snprintf(message, sizeof(message), "Hashing %u byte main.dol data segment %u", dol_sizes[ix], ix - 7);
verbose_message_callback(message);
}
md5_append(&md5, buffer, dol_sizes[ix]);
}
/* Finalize */
rc_file_close(file_handle);
free(buffer);
return rc_hash_finalize(&md5, hash);
}
static int rc_hash_pce(char hash[33], const uint8_t* buffer, size_t buffer_size)
{
/* if the file contains a header, ignore it (expect ROM data to be multiple of 128KB) */
@@ -1290,7 +1646,7 @@ static int rc_hash_find_playstation_executable(void* track_handle, const char* b
if (strncmp(ptr, cdrom_prefix, cdrom_prefix_len) == 0)
ptr += cdrom_prefix_len;
if (*ptr == '\\')
while (*ptr == '\\')
++ptr;
start = ptr;
@@ -1454,18 +1810,30 @@ static int rc_hash_psp(char hash[33], const char* path)
*/
sector = rc_cd_find_file_sector(track_handle, "PSP_GAME\\PARAM.SFO", &size);
if (!sector)
{
rc_cd_close_track(track_handle);
return rc_hash_error("Not a PSP game disc");
}
md5_init(&md5);
if (!rc_hash_cd_file(&md5, track_handle, sector, NULL, size, "PSP_GAME\\PARAM.SFO"))
{
rc_cd_close_track(track_handle);
return 0;
}
sector = rc_cd_find_file_sector(track_handle, "PSP_GAME\\SYSDIR\\EBOOT.BIN", &size);
if (!sector)
{
rc_cd_close_track(track_handle);
return rc_hash_error("Could not find primary executable");
}
if (!rc_hash_cd_file(&md5, track_handle, sector, NULL, size, "PSP_GAME\\SYSDIR\\EBOOT.BIN"))
{
rc_cd_close_track(track_handle);
return 0;
}
rc_cd_close_track(track_handle);
return rc_hash_finalize(&md5, hash);
@@ -1527,7 +1895,11 @@ static struct rc_buffered_file rc_buffered_file;
static void* rc_file_open_buffered_file(const char* path)
{
struct rc_buffered_file* handle = (struct rc_buffered_file*)malloc(sizeof(struct rc_buffered_file));
memcpy(handle, &rc_buffered_file, sizeof(rc_buffered_file));
(void)path;
if (handle)
memcpy(handle, &rc_buffered_file, sizeof(rc_buffered_file));
return handle;
}
@@ -1631,7 +2003,9 @@ int rc_hash_generate_from_buffer(char hash[33], int console_id, const uint8_t* b
case RC_CONSOLE_SEGA_32X:
case RC_CONSOLE_SG1000:
case RC_CONSOLE_SUPERVISION:
case RC_CONSOLE_TI83:
case RC_CONSOLE_TIC80:
case RC_CONSOLE_UZEBOX:
case RC_CONSOLE_VECTREX:
case RC_CONSOLE_VIRTUAL_BOY:
case RC_CONSOLE_WASM4:
@@ -1659,6 +2033,7 @@ int rc_hash_generate_from_buffer(char hash[33], int console_id, const uint8_t* b
case RC_CONSOLE_NINTENDO_64:
case RC_CONSOLE_NINTENDO_DS:
case RC_CONSOLE_NINTENDO_DSI:
return rc_hash_file_from_buffer(hash, console_id, buffer, buffer_size);
}
}
@@ -1922,7 +2297,9 @@ int rc_hash_generate_from_file(char hash[33], int console_id, const char* path)
case RC_CONSOLE_SEGA_32X:
case RC_CONSOLE_SG1000:
case RC_CONSOLE_SUPERVISION:
case RC_CONSOLE_TI83:
case RC_CONSOLE_TIC80:
case RC_CONSOLE_UZEBOX:
case RC_CONSOLE_VECTREX:
case RC_CONSOLE_VIRTUAL_BOY:
case RC_CONSOLE_WASM4:
@@ -1946,6 +2323,7 @@ int rc_hash_generate_from_file(char hash[33], int console_id, const char* path)
case RC_CONSOLE_ATARI_7800:
case RC_CONSOLE_ATARI_LYNX:
case RC_CONSOLE_NINTENDO:
case RC_CONSOLE_PC_ENGINE:
case RC_CONSOLE_SUPER_NINTENDO:
/* additional logic whole-file hash - buffer then call rc_hash_generate_from_buffer */
return rc_hash_buffered_file(hash, console_id, path);
@@ -1959,13 +2337,29 @@ int rc_hash_generate_from_file(char hash[33], int console_id, const char* path)
case RC_CONSOLE_ARCADE:
return rc_hash_arcade(hash, path);
case RC_CONSOLE_ATARI_JAGUAR_CD:
return rc_hash_jaguar_cd(hash, path);
case RC_CONSOLE_DREAMCAST:
if (rc_path_compare_extension(path, "m3u"))
return rc_hash_generate_from_playlist(hash, console_id, path);
return rc_hash_dreamcast(hash, path);
case RC_CONSOLE_GAMECUBE:
return rc_hash_gamecube(hash, path);
case RC_CONSOLE_NEO_GEO_CD:
return rc_hash_neogeo_cd(hash, path);
case RC_CONSOLE_NINTENDO_64:
return rc_hash_n64(hash, path);
case RC_CONSOLE_NINTENDO_DS:
case RC_CONSOLE_NINTENDO_DSI:
return rc_hash_nintendo_ds(hash, path);
case RC_CONSOLE_PC_ENGINE:
case RC_CONSOLE_PC_ENGINE_CD:
if (rc_path_compare_extension(path, "cue") || rc_path_compare_extension(path, "chd"))
return rc_hash_pce_cd(hash, path);
@@ -1995,12 +2389,6 @@ int rc_hash_generate_from_file(char hash[33], int console_id, const char* path)
case RC_CONSOLE_PSP:
return rc_hash_psp(hash, path);
case RC_CONSOLE_DREAMCAST:
if (rc_path_compare_extension(path, "m3u"))
return rc_hash_generate_from_playlist(hash, console_id, path);
return rc_hash_dreamcast(hash, path);
case RC_CONSOLE_SEGA_CD:
case RC_CONSOLE_SATURN:
if (rc_path_compare_extension(path, "m3u"))
@@ -2077,7 +2465,7 @@ static void rc_hash_initialize_dsk_iterator(struct rc_hash_iterator* iterator, c
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)
void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char* path, const uint8_t* buffer, size_t buffer_size)
{
int need_path = !buffer;
@@ -2108,6 +2496,15 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
}
break;
case '8':
/* http://tibasicdev.wikidot.com/file-extensions */
if (rc_path_compare_extension(ext, "83g") ||
rc_path_compare_extension(ext, "83p"))
{
iterator->consoles[0] = RC_CONSOLE_TI83;
}
break;
case 'a':
if (rc_path_compare_extension(ext, "a78"))
{
@@ -2162,9 +2559,11 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
iterator->consoles[1] = RC_CONSOLE_PLAYSTATION_2;
iterator->consoles[2] = RC_CONSOLE_DREAMCAST;
iterator->consoles[3] = RC_CONSOLE_SEGA_CD; /* ASSERT: handles both Sega CD and Saturn */
iterator->consoles[4] = RC_CONSOLE_PC_ENGINE;
iterator->consoles[4] = RC_CONSOLE_PC_ENGINE_CD;
iterator->consoles[5] = RC_CONSOLE_3DO;
iterator->consoles[6] = RC_CONSOLE_PCFX;
iterator->consoles[7] = RC_CONSOLE_NEO_GEO_CD;
iterator->consoles[8] = RC_CONSOLE_ATARI_JAGUAR_CD;
need_path = 1;
}
else if (rc_path_compare_extension(ext, "chd"))
@@ -2173,7 +2572,7 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
iterator->consoles[1] = RC_CONSOLE_PLAYSTATION_2;
iterator->consoles[2] = RC_CONSOLE_DREAMCAST;
iterator->consoles[3] = RC_CONSOLE_SEGA_CD; /* ASSERT: handles both Sega CD and Saturn */
iterator->consoles[4] = RC_CONSOLE_PC_ENGINE;
iterator->consoles[4] = RC_CONSOLE_PC_ENGINE_CD;
iterator->consoles[5] = RC_CONSOLE_3DO;
iterator->consoles[6] = RC_CONSOLE_PCFX;
need_path = 1;
@@ -2199,7 +2598,7 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
}
else if (rc_path_compare_extension(ext, "d64"))
{
iterator->consoles[0] = RC_CONSOLE_COMMODORE_64;
iterator->consoles[0] = RC_CONSOLE_COMMODORE_64;
}
else if (rc_path_compare_extension(ext, "d88"))
{
@@ -2219,7 +2618,7 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
}
else if (rc_path_compare_extension(ext, "fd"))
{
iterator->consoles[0] = RC_CONSOLE_THOMSONTO8; /* disk */
iterator->consoles[0] = RC_CONSOLE_THOMSONTO8; /* disk */
}
break;
@@ -2330,7 +2729,7 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
}
else if (rc_path_compare_extension(ext, "nds"))
{
iterator->consoles[0] = RC_CONSOLE_NINTENDO_DS;
iterator->consoles[0] = RC_CONSOLE_NINTENDO_DS; /* ASSERT: handles both DS and DSi */
}
else if (rc_path_compare_extension(ext, "n64") ||
rc_path_compare_extension(ext, "ndd"))
@@ -2412,6 +2811,13 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
}
break;
case 'u':
if (rc_path_compare_extension(ext, "uze"))
{
iterator->consoles[0] = RC_CONSOLE_UZEBOX;
}
break;
case 'v':
if (rc_path_compare_extension(ext, "vb"))
{