mirror of
https://github.com/WinampDesktop/winamp.git
synced 2025-06-19 05:15:46 -04:00
Upgrade rcheevos to v10.1.0
This commit is contained in:

committed by
Connor McLaughlin

parent
9d26a85967
commit
d567f1e870
@ -8,8 +8,8 @@
|
||||
|
||||
/* internal helper functions in hash.c */
|
||||
extern void* rc_file_open(const char* path);
|
||||
extern void rc_file_seek(void* file_handle, size_t offset, int origin);
|
||||
extern size_t rc_file_tell(void* file_handle);
|
||||
extern void rc_file_seek(void* file_handle, int64_t offset, int origin);
|
||||
extern int64_t rc_file_tell(void* file_handle);
|
||||
extern size_t rc_file_read(void* file_handle, void* buffer, int requested_bytes);
|
||||
extern void rc_file_close(void* file_handle);
|
||||
extern int rc_hash_error(const char* message);
|
||||
@ -22,8 +22,8 @@ struct cdrom_t
|
||||
void* file_handle;
|
||||
int sector_size;
|
||||
int sector_header_size;
|
||||
int first_sector_offset;
|
||||
int first_sector;
|
||||
int64_t first_sector_offset;
|
||||
};
|
||||
|
||||
static void cdreader_determine_sector_size(struct cdrom_t* cdrom)
|
||||
@ -38,13 +38,14 @@ static void cdreader_determine_sector_size(struct cdrom_t* cdrom)
|
||||
};
|
||||
|
||||
unsigned char header[32];
|
||||
const int toc_sector = 16;
|
||||
const int64_t toc_sector = 16;
|
||||
|
||||
cdrom->sector_size = 0;
|
||||
cdrom->sector_header_size = 0;
|
||||
|
||||
rc_file_seek(cdrom->file_handle, toc_sector * 2352 + cdrom->first_sector_offset, SEEK_SET);
|
||||
rc_file_read(cdrom->file_handle, header, sizeof(header));
|
||||
if (rc_file_read(cdrom->file_handle, header, sizeof(header)) < sizeof(header))
|
||||
return;
|
||||
|
||||
if (memcmp(header, sync_pattern, 12) == 0)
|
||||
{
|
||||
@ -219,9 +220,9 @@ static char* cdreader_get_bin_path(const char* cue_path, const char* bin_name)
|
||||
return bin_filename;
|
||||
}
|
||||
|
||||
static size_t cdreader_get_bin_size(const char* cue_path, const char* bin_name)
|
||||
static int64_t cdreader_get_bin_size(const char* cue_path, const char* bin_name)
|
||||
{
|
||||
size_t size = 0;
|
||||
int64_t size = 0;
|
||||
char* bin_filename = cdreader_get_bin_path(cue_path, bin_name);
|
||||
if (bin_filename)
|
||||
{
|
||||
@ -242,7 +243,7 @@ static size_t cdreader_get_bin_size(const char* cue_path, const char* bin_name)
|
||||
static void* cdreader_open_cue_track(const char* path, uint32_t track)
|
||||
{
|
||||
void* file_handle;
|
||||
size_t file_offset = 0;
|
||||
int64_t file_offset = 0;
|
||||
char buffer[1024], mode[16];
|
||||
char* bin_filename;
|
||||
char file[256];
|
||||
@ -253,14 +254,14 @@ static void* cdreader_open_cue_track(const char* path, uint32_t track)
|
||||
int previous_sector_size = 0;
|
||||
int previous_index_sector_offset = 0;
|
||||
int previous_track_is_data = 0;
|
||||
int previous_track_sector_offset = 0;
|
||||
int64_t previous_track_sector_offset = 0;
|
||||
char previous_track_mode[16];
|
||||
int largest_track = 0;
|
||||
int largest_track_sector_count = 0;
|
||||
int largest_track_offset = 0;
|
||||
int64_t largest_track_offset = 0;
|
||||
char largest_track_mode[16];
|
||||
char largest_track_file[256];
|
||||
int offset = 0;
|
||||
int64_t offset = 0;
|
||||
int done = 0;
|
||||
size_t num_read = 0;
|
||||
struct cdrom_t* cdrom = NULL;
|
||||
@ -290,7 +291,8 @@ static void* cdreader_open_cue_track(const char* path, uint32_t track)
|
||||
if (strncasecmp(ptr, "INDEX ", 6) == 0)
|
||||
{
|
||||
int m = 0, s = 0, f = 0;
|
||||
int index, sector_offset;
|
||||
int index;
|
||||
int sector_offset;
|
||||
|
||||
ptr += 6;
|
||||
index = atoi(ptr);
|
||||
@ -336,7 +338,9 @@ static void* cdreader_open_cue_track(const char* path, uint32_t track)
|
||||
++scan;
|
||||
*scan = '\0';
|
||||
|
||||
snprintf(message, sizeof(message), "Found %s track %d (sector size %d, track starts at %d)", mode, current_track, sector_size, offset);
|
||||
/* it's undesirable to truncate offset to 32-bits, but %lld isn't defined in c89. */
|
||||
snprintf(message, sizeof(message), "Found %s track %d (sector size %d, track starts at %d)",
|
||||
mode, current_track, sector_size, (int)offset);
|
||||
verbose_message_callback(message);
|
||||
}
|
||||
|
||||
@ -501,7 +505,8 @@ static void* cdreader_open_cue_track(const char* path, uint32_t track)
|
||||
if (verbose_message_callback)
|
||||
{
|
||||
if (cdrom->first_sector_offset)
|
||||
snprintf((char*)buffer, sizeof(buffer), "Opened track %d (sector size %d, track starts at %d)", track, cdrom->sector_size, cdrom->first_sector_offset);
|
||||
snprintf((char*)buffer, sizeof(buffer), "Opened track %d (sector size %d, track starts at %d)",
|
||||
track, cdrom->sector_size, (int)cdrom->first_sector_offset);
|
||||
else
|
||||
snprintf((char*)buffer, sizeof(buffer), "Opened track %d (sector size %d)", track, cdrom->sector_size);
|
||||
|
||||
@ -531,7 +536,7 @@ static void* cdreader_open_gdi_track(const char* path, uint32_t track)
|
||||
char mode[16] = "MODE1/";
|
||||
char sector_size[16];
|
||||
char file[256];
|
||||
size_t track_size;
|
||||
int64_t track_size;
|
||||
int track_type;
|
||||
char* bin_path = "";
|
||||
uint32_t current_track = 0;
|
||||
@ -539,14 +544,14 @@ static void* cdreader_open_gdi_track(const char* path, uint32_t track)
|
||||
int lba = 0;
|
||||
|
||||
uint32_t largest_track = 0;
|
||||
size_t largest_track_size = 0;
|
||||
int64_t largest_track_size = 0;
|
||||
char largest_track_file[256];
|
||||
char largest_track_sector_size[16];
|
||||
int largest_track_lba = 0;
|
||||
|
||||
int found = 0;
|
||||
size_t num_read = 0;
|
||||
size_t file_offset = 0;
|
||||
int64_t file_offset = 0;
|
||||
struct cdrom_t* cdrom = NULL;
|
||||
|
||||
file_handle = rc_file_open(path);
|
||||
@ -584,6 +589,9 @@ static void* cdreader_open_gdi_track(const char* path, uint32_t track)
|
||||
++ptr;
|
||||
|
||||
/* line format: [trackid] [lba] [type] [sectorsize] [file] [?] */
|
||||
while (isspace(*ptr))
|
||||
++ptr;
|
||||
|
||||
current_track = (uint32_t)atoi(ptr);
|
||||
if (track && current_track != track)
|
||||
continue;
|
||||
@ -592,22 +600,34 @@ static void* cdreader_open_gdi_track(const char* path, uint32_t track)
|
||||
++ptr;
|
||||
++ptr;
|
||||
|
||||
while (isspace(*ptr))
|
||||
++ptr;
|
||||
|
||||
lba = atoi(ptr);
|
||||
while (isdigit(*ptr))
|
||||
++ptr;
|
||||
++ptr;
|
||||
|
||||
while (isspace(*ptr))
|
||||
++ptr;
|
||||
|
||||
track_type = atoi(ptr);
|
||||
while (isdigit(*ptr))
|
||||
++ptr;
|
||||
++ptr;
|
||||
|
||||
while (isspace(*ptr))
|
||||
++ptr;
|
||||
|
||||
ptr2 = sector_size;
|
||||
while (isdigit(*ptr))
|
||||
*ptr2++ = *ptr++;
|
||||
*ptr2 = '\0';
|
||||
++ptr;
|
||||
|
||||
while (isspace(*ptr))
|
||||
++ptr;
|
||||
|
||||
ptr2 = file;
|
||||
if (*ptr == '\"')
|
||||
{
|
||||
@ -698,6 +718,8 @@ static void* cdreader_open_gdi_track(const char* path, uint32_t track)
|
||||
cdrom = NULL;
|
||||
}
|
||||
|
||||
free(bin_path);
|
||||
|
||||
return cdrom;
|
||||
}
|
||||
|
||||
@ -717,7 +739,7 @@ static void* cdreader_open_track(const char* path, uint32_t track)
|
||||
|
||||
static size_t cdreader_read_sector(void* track_handle, uint32_t sector, void* buffer, size_t requested_bytes)
|
||||
{
|
||||
size_t sector_start;
|
||||
int64_t sector_start;
|
||||
size_t num_read, total_read = 0;
|
||||
uint8_t* buffer_ptr = (uint8_t*)buffer;
|
||||
|
||||
@ -725,7 +747,7 @@ static size_t cdreader_read_sector(void* track_handle, uint32_t sector, void* bu
|
||||
if (!cdrom)
|
||||
return 0;
|
||||
|
||||
sector_start = sector * cdrom->sector_size + cdrom->sector_header_size + cdrom->first_sector_offset;
|
||||
sector_start = (int64_t)sector * cdrom->sector_size + cdrom->sector_header_size + cdrom->first_sector_offset;
|
||||
|
||||
while (requested_bytes > 2048)
|
||||
{
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "md5.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/* arbitrary limit to prevent allocating and hashing large files */
|
||||
@ -50,14 +51,27 @@ static void* filereader_open(const char* path)
|
||||
return fopen(path, "rb");
|
||||
}
|
||||
|
||||
static void filereader_seek(void* file_handle, size_t offset, int origin)
|
||||
static void filereader_seek(void* file_handle, int64_t offset, int origin)
|
||||
{
|
||||
fseek((FILE*)file_handle, (long)offset, origin);
|
||||
#if defined(_WIN32)
|
||||
_fseeki64((FILE*)file_handle, offset, origin);
|
||||
#elif defined(_LARGEFILE64_SOURCE)
|
||||
fseeko64((FILE*)file_handle, offset, origin);
|
||||
#else
|
||||
#pragma message("Using generic fseek may fail for large files")
|
||||
fseek((FILE*)file_handle, offset, origin);
|
||||
#endif
|
||||
}
|
||||
|
||||
static size_t filereader_tell(void* file_handle)
|
||||
static int64_t filereader_tell(void* file_handle)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return _ftelli64((FILE*)file_handle);
|
||||
#elif defined(_LARGEFILE64_SOURCE)
|
||||
return ftello64((FILE*)file_handle);
|
||||
#else
|
||||
return ftell((FILE*)file_handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
static size_t filereader_read(void* file_handle, void* buffer, size_t requested_bytes)
|
||||
@ -118,13 +132,13 @@ void* rc_file_open(const char* path)
|
||||
return handle;
|
||||
}
|
||||
|
||||
void rc_file_seek(void* file_handle, size_t offset, int origin)
|
||||
void rc_file_seek(void* file_handle, int64_t offset, int origin)
|
||||
{
|
||||
if (filereader)
|
||||
filereader->seek(file_handle, offset, origin);
|
||||
}
|
||||
|
||||
size_t rc_file_tell(void* file_handle)
|
||||
int64_t rc_file_tell(void* file_handle)
|
||||
{
|
||||
return (filereader) ? filereader->tell(file_handle) : 0;
|
||||
}
|
||||
@ -367,6 +381,50 @@ static int rc_hash_buffer(char hash[33], uint8_t* buffer, size_t buffer_size)
|
||||
return rc_hash_finalize(&md5, hash);
|
||||
}
|
||||
|
||||
static int rc_hash_cd_file(md5_state_t* md5, void* track_handle, uint32_t sector, const char* name, unsigned size, const char* description)
|
||||
{
|
||||
uint8_t buffer[2048];
|
||||
size_t num_read;
|
||||
|
||||
if ((num_read = rc_cd_read_sector(track_handle, sector, buffer, sizeof(buffer))) < sizeof(buffer))
|
||||
{
|
||||
char message[128];
|
||||
snprintf(message, sizeof(message), "Could not read %s", description);
|
||||
return rc_hash_error(message);
|
||||
}
|
||||
|
||||
if (size > MAX_BUFFER_SIZE)
|
||||
size = MAX_BUFFER_SIZE;
|
||||
|
||||
if (verbose_message_callback)
|
||||
{
|
||||
char message[128];
|
||||
if (name)
|
||||
snprintf(message, sizeof(message), "Hashing %s title (%u bytes) and contents (%u bytes) ", name, (unsigned)strlen(name), size);
|
||||
else
|
||||
snprintf(message, sizeof(message), "Hashing %s contents (%u bytes)", description, size);
|
||||
|
||||
verbose_message_callback(message);
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
md5_append(md5, buffer, (int)num_read);
|
||||
|
||||
size -= (unsigned)num_read;
|
||||
if (size == 0)
|
||||
break;
|
||||
|
||||
++sector;
|
||||
if (size >= sizeof(buffer))
|
||||
num_read = rc_cd_read_sector(track_handle, sector, buffer, sizeof(buffer));
|
||||
else
|
||||
num_read = rc_cd_read_sector(track_handle, sector, buffer, size);
|
||||
} while (num_read > 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int rc_hash_3do(char hash[33], const char* path)
|
||||
{
|
||||
uint8_t buffer[2048];
|
||||
@ -500,6 +558,20 @@ static int rc_hash_3do(char hash[33], const char* path)
|
||||
return rc_hash_finalize(&md5, hash);
|
||||
}
|
||||
|
||||
static int rc_hash_7800(char hash[33], uint8_t* buffer, size_t buffer_size)
|
||||
{
|
||||
/* if the file contains a header, ignore it */
|
||||
if (memcmp(&buffer[1], "ATARI7800", 9) == 0)
|
||||
{
|
||||
rc_hash_verbose("Ignoring 7800 header");
|
||||
|
||||
buffer += 128;
|
||||
buffer_size -= 128;
|
||||
}
|
||||
|
||||
return rc_hash_buffer(hash, buffer, buffer_size);
|
||||
}
|
||||
|
||||
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 */
|
||||
@ -614,7 +686,7 @@ static int rc_hash_nintendo_ds(char hash[33], const char* path)
|
||||
uint8_t* hash_buffer;
|
||||
unsigned int hash_size, arm9_size, arm9_addr, arm7_size, arm7_addr, icon_addr;
|
||||
size_t num_read;
|
||||
int offset = 0;
|
||||
int64_t offset = 0;
|
||||
md5_state_t md5;
|
||||
void* file_handle;
|
||||
|
||||
@ -745,7 +817,10 @@ static int rc_hash_pce_track(char hash[33], void* track_handle)
|
||||
* the string "PC Engine CD-ROM SYSTEM" should exist at 32 bytes into the sector
|
||||
* http://shu.sheldows.com/shu/download/pcedocs/pce_cdrom.html
|
||||
*/
|
||||
rc_cd_read_sector(track_handle, 1, buffer, 128);
|
||||
if (rc_cd_read_sector(track_handle, 1, buffer, 128) < 128)
|
||||
{
|
||||
return rc_hash_error("Not a PC Engine CD");
|
||||
}
|
||||
|
||||
/* normal PC Engine CD will have a header block in sector 1 */
|
||||
if (memcmp("PC Engine CD-ROM SYSTEM", &buffer[32], 23) == 0)
|
||||
@ -914,13 +989,13 @@ static int rc_hash_pcfx_cd(char hash[33], const char* path)
|
||||
|
||||
static int rc_hash_dreamcast(char hash[33], const char* path)
|
||||
{
|
||||
uint8_t buffer[2048];
|
||||
uint8_t buffer[256];
|
||||
void* track_handle;
|
||||
void* last_track_handle;
|
||||
char exe_file[32] = "";
|
||||
unsigned size;
|
||||
size_t num_read = 0;
|
||||
uint32_t sector;
|
||||
uint32_t track_sector;
|
||||
int result = 0;
|
||||
md5_state_t md5;
|
||||
int i = 0;
|
||||
@ -940,6 +1015,7 @@ static int rc_hash_dreamcast(char hash[33], const char* path)
|
||||
return rc_hash_error("Not a Dreamcast CD");
|
||||
}
|
||||
|
||||
/* start the hash with the game meta information */
|
||||
md5_init(&md5);
|
||||
md5_append(&md5, (md5_byte_t*)buffer, 256);
|
||||
|
||||
@ -955,6 +1031,7 @@ static int rc_hash_dreamcast(char hash[33], const char* path)
|
||||
verbose_message_callback(message);
|
||||
}
|
||||
|
||||
/* the boot filename is 96 bytes into the meta information (https://mc.pp.se/dc/ip0000.bin.html) */
|
||||
/* remove whitespace from bootfile */
|
||||
i = 0;
|
||||
while (!isspace(buffer[96 + i]) && i < 16)
|
||||
@ -980,50 +1057,98 @@ static int rc_hash_dreamcast(char hash[33], const char* path)
|
||||
|
||||
/* last track contains the boot executable */
|
||||
last_track_handle = rc_cd_open_track(path, RC_HASH_CDTRACK_LAST);
|
||||
track_sector = rc_cd_absolute_sector_to_track_sector(last_track_handle, sector);
|
||||
|
||||
sector = rc_cd_absolute_sector_to_track_sector(last_track_handle, sector);
|
||||
|
||||
if ((num_read = rc_cd_read_sector(last_track_handle, sector, buffer, sizeof(buffer))) < sizeof(buffer))
|
||||
rc_hash_error("Could not read boot executable");
|
||||
|
||||
if (size > MAX_BUFFER_SIZE)
|
||||
size = MAX_BUFFER_SIZE;
|
||||
|
||||
if (verbose_message_callback)
|
||||
if ((int32_t)track_sector < 0)
|
||||
{
|
||||
char message[128];
|
||||
snprintf(message, sizeof(message), "Hashing %s contents (%u bytes)", exe_file, size);
|
||||
verbose_message_callback(message);
|
||||
/* boot executable is not in the last track; try the primary data track.
|
||||
* There's only a handful of games that do this: Q*bert was the first identified. */
|
||||
rc_cd_close_track(last_track_handle);
|
||||
|
||||
rc_hash_verbose("Boot executable not found in last track, trying primary track");
|
||||
last_track_handle = rc_cd_open_track(path, 3);
|
||||
track_sector = rc_cd_absolute_sector_to_track_sector(last_track_handle, sector);
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
md5_append(&md5, buffer, (int)num_read);
|
||||
|
||||
size -= (unsigned)num_read;
|
||||
if (size == 0)
|
||||
break;
|
||||
|
||||
++sector;
|
||||
if (size >= sizeof(buffer))
|
||||
num_read = rc_cd_read_sector(last_track_handle, sector, buffer, sizeof(buffer));
|
||||
else
|
||||
num_read = rc_cd_read_sector(last_track_handle, sector, buffer, size);
|
||||
} while (num_read > 0);
|
||||
result = rc_hash_cd_file(&md5, last_track_handle, track_sector, NULL, size, "boot executable");
|
||||
|
||||
rc_cd_close_track(last_track_handle);
|
||||
|
||||
result = rc_hash_finalize(&md5, hash);
|
||||
|
||||
rc_hash_finalize(&md5, hash);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int rc_hash_find_playstation_executable(void* track_handle, const char* boot_key, const char* cdrom_prefix,
|
||||
char exe_name[], unsigned exe_name_size, unsigned* exe_size)
|
||||
{
|
||||
uint8_t buffer[2048];
|
||||
unsigned size;
|
||||
char* ptr;
|
||||
char* start;
|
||||
const size_t boot_key_len = strlen(boot_key);
|
||||
const size_t cdrom_prefix_len = strlen(cdrom_prefix);
|
||||
int sector;
|
||||
|
||||
sector = rc_cd_find_file_sector(track_handle, "SYSTEM.CNF", NULL);
|
||||
if (!sector)
|
||||
return 0;
|
||||
|
||||
size = (unsigned)rc_cd_read_sector(track_handle, sector, buffer, sizeof(buffer) - 1);
|
||||
buffer[size] = '\0';
|
||||
|
||||
for (ptr = (char*)buffer; *ptr; ++ptr)
|
||||
{
|
||||
if (strncmp(ptr, boot_key, boot_key_len) == 0)
|
||||
{
|
||||
ptr += boot_key_len;
|
||||
while (isspace(*ptr))
|
||||
++ptr;
|
||||
|
||||
if (*ptr == '=')
|
||||
{
|
||||
++ptr;
|
||||
while (isspace(*ptr))
|
||||
++ptr;
|
||||
|
||||
if (strncmp(ptr, cdrom_prefix, cdrom_prefix_len) == 0)
|
||||
ptr += cdrom_prefix_len;
|
||||
if (*ptr == '\\')
|
||||
++ptr;
|
||||
|
||||
start = ptr;
|
||||
while (!isspace(*ptr) && *ptr != ';')
|
||||
++ptr;
|
||||
|
||||
size = (unsigned)(ptr - start);
|
||||
if (size >= exe_name_size)
|
||||
size = exe_name_size - 1;
|
||||
|
||||
memcpy(exe_name, start, size);
|
||||
exe_name[size] = '\0';
|
||||
|
||||
if (verbose_message_callback)
|
||||
{
|
||||
snprintf((char*)buffer, sizeof(buffer), "Looking for boot executable: %s", exe_name);
|
||||
verbose_message_callback((const char*)buffer);
|
||||
}
|
||||
|
||||
sector = rc_cd_find_file_sector(track_handle, exe_name, exe_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* advance to end of line */
|
||||
while (*ptr && *ptr != '\n')
|
||||
++ptr;
|
||||
}
|
||||
|
||||
return sector;
|
||||
}
|
||||
|
||||
static int rc_hash_psx(char hash[33], const char* path)
|
||||
{
|
||||
uint8_t buffer[2048];
|
||||
uint8_t buffer[32];
|
||||
char exe_name[64] = "";
|
||||
char* ptr;
|
||||
char* start;
|
||||
void* track_handle;
|
||||
uint32_t sector;
|
||||
unsigned size;
|
||||
@ -1035,63 +1160,12 @@ static int rc_hash_psx(char hash[33], const char* path)
|
||||
if (!track_handle)
|
||||
return rc_hash_error("Could not open track");
|
||||
|
||||
sector = rc_cd_find_file_sector(track_handle, "SYSTEM.CNF", NULL);
|
||||
sector = rc_hash_find_playstation_executable(track_handle, "BOOT", "cdrom:", exe_name, sizeof(exe_name), &size);
|
||||
if (!sector)
|
||||
{
|
||||
sector = rc_cd_find_file_sector(track_handle, "PSX.EXE", &size);
|
||||
if (sector)
|
||||
strcpy(exe_name, "PSX.EXE");
|
||||
}
|
||||
else
|
||||
{
|
||||
size = (unsigned)rc_cd_read_sector(track_handle, sector, buffer, sizeof(buffer) - 1);
|
||||
buffer[size] = '\0';
|
||||
|
||||
for (ptr = (char*)buffer; *ptr; ++ptr)
|
||||
{
|
||||
if (strncmp(ptr, "BOOT", 4) == 0)
|
||||
{
|
||||
ptr += 4;
|
||||
while (isspace(*ptr))
|
||||
++ptr;
|
||||
|
||||
if (*ptr == '=')
|
||||
{
|
||||
++ptr;
|
||||
while (isspace(*ptr))
|
||||
++ptr;
|
||||
|
||||
if (strncmp(ptr, "cdrom:", 6) == 0)
|
||||
ptr += 6;
|
||||
if (*ptr == '\\')
|
||||
++ptr;
|
||||
|
||||
start = ptr;
|
||||
while (!isspace(*ptr) && *ptr != ';')
|
||||
++ptr;
|
||||
|
||||
size = (unsigned)(ptr - start);
|
||||
if (size >= sizeof(exe_name))
|
||||
size = sizeof(exe_name) - 1;
|
||||
|
||||
memcpy(exe_name, start, size);
|
||||
exe_name[size] = '\0';
|
||||
|
||||
if (verbose_message_callback)
|
||||
{
|
||||
snprintf((char*)buffer, sizeof(buffer), "Looking for boot executable: %s", exe_name);
|
||||
verbose_message_callback((const char*)buffer);
|
||||
}
|
||||
|
||||
sector = rc_cd_find_file_sector(track_handle, exe_name, &size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* advance to end of line */
|
||||
while (*ptr && *ptr != '\n')
|
||||
++ptr;
|
||||
}
|
||||
memcpy(exe_name, "PSX.EXE", 8);
|
||||
}
|
||||
|
||||
if (!sector)
|
||||
@ -1121,38 +1195,65 @@ static int rc_hash_psx(char hash[33], const char* path)
|
||||
size = (((uint8_t)buffer[31] << 24) | ((uint8_t)buffer[30] << 16) | ((uint8_t)buffer[29] << 8) | (uint8_t)buffer[28]) + 2048;
|
||||
}
|
||||
|
||||
if (size > MAX_BUFFER_SIZE)
|
||||
size = MAX_BUFFER_SIZE;
|
||||
|
||||
if (verbose_message_callback)
|
||||
{
|
||||
char message[128];
|
||||
snprintf(message, sizeof(message), "Hashing %s title (%u bytes) and contents (%u bytes) ", exe_name, (unsigned)strlen(exe_name), size);
|
||||
verbose_message_callback(message);
|
||||
}
|
||||
|
||||
/* there's also a few games that are use a singular engine and only differ via their data files. luckily, they have
|
||||
* unique serial numbers, and use the serial number as the boot file in the standard way. include the boot file in the hash
|
||||
/* there's a few games that use a singular engine and only differ via their data files. luckily, they have unique
|
||||
* serial numbers, and use the serial number as the boot file in the standard way. include the boot file name in the hash.
|
||||
*/
|
||||
md5_init(&md5);
|
||||
md5_append(&md5, (md5_byte_t*)exe_name, (int)strlen(exe_name));
|
||||
|
||||
do
|
||||
result = rc_hash_cd_file(&md5, track_handle, sector, exe_name, size, "primary executable");
|
||||
rc_hash_finalize(&md5, hash);
|
||||
}
|
||||
|
||||
rc_cd_close_track(track_handle);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int rc_hash_ps2(char hash[33], const char* path)
|
||||
{
|
||||
uint8_t buffer[4];
|
||||
char exe_name[64] = "";
|
||||
void* track_handle;
|
||||
uint32_t sector;
|
||||
unsigned size;
|
||||
size_t num_read;
|
||||
int result = 0;
|
||||
md5_state_t md5;
|
||||
|
||||
track_handle = rc_cd_open_track(path, 1);
|
||||
if (!track_handle)
|
||||
return rc_hash_error("Could not open track");
|
||||
|
||||
sector = rc_hash_find_playstation_executable(track_handle, "BOOT2", "cdrom0:", exe_name, sizeof(exe_name), &size);
|
||||
if (!sector)
|
||||
{
|
||||
rc_hash_error("Could not locate primary executable");
|
||||
}
|
||||
else if ((num_read = rc_cd_read_sector(track_handle, sector, buffer, sizeof(buffer))) < sizeof(buffer))
|
||||
{
|
||||
rc_hash_error("Could not read primary executable");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (memcmp(buffer, "\x7f\x45\x4c\x46", 4) != 0)
|
||||
{
|
||||
md5_append(&md5, buffer, (int)num_read);
|
||||
if (verbose_message_callback)
|
||||
{
|
||||
char message[128];
|
||||
snprintf(message, sizeof(message), "%s did not contain ELF marker", exe_name);
|
||||
verbose_message_callback(message);
|
||||
}
|
||||
}
|
||||
|
||||
size -= (unsigned)num_read;
|
||||
if (size == 0)
|
||||
break;
|
||||
/* there's a few games that use a singular engine and only differ via their data files. luckily, they have unique
|
||||
* serial numbers, and use the serial number as the boot file in the standard way. include the boot file name in the hash.
|
||||
*/
|
||||
md5_init(&md5);
|
||||
md5_append(&md5, (md5_byte_t*)exe_name, (int)strlen(exe_name));
|
||||
|
||||
++sector;
|
||||
if (size >= sizeof(buffer))
|
||||
num_read = rc_cd_read_sector(track_handle, sector, buffer, sizeof(buffer));
|
||||
else
|
||||
num_read = rc_cd_read_sector(track_handle, sector, buffer, size);
|
||||
} while (num_read > 0);
|
||||
|
||||
result = rc_hash_finalize(&md5, hash);
|
||||
result = rc_hash_cd_file(&md5, track_handle, sector, exe_name, size, "primary executable");
|
||||
rc_hash_finalize(&md5, hash);
|
||||
}
|
||||
|
||||
rc_cd_close_track(track_handle);
|
||||
@ -1217,7 +1318,6 @@ int rc_hash_generate_from_buffer(char hash[33], int console_id, uint8_t* buffer,
|
||||
|
||||
case RC_CONSOLE_APPLE_II:
|
||||
case RC_CONSOLE_ATARI_2600:
|
||||
case RC_CONSOLE_ATARI_7800:
|
||||
case RC_CONSOLE_ATARI_JAGUAR:
|
||||
case RC_CONSOLE_COLECOVISION:
|
||||
case RC_CONSOLE_GAMEBOY:
|
||||
@ -1236,11 +1336,16 @@ int rc_hash_generate_from_buffer(char hash[33], int console_id, uint8_t* buffer,
|
||||
case RC_CONSOLE_POKEMON_MINI:
|
||||
case RC_CONSOLE_SEGA_32X:
|
||||
case RC_CONSOLE_SG1000:
|
||||
case RC_CONSOLE_SUPERVISION:
|
||||
case RC_CONSOLE_TIC80:
|
||||
case RC_CONSOLE_VECTREX:
|
||||
case RC_CONSOLE_VIRTUAL_BOY:
|
||||
case RC_CONSOLE_WONDERSWAN:
|
||||
return rc_hash_buffer(hash, buffer, buffer_size);
|
||||
|
||||
case RC_CONSOLE_ATARI_7800:
|
||||
return rc_hash_7800(hash, buffer, buffer_size);
|
||||
|
||||
case RC_CONSOLE_ATARI_LYNX:
|
||||
return rc_hash_lynx(hash, buffer, buffer_size);
|
||||
|
||||
@ -1259,9 +1364,10 @@ static int rc_hash_whole_file(char hash[33], int console_id, const char* path)
|
||||
{
|
||||
md5_state_t md5;
|
||||
uint8_t* buffer;
|
||||
size_t size;
|
||||
int64_t size;
|
||||
const size_t buffer_size = 65536;
|
||||
void* file_handle;
|
||||
size_t remaining;
|
||||
int result = 0;
|
||||
|
||||
file_handle = rc_file_open(path);
|
||||
@ -1282,7 +1388,9 @@ static int rc_hash_whole_file(char hash[33], int console_id, const char* path)
|
||||
}
|
||||
|
||||
if (size > MAX_BUFFER_SIZE)
|
||||
size = MAX_BUFFER_SIZE;
|
||||
remaining = MAX_BUFFER_SIZE;
|
||||
else
|
||||
remaining = (size_t)size;
|
||||
|
||||
md5_init(&md5);
|
||||
|
||||
@ -1290,17 +1398,17 @@ static int rc_hash_whole_file(char hash[33], int console_id, const char* path)
|
||||
if (buffer)
|
||||
{
|
||||
rc_file_seek(file_handle, 0, SEEK_SET);
|
||||
while (size >= buffer_size)
|
||||
while (remaining >= buffer_size)
|
||||
{
|
||||
rc_file_read(file_handle, buffer, (int)buffer_size);
|
||||
md5_append(&md5, buffer, (int)buffer_size);
|
||||
size -= buffer_size;
|
||||
remaining -= buffer_size;
|
||||
}
|
||||
|
||||
if (size > 0)
|
||||
if (remaining > 0)
|
||||
{
|
||||
rc_file_read(file_handle, buffer, (int)size);
|
||||
md5_append(&md5, buffer, (int)size);
|
||||
rc_file_read(file_handle, buffer, (int)remaining);
|
||||
md5_append(&md5, buffer, (int)remaining);
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
@ -1314,7 +1422,7 @@ static int rc_hash_whole_file(char hash[33], int console_id, const char* path)
|
||||
static int rc_hash_buffered_file(char hash[33], int console_id, const char* path)
|
||||
{
|
||||
uint8_t* buffer;
|
||||
size_t size;
|
||||
int64_t size;
|
||||
int result = 0;
|
||||
void* file_handle;
|
||||
|
||||
@ -1338,13 +1446,13 @@ static int rc_hash_buffered_file(char hash[33], int console_id, const char* path
|
||||
if (size > MAX_BUFFER_SIZE)
|
||||
size = MAX_BUFFER_SIZE;
|
||||
|
||||
buffer = (uint8_t*)malloc(size);
|
||||
buffer = (uint8_t*)malloc((size_t)size);
|
||||
if (buffer)
|
||||
{
|
||||
rc_file_seek(file_handle, 0, SEEK_SET);
|
||||
rc_file_read(file_handle, buffer, (int)size);
|
||||
|
||||
result = rc_hash_generate_from_buffer(hash, console_id, buffer, size);
|
||||
result = rc_hash_generate_from_buffer(hash, console_id, buffer, (size_t)size);
|
||||
|
||||
free(buffer);
|
||||
}
|
||||
@ -1492,7 +1600,6 @@ int rc_hash_generate_from_file(char hash[33], int console_id, const char* path)
|
||||
|
||||
case RC_CONSOLE_APPLE_II:
|
||||
case RC_CONSOLE_ATARI_2600:
|
||||
case RC_CONSOLE_ATARI_7800:
|
||||
case RC_CONSOLE_ATARI_JAGUAR:
|
||||
case RC_CONSOLE_COLECOVISION:
|
||||
case RC_CONSOLE_GAMEBOY:
|
||||
@ -1509,6 +1616,8 @@ int rc_hash_generate_from_file(char hash[33], int console_id, const char* path)
|
||||
case RC_CONSOLE_POKEMON_MINI:
|
||||
case RC_CONSOLE_SEGA_32X:
|
||||
case RC_CONSOLE_SG1000:
|
||||
case RC_CONSOLE_SUPERVISION:
|
||||
case RC_CONSOLE_TIC80:
|
||||
case RC_CONSOLE_VECTREX:
|
||||
case RC_CONSOLE_VIRTUAL_BOY:
|
||||
case RC_CONSOLE_WONDERSWAN:
|
||||
@ -1523,6 +1632,7 @@ 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_ATARI_7800:
|
||||
case RC_CONSOLE_ATARI_LYNX:
|
||||
case RC_CONSOLE_NINTENDO:
|
||||
case RC_CONSOLE_SUPER_NINTENDO:
|
||||
@ -1562,6 +1672,12 @@ int rc_hash_generate_from_file(char hash[33], int console_id, const char* path)
|
||||
|
||||
return rc_hash_psx(hash, path);
|
||||
|
||||
case RC_CONSOLE_PLAYSTATION_2:
|
||||
if (rc_path_compare_extension(path, "m3u"))
|
||||
return rc_hash_generate_from_playlist(hash, console_id, path);
|
||||
|
||||
return rc_hash_ps2(hash, path);
|
||||
|
||||
case RC_CONSOLE_DREAMCAST:
|
||||
if (rc_path_compare_extension(path, "m3u"))
|
||||
return rc_hash_generate_from_playlist(hash, console_id, path);
|
||||
@ -1601,7 +1717,7 @@ static void rc_hash_initialize_dsk_iterator(struct rc_hash_iterator* iterator, c
|
||||
if (file)
|
||||
{
|
||||
rc_file_seek(file, 0, SEEK_END);
|
||||
size = rc_file_tell(file);
|
||||
size = (size_t)rc_file_tell(file);
|
||||
rc_file_close(file);
|
||||
}
|
||||
}
|
||||
@ -1655,6 +1771,13 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
|
||||
const char* ext = rc_path_get_extension(path);
|
||||
switch (tolower(*ext))
|
||||
{
|
||||
case '2':
|
||||
if (rc_path_compare_extension(ext, "2d"))
|
||||
{
|
||||
iterator->consoles[0] = RC_CONSOLE_SHARPX1;
|
||||
}
|
||||
break;
|
||||
|
||||
case '7':
|
||||
if (rc_path_compare_extension(ext, "7z"))
|
||||
{
|
||||
@ -1680,7 +1803,7 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
|
||||
void* file = rc_file_open(path);
|
||||
if (file)
|
||||
{
|
||||
size_t size;
|
||||
int64_t size;
|
||||
|
||||
rc_file_seek(file, 0, SEEK_END);
|
||||
size = rc_file_tell(file);
|
||||
@ -1690,17 +1813,18 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
|
||||
{
|
||||
iterator->consoles[0] = RC_CONSOLE_3DO; /* 4DO supports directly opening the bin file */
|
||||
iterator->consoles[1] = RC_CONSOLE_PLAYSTATION; /* PCSX ReARMed supports directly opening the bin file*/
|
||||
iterator->consoles[2] = RC_CONSOLE_SEGA_CD; /* Genesis Plus GX supports directly opening the bin file*/
|
||||
iterator->consoles[2] = RC_CONSOLE_PLAYSTATION_2; /* PCSX2 supports directly opening the bin file*/
|
||||
iterator->consoles[3] = RC_CONSOLE_SEGA_CD; /* Genesis Plus GX supports directly opening the bin file*/
|
||||
|
||||
/* fallback to megadrive which just does a full hash */
|
||||
iterator->consoles[3] = RC_CONSOLE_MEGA_DRIVE;
|
||||
iterator->consoles[4] = RC_CONSOLE_MEGA_DRIVE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* bin is associated with MegaDrive, Sega32X and Atari 2600. Since they all use the same
|
||||
* hashing algorithm, only specify one of them */
|
||||
/* bin is associated with MegaDrive, Sega32X, Atari 2600, and Watara Supervision.
|
||||
* Since they all use the same hashing algorithm, only specify one of them */
|
||||
iterator->consoles[0] = RC_CONSOLE_MEGA_DRIVE;
|
||||
}
|
||||
else if (rc_path_compare_extension(ext, "bs"))
|
||||
@ -1713,20 +1837,22 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
|
||||
if (rc_path_compare_extension(ext, "cue"))
|
||||
{
|
||||
iterator->consoles[0] = RC_CONSOLE_PLAYSTATION;
|
||||
iterator->consoles[1] = RC_CONSOLE_PC_ENGINE;
|
||||
iterator->consoles[2] = RC_CONSOLE_3DO;
|
||||
iterator->consoles[3] = RC_CONSOLE_PCFX;
|
||||
iterator->consoles[4] = RC_CONSOLE_SEGA_CD; /* ASSERT: handles both Sega CD and Saturn */
|
||||
iterator->consoles[1] = RC_CONSOLE_PLAYSTATION_2;
|
||||
iterator->consoles[2] = RC_CONSOLE_PC_ENGINE;
|
||||
iterator->consoles[3] = RC_CONSOLE_3DO;
|
||||
iterator->consoles[4] = RC_CONSOLE_PCFX;
|
||||
iterator->consoles[5] = RC_CONSOLE_SEGA_CD; /* ASSERT: handles both Sega CD and Saturn */
|
||||
need_path = 1;
|
||||
}
|
||||
else if (rc_path_compare_extension(ext, "chd"))
|
||||
{
|
||||
iterator->consoles[0] = RC_CONSOLE_PLAYSTATION;
|
||||
iterator->consoles[1] = RC_CONSOLE_DREAMCAST;
|
||||
iterator->consoles[2] = RC_CONSOLE_PC_ENGINE;
|
||||
iterator->consoles[3] = RC_CONSOLE_3DO;
|
||||
iterator->consoles[4] = RC_CONSOLE_PCFX;
|
||||
iterator->consoles[5] = RC_CONSOLE_SEGA_CD; /* ASSERT: handles both Sega CD and Saturn */
|
||||
iterator->consoles[1] = RC_CONSOLE_PLAYSTATION_2;
|
||||
iterator->consoles[2] = RC_CONSOLE_DREAMCAST;
|
||||
iterator->consoles[3] = RC_CONSOLE_PC_ENGINE;
|
||||
iterator->consoles[4] = RC_CONSOLE_3DO;
|
||||
iterator->consoles[5] = RC_CONSOLE_PCFX;
|
||||
iterator->consoles[6] = RC_CONSOLE_SEGA_CD; /* ASSERT: handles both Sega CD and Saturn */
|
||||
need_path = 1;
|
||||
}
|
||||
else if (rc_path_compare_extension(ext, "col"))
|
||||
@ -1747,6 +1873,7 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
|
||||
else if (rc_path_compare_extension(ext, "d88"))
|
||||
{
|
||||
iterator->consoles[0] = RC_CONSOLE_PC8800;
|
||||
iterator->consoles[1] = RC_CONSOLE_SHARPX1;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1759,6 +1886,10 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
|
||||
{
|
||||
iterator->consoles[0] = RC_CONSOLE_NINTENDO;
|
||||
}
|
||||
else if (rc_path_compare_extension(ext, "fd"))
|
||||
{
|
||||
iterator->consoles[0] = RC_CONSOLE_THOMSONTO8; /* disk */
|
||||
}
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
@ -1787,8 +1918,9 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
|
||||
case 'i':
|
||||
if (rc_path_compare_extension(ext, "iso"))
|
||||
{
|
||||
iterator->consoles[0] = RC_CONSOLE_3DO;
|
||||
iterator->consoles[1] = RC_CONSOLE_SEGA_CD; /* ASSERT: handles both Sega CD and Saturn */
|
||||
iterator->consoles[0] = RC_CONSOLE_PLAYSTATION_2;
|
||||
iterator->consoles[1] = RC_CONSOLE_3DO;
|
||||
iterator->consoles[2] = RC_CONSOLE_SEGA_CD; /* ASSERT: handles both Sega CD and Saturn */
|
||||
need_path = 1;
|
||||
}
|
||||
break;
|
||||
@ -1800,6 +1932,13 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
|
||||
}
|
||||
break;
|
||||
|
||||
case 'k':
|
||||
if (rc_path_compare_extension(ext, "k7"))
|
||||
{
|
||||
iterator->consoles[0] = RC_CONSOLE_THOMSONTO8; /* tape */
|
||||
}
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
if (rc_path_compare_extension(ext, "lnx"))
|
||||
{
|
||||
@ -1835,6 +1974,14 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
|
||||
{
|
||||
iterator->consoles[0] = RC_CONSOLE_MSX;
|
||||
}
|
||||
else if (rc_path_compare_extension(ext, "m5"))
|
||||
{
|
||||
iterator->consoles[0] = RC_CONSOLE_THOMSONTO8; /* cartridge */
|
||||
}
|
||||
else if (rc_path_compare_extension(ext, "m7"))
|
||||
{
|
||||
iterator->consoles[0] = RC_CONSOLE_THOMSONTO8; /* cartridge */
|
||||
}
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
@ -1868,6 +2015,7 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
|
||||
if (rc_path_compare_extension(ext, "rom"))
|
||||
{
|
||||
iterator->consoles[0] = RC_CONSOLE_MSX;
|
||||
iterator->consoles[1] = RC_CONSOLE_THOMSONTO8; /* cartridge */
|
||||
}
|
||||
if (rc_path_compare_extension(ext, "ri"))
|
||||
{
|
||||
@ -1890,6 +2038,14 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
|
||||
{
|
||||
iterator->consoles[0] = RC_CONSOLE_PC_ENGINE;
|
||||
}
|
||||
else if (rc_path_compare_extension(ext, "sv"))
|
||||
{
|
||||
iterator->consoles[0] = RC_CONSOLE_SUPERVISION;
|
||||
}
|
||||
else if (rc_path_compare_extension(ext, "sap"))
|
||||
{
|
||||
iterator->consoles[0] = RC_CONSOLE_THOMSONTO8; /* disk */
|
||||
}
|
||||
break;
|
||||
|
||||
case 't':
|
||||
@ -1897,6 +2053,10 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
|
||||
{
|
||||
iterator->consoles[0] = RC_CONSOLE_ORIC;
|
||||
}
|
||||
else if (rc_path_compare_extension(ext, "tic"))
|
||||
{
|
||||
iterator->consoles[0] = RC_CONSOLE_TIC80;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
|
Reference in New Issue
Block a user