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

@@ -22,6 +22,7 @@ struct cdrom_t
void* file_handle; /* the file handle for reading the track data */
int sector_size; /* the size of each sector in the track data */
int sector_header_size; /* the offset to the raw data within a sector block */
int raw_data_size; /* the amount of raw data within a sector block */
int64_t file_track_offset;/* the offset of the track data within the file */
int track_first_sector; /* the first absolute sector associated to the track (includes pregap) */
int track_pregap_sectors; /* the number of pregap sectors */
@@ -58,6 +59,7 @@ static void cdreader_determine_sector_size(struct cdrom_t* cdrom)
cdrom->sector_size = 0;
cdrom->sector_header_size = 0;
cdrom->raw_data_size = 2048;
rc_file_seek(cdrom->file_handle, toc_sector * 2352 + cdrom->file_track_offset, SEEK_SET);
if (rc_file_read(cdrom->file_handle, header, sizeof(header)) < sizeof(header))
@@ -122,6 +124,8 @@ static void* cdreader_open_bin_track(const char* path, uint32_t track)
return NULL;
cdrom = (struct cdrom_t*)calloc(1, sizeof(*cdrom));
if (!cdrom)
return NULL;
cdrom->file_handle = file_handle;
#ifndef NDEBUG
cdrom->track_id = track;
@@ -219,6 +223,7 @@ static int cdreader_open_bin(struct cdrom_t* cdrom, const char* path, const char
{
cdrom->sector_size = 2352;
cdrom->sector_header_size = 0;
cdrom->raw_data_size = 2352; /* no header or footer data on audio tracks */
}
}
@@ -282,6 +287,7 @@ static void* cdreader_open_cue_track(const char* path, uint32_t track)
char* bin_filename = NULL;
char *ptr, *ptr2, *end;
int done = 0;
int session = 1;
size_t num_read = 0;
struct cdrom_t* cdrom = NULL;
@@ -339,7 +345,7 @@ static void* cdreader_open_cue_track(const char* path, uint32_t track)
++ptr;
/* convert mm:ss:ff to sector count */
sscanf(ptr, "%d:%d:%d", &m, &s, &f);
sscanf_s(ptr, "%d:%d:%d", &m, &s, &f);
sector_offset = ((m * 60) + s) * 75 + f;
if (current_track.first_sector == -1)
@@ -389,6 +395,13 @@ static void* cdreader_open_cue_track(const char* path, uint32_t track)
done = 1;
break;
}
if (track == RC_HASH_CDTRACK_FIRST_OF_SECOND_SESSION && session == 2)
{
track = current_track.id;
done = 1;
break;
}
}
}
else if (strncasecmp(ptr, "TRACK ", 6) == 0)
@@ -465,6 +478,20 @@ static void* cdreader_open_cue_track(const char* path, uint32_t track)
if (ptr2 - ptr < (int)sizeof(current_track.filename))
memcpy(current_track.filename, ptr, ptr2 - ptr);
}
else if (strncasecmp(ptr, "REM ", 4) == 0)
{
ptr += 4;
while (*ptr == ' ')
++ptr;
if (strncasecmp(ptr, "SESSION ", 8) == 0)
{
ptr += 8;
while (*ptr == ' ')
++ptr;
session = atoi(ptr);
}
}
while (*ptr && *ptr != '\n')
++ptr;
@@ -694,8 +721,8 @@ static void* cdreader_open_gdi_track(const char* path, uint32_t track)
largest_track_size = track_size;
largest_track = current_track;
largest_track_lba = lba;
strcpy(largest_track_file, file);
strcpy(largest_track_sector_size, sector_size);
strcpy_s(largest_track_file, sizeof(largest_track_file), file);
strcpy_s(largest_track_sector_size, sizeof(largest_track_sector_size), sector_size);
}
}
}
@@ -723,8 +750,8 @@ static void* cdreader_open_gdi_track(const char* path, uint32_t track)
if (largest_track != 0 && largest_track != current_track)
{
current_track = largest_track;
strcpy(file, largest_track_file);
strcpy(sector_size, largest_track_sector_size);
strcpy_s(file, sizeof(file), largest_track_file);
strcpy_s(sector_size, sizeof(sector_size), largest_track_sector_size);
lba = largest_track_lba;
}
@@ -794,18 +821,18 @@ static size_t cdreader_read_sector(void* track_handle, uint32_t sector, void* bu
sector_start = (int64_t)(sector - cdrom->track_first_sector) * cdrom->sector_size +
cdrom->sector_header_size + cdrom->file_track_offset;
while (requested_bytes > 2048)
while (requested_bytes > (size_t)cdrom->raw_data_size)
{
rc_file_seek(cdrom->file_handle, sector_start, SEEK_SET);
num_read = rc_file_read(cdrom->file_handle, buffer_ptr, 2048);
num_read = rc_file_read(cdrom->file_handle, buffer_ptr, cdrom->raw_data_size);
total_read += num_read;
if (num_read < 2048)
if (num_read < (size_t)cdrom->raw_data_size)
return total_read;
buffer_ptr += 2048;
buffer_ptr += cdrom->raw_data_size;
sector_start += cdrom->sector_size;
requested_bytes -= 2048;
requested_bytes -= cdrom->raw_data_size;
}
rc_file_seek(cdrom->file_handle, sector_start, SEEK_SET);
@@ -844,7 +871,7 @@ void rc_hash_get_default_cdreader(struct rc_hash_cdreader* cdreader)
cdreader->first_track_sector = cdreader_first_track_sector;
}
void rc_hash_init_default_cdreader()
void rc_hash_init_default_cdreader(void)
{
struct rc_hash_cdreader cdreader;
rc_hash_get_default_cdreader(&cdreader);

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"))
{

View File

@@ -52,6 +52,7 @@
*/
#include "md5.h"
#include <stddef.h>
#include <string.h>
#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
@@ -161,7 +162,7 @@ md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
* On little-endian machines, we can process properly aligned
* data without copying it.
*/
if (!((data - (const md5_byte_t *)0) & 3)) {
if (!((ptrdiff_t)data & 3)) {
/* data are properly aligned */
X = (const md5_word_t *)data;
} else {