mirror of
https://github.com/holub/mame
synced 2025-05-31 01:51:46 +03:00
Hash generation and general cleanup. New class hash_collection holds
and manages a collection of hashes, and can be built from an internal format string which is stored with each ROM. All core instances are cleaned up to use the new interfaces, but it's likely that hashfile code in MESS will need an update. Also compacted the form of the hash strings used for ROMs, and fixed verification/hashing of non-ZIPped files.
This commit is contained in:
parent
06d479c54f
commit
5e4df8c772
@ -22,9 +22,9 @@
|
||||
FUNCTION PROTOTYPES
|
||||
***************************************************************************/
|
||||
|
||||
static void audit_one_rom(core_options *options, const rom_entry *rom, const char *regiontag, const game_driver *gamedrv, UINT32 validation, audit_record *record);
|
||||
static void audit_one_disk(core_options *options, const rom_entry *rom, const game_driver *gamedrv, UINT32 validation, audit_record *record);
|
||||
static int rom_used_by_parent(const game_driver *gamedrv, const rom_entry *romentry, const game_driver **parent);
|
||||
static void audit_one_rom(core_options *options, const rom_entry *rom, const char *regiontag, const game_driver *gamedrv, const char *validation, audit_record *record);
|
||||
static void audit_one_disk(core_options *options, const rom_entry *rom, const game_driver *gamedrv, const char *validation, audit_record *record);
|
||||
static int rom_used_by_parent(const game_driver *gamedrv, const hash_collection &romhashes, const game_driver **parent);
|
||||
|
||||
|
||||
|
||||
@ -54,7 +54,7 @@ INLINE void set_status(audit_record *record, UINT8 status, UINT8 substatus)
|
||||
images for a game
|
||||
-------------------------------------------------*/
|
||||
|
||||
int audit_images(core_options *options, const game_driver *gamedrv, UINT32 validation, audit_record **audit)
|
||||
int audit_images(core_options *options, const game_driver *gamedrv, const char *validation, audit_record **audit)
|
||||
{
|
||||
machine_config config(*gamedrv);
|
||||
const rom_entry *region, *rom;
|
||||
@ -74,12 +74,16 @@ int audit_images(core_options *options, const game_driver *gamedrv, UINT32 valid
|
||||
for (rom = rom_first_file(region); rom != NULL; rom = rom_next_file(rom))
|
||||
if (ROMREGION_ISROMDATA(region) || ROMREGION_ISDISKDATA(region))
|
||||
{
|
||||
if (source_is_gamedrv && !ROM_ISOPTIONAL(rom) && !ROM_NOGOODDUMP(rom))
|
||||
if (source_is_gamedrv && !ROM_ISOPTIONAL(rom))
|
||||
{
|
||||
anyrequired = TRUE;
|
||||
hash_collection hashes(ROM_GETHASHDATA(rom));
|
||||
if (!hashes.flag(hash_collection::FLAG_NO_DUMP))
|
||||
{
|
||||
anyrequired = TRUE;
|
||||
|
||||
if (allshared && !rom_used_by_parent(gamedrv, rom, NULL))
|
||||
allshared = FALSE;
|
||||
if (allshared && !rom_used_by_parent(gamedrv, hashes, NULL))
|
||||
allshared = FALSE;
|
||||
}
|
||||
}
|
||||
records++;
|
||||
}
|
||||
@ -119,7 +123,7 @@ int audit_images(core_options *options, const game_driver *gamedrv, UINT32 valid
|
||||
continue;
|
||||
}
|
||||
|
||||
if (source_is_gamedrv && record->status != AUDIT_STATUS_NOT_FOUND && (allshared || !rom_used_by_parent(gamedrv, rom, NULL)))
|
||||
if (source_is_gamedrv && record->status != AUDIT_STATUS_NOT_FOUND && (allshared || !rom_used_by_parent(gamedrv, record->exphashes, NULL)))
|
||||
anyfound = TRUE;
|
||||
|
||||
record++;
|
||||
@ -265,13 +269,10 @@ int audit_summary(const game_driver *gamedrv, int count, const audit_record *rec
|
||||
case SUBSTATUS_FOUND_BAD_CHECKSUM:
|
||||
if (output)
|
||||
{
|
||||
char hashbuf[512];
|
||||
|
||||
astring tempstr;
|
||||
mame_printf_info("INCORRECT CHECKSUM:\n");
|
||||
hash_data_print(record->exphash, 0, hashbuf);
|
||||
mame_printf_info("EXPECTED: %s\n", hashbuf);
|
||||
hash_data_print(record->hash, 0, hashbuf);
|
||||
mame_printf_info(" FOUND: %s\n", hashbuf);
|
||||
mame_printf_info("EXPECTED: %s\n", record->exphashes.macro_string(tempstr));
|
||||
mame_printf_info(" FOUND: %s\n", record->hashes.macro_string(tempstr));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -319,24 +320,20 @@ int audit_summary(const game_driver *gamedrv, int count, const audit_record *rec
|
||||
audit_one_rom - validate a single ROM entry
|
||||
-------------------------------------------------*/
|
||||
|
||||
static void audit_one_rom(core_options *options, const rom_entry *rom, const char *regiontag, const game_driver *gamedrv, UINT32 validation, audit_record *record)
|
||||
static void audit_one_rom(core_options *options, const rom_entry *rom, const char *regiontag, const game_driver *gamedrv, const char *validation, audit_record *record)
|
||||
{
|
||||
const game_driver *drv;
|
||||
UINT32 crc = 0;
|
||||
UINT8 crcs[4];
|
||||
int has_crc;
|
||||
|
||||
/* fill in the record basics */
|
||||
record->type = AUDIT_FILE_ROM;
|
||||
record->name = ROM_GETNAME(rom);
|
||||
record->exphash = ROM_GETHASHDATA(rom);
|
||||
record->exphashes.from_internal_string(ROM_GETHASHDATA(rom));
|
||||
record->length = 0;
|
||||
record->explength = rom_file_size(rom);
|
||||
|
||||
/* see if we have a CRC and extract it if so */
|
||||
has_crc = hash_data_extract_binary_checksum(record->exphash, HASH_CRC, crcs);
|
||||
if (has_crc)
|
||||
crc = (crcs[0] << 24) | (crcs[1] << 16) | (crcs[2] << 8) | crcs[3];
|
||||
bool has_crc = record->exphashes.crc(crc);
|
||||
|
||||
/* find the file and checksum it, getting the file length along the way */
|
||||
for (drv = gamedrv; drv != NULL; drv = driver_get_clone(drv))
|
||||
@ -351,7 +348,7 @@ static void audit_one_rom(core_options *options, const rom_entry *rom, const cha
|
||||
filerr = file.open(drv->name, PATH_SEPARATOR, ROM_GETNAME(rom));
|
||||
if (filerr == FILERR_NONE)
|
||||
{
|
||||
hash_data_copy(record->hash, file.hash_string(validation));
|
||||
record->hashes = file.hashes(validation);
|
||||
record->length = (UINT32)file.size();
|
||||
break;
|
||||
}
|
||||
@ -370,7 +367,7 @@ static void audit_one_rom(core_options *options, const rom_entry *rom, const cha
|
||||
filerr = file.open(regiontag, PATH_SEPARATOR, ROM_GETNAME(rom));
|
||||
if (filerr == FILERR_NONE)
|
||||
{
|
||||
hash_data_copy(record->hash, file.hash_string(validation));
|
||||
record->hashes = file.hashes(validation);
|
||||
record->length = (UINT32)file.size();
|
||||
}
|
||||
}
|
||||
@ -381,7 +378,7 @@ static void audit_one_rom(core_options *options, const rom_entry *rom, const cha
|
||||
const game_driver *parent;
|
||||
|
||||
/* no good dump */
|
||||
if (hash_data_has_info(record->exphash, HASH_INFO_NO_DUMP))
|
||||
if (record->exphashes.flag(hash_collection::FLAG_NO_DUMP))
|
||||
set_status(record, AUDIT_STATUS_NOT_FOUND, SUBSTATUS_NOT_FOUND_NODUMP);
|
||||
|
||||
/* optional ROM */
|
||||
@ -389,7 +386,7 @@ static void audit_one_rom(core_options *options, const rom_entry *rom, const cha
|
||||
set_status(record, AUDIT_STATUS_NOT_FOUND, SUBSTATUS_NOT_FOUND_OPTIONAL);
|
||||
|
||||
/* not found and used by parent */
|
||||
else if (rom_used_by_parent(gamedrv, rom, &parent))
|
||||
else if (rom_used_by_parent(gamedrv, record->exphashes, &parent))
|
||||
set_status(record, AUDIT_STATUS_NOT_FOUND, (parent->flags & GAME_IS_BIOS_ROOT) ? SUBSTATUS_NOT_FOUND_BIOS : SUBSTATUS_NOT_FOUND_PARENT);
|
||||
|
||||
/* just plain old not found */
|
||||
@ -405,15 +402,15 @@ static void audit_one_rom(core_options *options, const rom_entry *rom, const cha
|
||||
set_status(record, AUDIT_STATUS_FOUND_INVALID, SUBSTATUS_FOUND_WRONG_LENGTH);
|
||||
|
||||
/* found but needs a dump */
|
||||
else if (hash_data_has_info(record->exphash, HASH_INFO_NO_DUMP))
|
||||
else if (record->exphashes.flag(hash_collection::FLAG_NO_DUMP))
|
||||
set_status(record, AUDIT_STATUS_GOOD, SUBSTATUS_FOUND_NODUMP);
|
||||
|
||||
/* incorrect hash */
|
||||
else if (!hash_data_is_equal(record->exphash, record->hash, 0))
|
||||
else if (record->exphashes != record->hashes)
|
||||
set_status(record, AUDIT_STATUS_FOUND_INVALID, SUBSTATUS_FOUND_BAD_CHECKSUM);
|
||||
|
||||
/* correct hash but needs a redump */
|
||||
else if (hash_data_has_info(record->exphash, HASH_INFO_BAD_DUMP))
|
||||
else if (record->exphashes.flag(hash_collection::FLAG_BAD_DUMP))
|
||||
set_status(record, AUDIT_STATUS_GOOD, SUBSTATUS_GOOD_NEEDS_REDUMP);
|
||||
|
||||
/* just plain old good */
|
||||
@ -427,7 +424,7 @@ static void audit_one_rom(core_options *options, const rom_entry *rom, const cha
|
||||
audit_one_disk - validate a single disk entry
|
||||
-------------------------------------------------*/
|
||||
|
||||
static void audit_one_disk(core_options *options, const rom_entry *rom, const game_driver *gamedrv, UINT32 validation, audit_record *record)
|
||||
static void audit_one_disk(core_options *options, const rom_entry *rom, const game_driver *gamedrv, const char *validation, audit_record *record)
|
||||
{
|
||||
emu_file *source_file;
|
||||
chd_file *source;
|
||||
@ -436,7 +433,7 @@ static void audit_one_disk(core_options *options, const rom_entry *rom, const ga
|
||||
/* fill in the record basics */
|
||||
record->type = AUDIT_FILE_DISK;
|
||||
record->name = ROM_GETNAME(rom);
|
||||
record->exphash = ROM_GETHASHDATA(rom);
|
||||
record->exphashes.from_internal_string(ROM_GETHASHDATA(rom));
|
||||
|
||||
/* open the disk */
|
||||
err = open_disk_image(*options, gamedrv, rom, &source_file, &source, NULL);
|
||||
@ -449,7 +446,7 @@ static void audit_one_disk(core_options *options, const rom_entry *rom, const ga
|
||||
set_status(record, AUDIT_STATUS_ERROR, SUBSTATUS_ERROR);
|
||||
|
||||
/* not found but it's not good anyway */
|
||||
else if (hash_data_has_info(record->exphash, HASH_INFO_NO_DUMP))
|
||||
else if (record->exphashes.flag(hash_collection::FLAG_NO_DUMP))
|
||||
set_status(record, AUDIT_STATUS_NOT_FOUND, SUBSTATUS_NOT_FOUND_NODUMP);
|
||||
|
||||
/* not found but optional */
|
||||
@ -464,25 +461,25 @@ static void audit_one_disk(core_options *options, const rom_entry *rom, const ga
|
||||
/* if we succeeded, validate it */
|
||||
else
|
||||
{
|
||||
static const UINT8 nullhash[HASH_BUF_SIZE] = { 0 };
|
||||
static const UINT8 nullhash[20] = { 0 };
|
||||
chd_header header = *chd_get_header(source);
|
||||
|
||||
/* if there's an MD5 or SHA1 hash, add them to the output hash */
|
||||
if (memcmp(nullhash, header.md5, sizeof(header.md5)) != 0)
|
||||
hash_data_insert_binary_checksum(record->hash, HASH_MD5, header.md5);
|
||||
record->hashes.add_from_buffer(hash_collection::HASH_MD5, header.md5, sizeof(header.md5));
|
||||
if (memcmp(nullhash, header.sha1, sizeof(header.sha1)) != 0)
|
||||
hash_data_insert_binary_checksum(record->hash, HASH_SHA1, header.sha1);
|
||||
record->hashes.add_from_buffer(hash_collection::HASH_SHA1, header.sha1, sizeof(header.sha1));
|
||||
|
||||
/* found but needs a dump */
|
||||
if (hash_data_has_info(record->exphash, HASH_INFO_NO_DUMP))
|
||||
if (record->exphashes.flag(hash_collection::FLAG_NO_DUMP))
|
||||
set_status(record, AUDIT_STATUS_GOOD, SUBSTATUS_FOUND_NODUMP);
|
||||
|
||||
/* incorrect hash */
|
||||
else if (!hash_data_is_equal(record->exphash, record->hash, 0))
|
||||
else if (record->exphashes != record->hashes)
|
||||
set_status(record, AUDIT_STATUS_FOUND_INVALID, SUBSTATUS_FOUND_BAD_CHECKSUM);
|
||||
|
||||
/* correct hash but needs a redump */
|
||||
else if (hash_data_has_info(record->exphash, HASH_INFO_BAD_DUMP))
|
||||
else if (record->exphashes.flag(hash_collection::FLAG_BAD_DUMP))
|
||||
set_status(record, AUDIT_STATUS_GOOD, SUBSTATUS_GOOD_NEEDS_REDUMP);
|
||||
|
||||
/* just plain good */
|
||||
@ -500,9 +497,8 @@ static void audit_one_disk(core_options *options, const rom_entry *rom, const ga
|
||||
ROM is also used by the parent
|
||||
-------------------------------------------------*/
|
||||
|
||||
static int rom_used_by_parent(const game_driver *gamedrv, const rom_entry *romentry, const game_driver **parent)
|
||||
static int rom_used_by_parent(const game_driver *gamedrv, const hash_collection &romhashes, const game_driver **parent)
|
||||
{
|
||||
const char *hash = ROM_GETHASHDATA(romentry);
|
||||
const game_driver *drv;
|
||||
|
||||
/* iterate up the parent chain */
|
||||
@ -516,7 +512,7 @@ static int rom_used_by_parent(const game_driver *gamedrv, const rom_entry *romen
|
||||
for (const rom_source *source = rom_first_source(config); source != NULL; source = rom_next_source(*source))
|
||||
for (region = rom_first_region(*source); region; region = rom_next_region(region))
|
||||
for (rom = rom_first_file(region); rom; rom = rom_next_file(rom))
|
||||
if (hash_data_is_equal(ROM_GETHASHDATA(rom), hash, 0))
|
||||
if (hash_collection(ROM_GETHASHDATA(rom)) == romhashes)
|
||||
{
|
||||
if (parent != NULL)
|
||||
*parent = drv;
|
||||
|
@ -23,8 +23,8 @@
|
||||
***************************************************************************/
|
||||
|
||||
/* hashes to use for validation */
|
||||
#define AUDIT_VALIDATE_FAST (HASH_CRC)
|
||||
#define AUDIT_VALIDATE_FULL (HASH_CRC | HASH_SHA)
|
||||
#define AUDIT_VALIDATE_FAST "R" /* CRC only */
|
||||
#define AUDIT_VALIDATE_FULL "RS" /* CRC + SHA1 */
|
||||
|
||||
/* return values from audit_verify_roms and audit_verify_samples */
|
||||
enum
|
||||
@ -83,8 +83,8 @@ struct _audit_record
|
||||
const char * name; /* name of item */
|
||||
UINT32 explength; /* expected length of item */
|
||||
UINT32 length; /* actual length of item */
|
||||
const char * exphash; /* expected hash data */
|
||||
char hash[HASH_BUF_SIZE]; /* actual hash information */
|
||||
hash_collection exphashes; /* expected hash data */
|
||||
hash_collection hashes; /* actual hash information */
|
||||
};
|
||||
|
||||
|
||||
@ -93,7 +93,7 @@ struct _audit_record
|
||||
FUNCTION PROTOTYPES
|
||||
***************************************************************************/
|
||||
|
||||
int audit_images(core_options *options, const game_driver *gamedrv, UINT32 validation, audit_record **audit);
|
||||
int audit_images(core_options *options, const game_driver *gamedrv, const char *validation, audit_record **audit);
|
||||
int audit_samples(core_options *options, const game_driver *gamedrv, audit_record **audit);
|
||||
int audit_summary(const game_driver *gamedrv, int count, const audit_record *records, int output);
|
||||
|
||||
|
@ -61,7 +61,7 @@ static int info_listsoftware(core_options *options, const char *gamename);
|
||||
static void romident(core_options *options, const char *filename, romident_status *status);
|
||||
static void identify_file(core_options *options, const char *name, romident_status *status);
|
||||
static void identify_data(core_options *options, const char *name, const UINT8 *data, int length, romident_status *status);
|
||||
static void match_roms(core_options *options, const char *hash, int length, int *found);
|
||||
static void match_roms(core_options *options, const hash_collection &hashes, int length, int *found);
|
||||
static void display_suggestions(const char *gamename);
|
||||
|
||||
|
||||
@ -535,11 +535,10 @@ int cli_info_listcrc(core_options *options, const char *gamename)
|
||||
for (region = rom_first_region(*source); region; region = rom_next_region(region))
|
||||
for (rom = rom_first_file(region); rom; rom = rom_next_file(rom))
|
||||
{
|
||||
char hashbuf[HASH_BUF_SIZE];
|
||||
|
||||
/* if we have a CRC, display it */
|
||||
if (hash_data_extract_printable_checksum(ROM_GETHASHDATA(rom), HASH_CRC, hashbuf))
|
||||
mame_printf_info("%s %-12s %s\n", hashbuf, ROM_GETNAME(rom), drivers[drvindex]->description);
|
||||
UINT32 crc;
|
||||
if (hash_collection(ROM_GETHASHDATA(rom)).crc(crc))
|
||||
mame_printf_info("%08x %-12s %s\n", crc, ROM_GETNAME(rom), drivers[drvindex]->description);
|
||||
}
|
||||
|
||||
count++;
|
||||
@ -558,14 +557,13 @@ int cli_info_listcrc(core_options *options, const char *gamename)
|
||||
int cli_info_listroms(core_options *options, const char *gamename)
|
||||
{
|
||||
int drvindex, count = 0;
|
||||
astring tempstr;
|
||||
|
||||
/* iterate over drivers */
|
||||
for (drvindex = 0; drivers[drvindex] != NULL; drvindex++)
|
||||
if (mame_strwildcmp(gamename, drivers[drvindex]->name) == 0)
|
||||
{
|
||||
machine_config config(*drivers[drvindex]);
|
||||
const rom_entry *region, *rom;
|
||||
const rom_source *source;
|
||||
|
||||
/* print the header */
|
||||
if (count > 0)
|
||||
@ -574,20 +572,17 @@ int cli_info_listroms(core_options *options, const char *gamename)
|
||||
"Name Size Checksum\n", drivers[drvindex]->name);
|
||||
|
||||
/* iterate over sources, regions and then ROMs within the region */
|
||||
for (source = rom_first_source(config); source != NULL; source = rom_next_source(*source))
|
||||
for (region = rom_first_region(*source); region != NULL; region = rom_next_region(region))
|
||||
for (rom = rom_first_file(region); rom != NULL; rom = rom_next_file(rom))
|
||||
for (const rom_source *source = rom_first_source(config); source != NULL; source = rom_next_source(*source))
|
||||
for (const rom_entry *region = rom_first_region(*source); region != NULL; region = rom_next_region(region))
|
||||
for (const rom_entry *rom = rom_first_file(region); rom != NULL; rom = rom_next_file(rom))
|
||||
{
|
||||
const char *name = ROM_GETNAME(rom);
|
||||
const char *hash = ROM_GETHASHDATA(rom);
|
||||
char hashbuf[HASH_BUF_SIZE];
|
||||
int length = -1;
|
||||
|
||||
/* accumulate the total length of all chunks */
|
||||
int length = -1;
|
||||
if (ROMREGION_ISROMDATA(region))
|
||||
length = rom_file_size(rom);
|
||||
|
||||
/* start with the name */
|
||||
const char *name = ROM_GETNAME(rom);
|
||||
mame_printf_info("%-12s ", name);
|
||||
|
||||
/* output the length next */
|
||||
@ -597,13 +592,12 @@ int cli_info_listroms(core_options *options, const char *gamename)
|
||||
mame_printf_info(" ");
|
||||
|
||||
/* output the hash data */
|
||||
if (!hash_data_has_info(hash, HASH_INFO_NO_DUMP))
|
||||
hash_collection hashes(ROM_GETHASHDATA(rom));
|
||||
if (!hashes.flag(hash_collection::FLAG_NO_DUMP))
|
||||
{
|
||||
if (hash_data_has_info(hash, HASH_INFO_BAD_DUMP))
|
||||
if (hashes.flag(hash_collection::FLAG_BAD_DUMP))
|
||||
mame_printf_info(" BAD");
|
||||
|
||||
hash_data_print(hash, 0, hashbuf);
|
||||
mame_printf_info(" %s", hashbuf);
|
||||
mame_printf_info(" %s", hashes.macro_string(tempstr));
|
||||
}
|
||||
else
|
||||
mame_printf_info(" NO GOOD DUMP KNOWN");
|
||||
@ -975,23 +969,20 @@ static int info_listsoftware(core_options *options, const char *gamename)
|
||||
fprintf( out, "\t\t\t\t\t<disk name=\"%s\"", xml_normalize_string(ROM_GETNAME(rom)) );
|
||||
|
||||
/* dump checksum information only if there is a known dump */
|
||||
if (!hash_data_has_info(ROM_GETHASHDATA(rom), HASH_INFO_NO_DUMP))
|
||||
hash_collection hashes(ROM_GETHASHDATA(rom));
|
||||
if (!hashes.flag(hash_collection::FLAG_NO_DUMP))
|
||||
{
|
||||
char checksum[HASH_BUF_SIZE];
|
||||
int hashtype;
|
||||
|
||||
/* iterate over hash function types and print out their values */
|
||||
for (hashtype = 0; hashtype < HASH_NUM_FUNCTIONS; hashtype++)
|
||||
if (hash_data_extract_printable_checksum(ROM_GETHASHDATA(rom), 1 << hashtype, checksum))
|
||||
fprintf(out, " %s=\"%s\"", hash_function_name(1 << hashtype), checksum);
|
||||
astring tempstr;
|
||||
for (hash_base *hash = hashes.first(); hash != NULL; hash = hash->next())
|
||||
fprintf(out, " %s=\"%s\"", hash->name(), hash->string(tempstr));
|
||||
}
|
||||
|
||||
if (!is_disk)
|
||||
fprintf( out, " offset=\"0x%x\"", ROM_GETOFFSET(rom) );
|
||||
|
||||
if ( hash_data_has_info(ROM_GETHASHDATA(rom), HASH_INFO_BAD_DUMP) )
|
||||
if ( hashes.flag(hash_collection::FLAG_BAD_DUMP) )
|
||||
fprintf( out, " status=\"baddump\"" );
|
||||
if ( hash_data_has_info(ROM_GETHASHDATA(rom), HASH_INFO_NO_DUMP) )
|
||||
if ( hashes.flag(hash_collection::FLAG_NO_DUMP) )
|
||||
fprintf( out, " status=\"nodump\"" );
|
||||
|
||||
if (is_disk)
|
||||
@ -1081,7 +1072,7 @@ static int info_listsoftware(core_options *options, const char *gamename)
|
||||
softlist_match_roms - scan for a matching
|
||||
software ROM by hash
|
||||
-------------------------------------------------*/
|
||||
static void softlist_match_roms(core_options *options, const char *hash, int length, int *found)
|
||||
static void softlist_match_roms(core_options *options, const hash_collection &hashes, int length, int *found)
|
||||
{
|
||||
int drvindex;
|
||||
|
||||
@ -1108,9 +1099,10 @@ static void softlist_match_roms(core_options *options, const char *hash, int len
|
||||
{
|
||||
for ( const rom_entry *rom = rom_first_file(region); rom != NULL; rom = rom_next_file(rom) )
|
||||
{
|
||||
if ( hash_data_is_equal(hash, ROM_GETHASHDATA(rom), 0) )
|
||||
hash_collection romhashes(ROM_GETHASHDATA(rom));
|
||||
if ( hashes == romhashes )
|
||||
{
|
||||
int baddump = hash_data_has_info(ROM_GETHASHDATA(rom), HASH_INFO_BAD_DUMP);
|
||||
bool baddump = romhashes.flag(hash_collection::FLAG_BAD_DUMP);
|
||||
|
||||
/* output information about the match */
|
||||
if (*found != 0)
|
||||
@ -1416,20 +1408,18 @@ static void identify_file(core_options *options, const char *name, romident_stat
|
||||
}
|
||||
else
|
||||
{
|
||||
static const UINT8 nullhash[HASH_BUF_SIZE] = { 0 };
|
||||
char hash[HASH_BUF_SIZE]; /* actual hash information */
|
||||
|
||||
hash_data_clear(hash);
|
||||
static const UINT8 nullhash[20] = { 0 };
|
||||
hash_collection hashes;
|
||||
|
||||
/* if there's an MD5 or SHA1 hash, add them to the output hash */
|
||||
if (memcmp(nullhash, header.md5, sizeof(header.md5)) != 0)
|
||||
hash_data_insert_binary_checksum(hash, HASH_MD5, header.md5);
|
||||
hashes.add_from_buffer(hash_collection::HASH_MD5, header.md5, sizeof(header.md5));
|
||||
if (memcmp(nullhash, header.sha1, sizeof(header.sha1)) != 0)
|
||||
hash_data_insert_binary_checksum(hash, HASH_SHA1, header.sha1);
|
||||
hashes.add_from_buffer(hash_collection::HASH_SHA1, header.sha1, sizeof(header.sha1));
|
||||
|
||||
length = header.logicalbytes;
|
||||
|
||||
match_roms(options, hash, length, &found);
|
||||
match_roms(options, hashes, length, &found);
|
||||
|
||||
if (found == 0)
|
||||
{
|
||||
@ -1475,7 +1465,6 @@ static void identify_file(core_options *options, const char *name, romident_stat
|
||||
|
||||
static void identify_data(core_options *options, const char *name, const UINT8 *data, int length, romident_status *status)
|
||||
{
|
||||
char hash[HASH_BUF_SIZE];
|
||||
UINT8 *tempjed = NULL;
|
||||
astring basename;
|
||||
int found = 0;
|
||||
@ -1496,8 +1485,8 @@ static void identify_data(core_options *options, const char *name, const UINT8 *
|
||||
}
|
||||
|
||||
/* compute the hash of the data */
|
||||
hash_data_clear(hash);
|
||||
hash_compute(hash, data, length, HASH_SHA1 | HASH_CRC);
|
||||
hash_collection hashes;
|
||||
hashes.compute(data, length, hash_collection::HASH_TYPES_CRC_SHA1);
|
||||
|
||||
/* output the name */
|
||||
status->total++;
|
||||
@ -1505,7 +1494,7 @@ static void identify_data(core_options *options, const char *name, const UINT8 *
|
||||
mame_printf_info("%-20s", basename.cstr());
|
||||
|
||||
/* see if we can find a match in the ROMs */
|
||||
match_roms(options, hash, length, &found);
|
||||
match_roms(options, hashes, length, &found);
|
||||
|
||||
/* if we didn't find it, try to guess what it might be */
|
||||
if (found == 0)
|
||||
@ -1536,7 +1525,7 @@ static void identify_data(core_options *options, const char *name, const UINT8 *
|
||||
match_roms - scan for a matching ROM by hash
|
||||
-------------------------------------------------*/
|
||||
|
||||
static void match_roms(core_options *options, const char *hash, int length, int *found)
|
||||
static void match_roms(core_options *options, const hash_collection &hashes, int length, int *found)
|
||||
{
|
||||
int drvindex;
|
||||
|
||||
@ -1551,9 +1540,11 @@ static void match_roms(core_options *options, const char *hash, int length, int
|
||||
for (source = rom_first_source(config); source != NULL; source = rom_next_source(*source))
|
||||
for (region = rom_first_region(*source); region; region = rom_next_region(region))
|
||||
for (rom = rom_first_file(region); rom; rom = rom_next_file(rom))
|
||||
if (hash_data_is_equal(hash, ROM_GETHASHDATA(rom), 0))
|
||||
{
|
||||
hash_collection romhashes(ROM_GETHASHDATA(rom));
|
||||
if (hashes == romhashes)
|
||||
{
|
||||
int baddump = hash_data_has_info(ROM_GETHASHDATA(rom), HASH_INFO_BAD_DUMP);
|
||||
bool baddump = romhashes.flag(hash_collection::FLAG_NO_DUMP);
|
||||
|
||||
/* output information about the match */
|
||||
if (*found != 0)
|
||||
@ -1561,7 +1552,8 @@ static void match_roms(core_options *options, const char *hash, int length, int
|
||||
mame_printf_info("= %s%-20s %-10s %s\n", baddump ? "(BAD) " : "", ROM_GETNAME(rom), drivers[drvindex]->name, drivers[drvindex]->description);
|
||||
(*found)++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
softlist_match_roms( options, hash, length, found );
|
||||
softlist_match_roms( options, hashes, length, found );
|
||||
}
|
||||
|
@ -313,13 +313,10 @@ bool legacy_image_device_base::load_software(char *swlist, char *swname, rom_ent
|
||||
/* handle files */
|
||||
if (ROMENTRY_ISFILE(romp))
|
||||
{
|
||||
UINT32 crc = 0;
|
||||
UINT8 crcbytes[4];
|
||||
file_error filerr = FILERR_NOT_FOUND;
|
||||
|
||||
bool has_crc = hash_data_extract_binary_checksum(ROM_GETHASHDATA(romp), HASH_CRC, crcbytes);
|
||||
if (has_crc)
|
||||
crc = (crcbytes[0] << 24) | (crcbytes[1] << 16) | (crcbytes[2] << 8) | crcbytes[3];
|
||||
UINT32 crc = 0;
|
||||
bool has_crc = hash_collection(ROM_GETHASHDATA(romp)).crc(crc);
|
||||
|
||||
// attempt reading up the chain through the parents and create a locationtag astring in the format
|
||||
// " swlist % clonename % parentname "
|
||||
|
@ -142,16 +142,16 @@ iodevice_t device_config_image_interface::device_typeid(const char *name)
|
||||
using this device's partial hash if appropriate
|
||||
-------------------------------------------------*/
|
||||
|
||||
void device_config_image_interface::device_compute_hash(char *dest, const void *data, size_t length, unsigned int functions) const
|
||||
void device_config_image_interface::device_compute_hash(hash_collection &hashes, const void *data, size_t length, const char *types) const
|
||||
{
|
||||
/* retrieve the partial hash func */
|
||||
device_image_partialhash_func partialhash = get_partial_hash();
|
||||
|
||||
/* compute the hash */
|
||||
if (partialhash)
|
||||
partialhash(dest, (const unsigned char*)data, length, functions);
|
||||
partialhash(hashes, (const unsigned char*)data, length, types);
|
||||
else
|
||||
hash_compute(dest, (const unsigned char*)data, length, functions);
|
||||
hashes.compute(reinterpret_cast<const UINT8 *>(data), length, types);
|
||||
}
|
||||
|
||||
|
||||
@ -505,26 +505,6 @@ void device_image_interface::image_freeptr(void *ptr)
|
||||
to be loaded
|
||||
****************************************************************************/
|
||||
|
||||
/*-------------------------------------------------
|
||||
hash_data_extract_crc32 - extract crc32 value
|
||||
from hash string
|
||||
-------------------------------------------------*/
|
||||
|
||||
static UINT32 hash_data_extract_crc32(const char *d)
|
||||
{
|
||||
UINT32 crc = 0;
|
||||
UINT8 crc_bytes[4];
|
||||
|
||||
if (hash_data_extract_binary_checksum(d, HASH_CRC, crc_bytes) == 1)
|
||||
{
|
||||
crc = (((UINT32) crc_bytes[0]) << 24)
|
||||
| (((UINT32) crc_bytes[1]) << 16)
|
||||
| (((UINT32) crc_bytes[2]) << 8)
|
||||
| (((UINT32) crc_bytes[3]) << 0);
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
int device_image_interface::read_hash_config(const char *sysname)
|
||||
{
|
||||
hash_file *hashfile = NULL;
|
||||
@ -536,7 +516,7 @@ int device_image_interface::read_hash_config(const char *sysname)
|
||||
goto done;
|
||||
|
||||
/* look up this entry in the hash file */
|
||||
info = hashfile_lookup(hashfile, m_hash.cstr());
|
||||
info = hashfile_lookup(hashfile, m_hash);
|
||||
|
||||
if (!info)
|
||||
goto done;
|
||||
@ -557,13 +537,13 @@ done:
|
||||
|
||||
|
||||
|
||||
void device_image_interface::run_hash(void (*partialhash)(char *, const unsigned char *, unsigned long, unsigned int),
|
||||
char *dest, unsigned int hash_functions)
|
||||
void device_image_interface::run_hash(void (*partialhash)(hash_collection &, const unsigned char *, unsigned long, const char *),
|
||||
hash_collection &hashes, const char *types)
|
||||
{
|
||||
UINT32 size;
|
||||
UINT8 *buf = NULL;
|
||||
|
||||
*dest = '\0';
|
||||
hashes.reset();
|
||||
size = (UINT32) length();
|
||||
|
||||
buf = (UINT8*)malloc(size);
|
||||
@ -574,9 +554,9 @@ void device_image_interface::run_hash(void (*partialhash)(char *, const unsigned
|
||||
fread(buf, size);
|
||||
|
||||
if (partialhash)
|
||||
partialhash(dest, buf, size, hash_functions);
|
||||
partialhash(hashes, buf, size, types);
|
||||
else
|
||||
hash_compute(dest, buf, size, hash_functions);
|
||||
hashes.compute(buf, size, types);
|
||||
|
||||
/* cleanup */
|
||||
free(buf);
|
||||
@ -588,12 +568,11 @@ void device_image_interface::run_hash(void (*partialhash)(char *, const unsigned
|
||||
void device_image_interface::image_checkhash()
|
||||
{
|
||||
const game_driver *drv;
|
||||
char hash_string[HASH_BUF_SIZE];
|
||||
device_image_partialhash_func partialhash;
|
||||
int rc;
|
||||
|
||||
/* only calculate CRC if it hasn't been calculated, and the open_mode is read only */
|
||||
if (!m_hash && !m_writeable && !m_created)
|
||||
if (m_hash.first() == NULL && !m_writeable && !m_created)
|
||||
{
|
||||
/* do not cause a linear read of 600 megs please */
|
||||
/* TODO: use SHA/MD5 in the CHD header as the hash */
|
||||
@ -607,9 +586,7 @@ void device_image_interface::image_checkhash()
|
||||
/* retrieve the partial hash func */
|
||||
partialhash = get_partial_hash();
|
||||
|
||||
run_hash(partialhash, hash_string, HASH_CRC | HASH_MD5 | HASH_SHA1);
|
||||
|
||||
m_hash = hash_string;
|
||||
run_hash(partialhash, m_hash, hash_collection::HASH_TYPES_ALL);
|
||||
|
||||
/* now read the hash file */
|
||||
drv = device().machine->gamedrv;
|
||||
@ -628,8 +605,7 @@ UINT32 device_image_interface::crc()
|
||||
UINT32 crc = 0;
|
||||
|
||||
image_checkhash();
|
||||
if (m_hash)
|
||||
crc = hash_data_extract_crc32(m_hash.cstr());
|
||||
m_hash.crc(crc);
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
@ -113,7 +113,7 @@ typedef int (*device_image_load_func)(device_image_interface &image);
|
||||
typedef int (*device_image_create_func)(device_image_interface &image, int format_type, option_resolution *format_options);
|
||||
typedef void (*device_image_unload_func)(device_image_interface &image);
|
||||
typedef void (*device_image_display_func)(device_image_interface &image);
|
||||
typedef void (*device_image_partialhash_func)(char *, const unsigned char *, unsigned long, unsigned int);
|
||||
typedef void (*device_image_partialhash_func)(hash_collection &, const unsigned char *, unsigned long, const char *);
|
||||
typedef void (*device_image_get_devices_func)(device_image_interface &device);
|
||||
typedef bool (*device_image_softlist_load_func)(device_image_interface &image, char *swlist, char *swname, rom_entry *start_entry);
|
||||
|
||||
@ -178,7 +178,7 @@ public:
|
||||
static iodevice_t device_typeid(const char *name);
|
||||
|
||||
virtual device_image_partialhash_func get_partial_hash() const = 0;
|
||||
virtual void device_compute_hash(char *dest, const void *data, size_t length, unsigned int functions) const;
|
||||
virtual void device_compute_hash(hash_collection &hashes, const void *data, size_t length, const char *types) const;
|
||||
protected:
|
||||
static const image_device_type_info *find_device_type(iodevice_t type);
|
||||
static const image_device_type_info m_device_info_array[];
|
||||
@ -282,7 +282,7 @@ protected:
|
||||
bool try_change_working_directory(const char *subdir);
|
||||
|
||||
int read_hash_config(const char *sysname);
|
||||
void run_hash(void (*partialhash)(char *, const unsigned char *, unsigned long, unsigned int), char *dest, unsigned int hash_functions);
|
||||
void run_hash(void (*partialhash)(hash_collection &, const unsigned char *, unsigned long, const char *), hash_collection &hashes, const char *types);
|
||||
void image_checkhash();
|
||||
// derived class overrides
|
||||
|
||||
@ -328,7 +328,7 @@ protected:
|
||||
|
||||
object_pool *m_mempool;
|
||||
|
||||
astring m_hash;
|
||||
hash_collection m_hash;
|
||||
};
|
||||
|
||||
|
||||
|
@ -62,6 +62,7 @@
|
||||
|
||||
// emulator-specific utilities
|
||||
#include "attotime.h"
|
||||
#include "hash.h"
|
||||
#include "fileio.h" // remove me once NVRAM is implemented as device
|
||||
#include "tokenize.h"
|
||||
#include "delegate.h"
|
||||
|
@ -206,27 +206,39 @@ emu_file::operator core_file *()
|
||||
// hash - returns the hash for a file
|
||||
//-------------------------------------------------
|
||||
|
||||
const char *emu_file::hash_string(UINT32 functions)
|
||||
hash_collection &emu_file::hashes(const char *types)
|
||||
{
|
||||
// if we already have the functions we need, just return
|
||||
UINT32 wehave = hash_data_used_functions(m_hash);
|
||||
if ((wehave & functions) == functions)
|
||||
return m_hash;
|
||||
|
||||
// load the ZIP file now if we haven't yet
|
||||
// determine which hashes we need
|
||||
astring needed;
|
||||
for (const char *scan = types; *scan != 0; scan++)
|
||||
if (m_hashes.hash(*scan) == NULL)
|
||||
needed.cat(*scan);
|
||||
|
||||
// if we need nothing, skip it
|
||||
if (!needed)
|
||||
return m_hashes;
|
||||
|
||||
// load the ZIP file if needed
|
||||
if (m_zipfile != NULL && load_zipped_file() != FILERR_NONE)
|
||||
return m_hash;
|
||||
return m_hashes;
|
||||
if (m_file == NULL)
|
||||
return m_hash;
|
||||
return m_hashes;
|
||||
|
||||
// if we have ZIP data, just hash that directly
|
||||
if (m_zipdata != NULL)
|
||||
{
|
||||
m_hashes.compute(m_zipdata, m_ziplength, needed);
|
||||
return m_hashes;
|
||||
}
|
||||
|
||||
// read the data if we can
|
||||
const UINT8 *filedata = (const UINT8 *)core_fbuffer(m_file);
|
||||
if (filedata == NULL)
|
||||
return m_hash;
|
||||
return m_hashes;
|
||||
|
||||
// compute the hash
|
||||
hash_compute(m_hash, filedata, core_fsize(m_file), wehave | functions);
|
||||
return m_hash;
|
||||
m_hashes.compute(filedata, core_fsize(m_file), needed);
|
||||
return m_hashes;
|
||||
}
|
||||
|
||||
|
||||
@ -377,6 +389,10 @@ void emu_file::close()
|
||||
if (m_remove_on_close)
|
||||
osd_rmfile(m_fullpath);
|
||||
m_remove_on_close = false;
|
||||
|
||||
// reset our hashes and path as well
|
||||
m_hashes.reset();
|
||||
m_fullpath.reset();
|
||||
}
|
||||
|
||||
|
||||
@ -652,14 +668,8 @@ file_error emu_file::attempt_zipped()
|
||||
m_ziplength = header->uncompressed_length;
|
||||
|
||||
// build a hash with just the CRC
|
||||
hash_data_clear(m_hash);
|
||||
UINT8 crcs[4];
|
||||
crcs[0] = header->crc >> 24;
|
||||
crcs[1] = header->crc >> 16;
|
||||
crcs[2] = header->crc >> 8;
|
||||
crcs[3] = header->crc >> 0;
|
||||
hash_data_insert_binary_checksum(m_hash, HASH_CRC, crcs);
|
||||
|
||||
m_hashes.reset();
|
||||
m_hashes.add_crc(header->crc);
|
||||
return (m_openflags & OPEN_FLAG_NO_PRELOAD) ? FILERR_NONE : load_zipped_file();
|
||||
}
|
||||
|
||||
|
@ -151,7 +151,7 @@ public:
|
||||
const char *filename() const { return m_filename; }
|
||||
const char *fullpath() const { return m_fullpath; }
|
||||
UINT32 openflags() const { return m_openflags; }
|
||||
const char *hash_string(UINT32 functions);
|
||||
hash_collection &hashes(const char *types);
|
||||
|
||||
// setters
|
||||
void remove_on_close() { m_remove_on_close = true; }
|
||||
@ -203,7 +203,7 @@ private:
|
||||
path_iterator m_iterator; // iterator for paths
|
||||
UINT32 m_crc; // iterator for paths
|
||||
UINT32 m_openflags; // flags we used for the open
|
||||
char m_hash[HASH_BUF_SIZE]; // hash data for the file
|
||||
hash_collection m_hashes; // collection of hashes
|
||||
zip_file * m_zipfile; // ZIP file pointer
|
||||
UINT8 * m_zipdata; // ZIP file data
|
||||
UINT64 m_ziplength; // ZIP file length
|
||||
|
1386
src/emu/hash.c
1386
src/emu/hash.c
File diff suppressed because it is too large
Load Diff
207
src/emu/hash.h
207
src/emu/hash.h
@ -1,79 +1,188 @@
|
||||
/*********************************************************************
|
||||
/***************************************************************************
|
||||
|
||||
hash.h
|
||||
|
||||
Function to handle hash functions (checksums)
|
||||
|
||||
Copyright Nicola Salmoria and the MAME Team.
|
||||
Visit http://mamedev.org for licensing and usage restrictions.
|
||||
Based on original idea by Farfetch'd
|
||||
|
||||
*********************************************************************/
|
||||
****************************************************************************
|
||||
|
||||
Copyright Aaron Giles
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name 'MAME' nor the names of its contributors may be
|
||||
used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __HASH_H__
|
||||
#define __HASH_H__
|
||||
|
||||
#define HASH_INFO_NO_DUMP 0
|
||||
#define HASH_INFO_BAD_DUMP 1
|
||||
|
||||
#define HASH_CRC (1 << 0)
|
||||
#define HASH_SHA1 (1 << 1)
|
||||
#define HASH_MD5 (1 << 2)
|
||||
//**************************************************************************
|
||||
// MACROS
|
||||
//**************************************************************************
|
||||
|
||||
#define HASH_NUM_FUNCTIONS 3
|
||||
// use these to define compile-time internal-format hash strings
|
||||
#define CRC(x) "R" #x
|
||||
#define MD5(x) "M" #x
|
||||
#define SHA1(x) "S" #x
|
||||
#define NO_DUMP "!"
|
||||
#define BAD_DUMP "^"
|
||||
|
||||
// Standard size of a hash data buffer, all the manipulated buffers
|
||||
// must respect this size
|
||||
#define HASH_BUF_SIZE 256
|
||||
|
||||
// Get function name of the specified function
|
||||
const char* hash_function_name(unsigned int function);
|
||||
|
||||
// Check if const char* contains the checksum for a specific function
|
||||
int hash_data_has_checksum(const char* d, unsigned int function);
|
||||
//**************************************************************************
|
||||
// TYPE DEFINITIONS
|
||||
//**************************************************************************
|
||||
|
||||
// Extract the binary or printable checksum of a specific function from a hash data. If the checksum information
|
||||
// is not available, the functions return 0. If the pointer to the output buffer is NULL, the function will
|
||||
// return the minimum size of the output buffer required to store the informations. Otherwise, the buffer
|
||||
// will be filled and the function will return 1 as success code.
|
||||
int hash_data_extract_binary_checksum(const char* d, unsigned int function, unsigned char* checksum);
|
||||
int hash_data_extract_printable_checksum(const char* d, unsigned int function, char* checksum);
|
||||
|
||||
// Insert an already computed binary checksum inside a hash data. This is useful when we already have
|
||||
// checksum informations (e.g, from archive headers) and we want to prepare a hash data to compare
|
||||
// with another const char* (e.g. the expected checksums). Returns 0 in case of error, 1 if the checksum
|
||||
// was added correctly, 2 if the checksum was added overwriting a previously existing checksum for the
|
||||
// the same function
|
||||
int hash_data_insert_binary_checksum(char* d, unsigned int function, const unsigned char* checksum);
|
||||
int hash_data_insert_printable_checksum(char* d, unsigned int function, const char* checksum);
|
||||
// ======================> hash_base
|
||||
|
||||
// Check if the hash data contains the requested info
|
||||
int hash_data_has_info(const char* d, unsigned int info);
|
||||
// base class for all hash types, which does most of the heavy lifting
|
||||
class hash_base
|
||||
{
|
||||
friend class simple_list<hash_base>;
|
||||
|
||||
// Compare two hash data to check if they are the same. 'functions' can be either a combination of the
|
||||
// hash function bits (HASH_CRC, etc) or zero to ask to check for all the available checksums
|
||||
int hash_data_is_equal(const char* d1, const char* d2, unsigned int functions);
|
||||
public:
|
||||
// construction/destruction
|
||||
hash_base(char id, const char *name, UINT8 length, UINT8 *bufptr);
|
||||
|
||||
// operators
|
||||
bool operator==(const hash_base &rhs) const { return (m_length == rhs.m_length && memcmp(m_bufptr, rhs.m_bufptr, m_length) == 0); }
|
||||
bool operator!=(const hash_base &rhs) const { return (m_length != rhs.m_length || memcmp(m_bufptr, rhs.m_bufptr, m_length) != 0); }
|
||||
|
||||
// getters
|
||||
hash_base *next() const { return m_next; }
|
||||
char id() const { return m_id; }
|
||||
const char *name() const { return m_name; }
|
||||
int length() const { return m_length; }
|
||||
bool in_progress() const { return m_in_progress; }
|
||||
bool parse_error() const { return m_parse_error; }
|
||||
UINT8 byte(int index) const { return (index >= 0 && index < m_length) ? m_bufptr[index] : 0; }
|
||||
|
||||
// buffer conversion
|
||||
const UINT8 *buffer() { return m_bufptr; }
|
||||
bool from_buffer(const UINT8 *buffer, int buflen);
|
||||
|
||||
// string conversion
|
||||
const char *string(astring &buffer);
|
||||
bool from_string(const char *&string, int length);
|
||||
|
||||
// creation
|
||||
virtual void begin() = 0;
|
||||
virtual void buffer(const UINT8 *data, UINT32 length) = 0;
|
||||
virtual void end() = 0;
|
||||
|
||||
protected:
|
||||
// internal helpers
|
||||
int fromhex(char c);
|
||||
|
||||
// internal state
|
||||
hash_base * m_next;
|
||||
const char * m_name;
|
||||
bool m_in_progress;
|
||||
bool m_parse_error;
|
||||
char m_id;
|
||||
UINT8 m_length;
|
||||
UINT8 * m_bufptr;
|
||||
};
|
||||
|
||||
// Print hash data informations in a standard format. 'functions' can be either a combination of the
|
||||
// hash function bits (HASH_CRC, etc) or zero to ask to print all the available checksums
|
||||
void hash_data_print(const char* d, unsigned int functions, char* buffer);
|
||||
|
||||
// Copy hash data informations
|
||||
void hash_data_copy(char* dst, const char* src);
|
||||
// ======================> hash_collection
|
||||
|
||||
// Clear hash data informations
|
||||
void hash_data_clear(char* dst);
|
||||
// a collection of the various supported hashes and flags
|
||||
class hash_collection
|
||||
{
|
||||
public:
|
||||
// hash types are identified by non-hex alpha values (G-Z)
|
||||
static const char HASH_CRC = 'R';
|
||||
static const char HASH_MD5 = 'M';
|
||||
static const char HASH_SHA1 = 'S';
|
||||
|
||||
// common combinations for requests
|
||||
static const char *HASH_TYPES_CRC;
|
||||
static const char *HASH_TYPES_CRC_SHA1;
|
||||
static const char *HASH_TYPES_ALL;
|
||||
|
||||
// flags are identified by punctuation marks
|
||||
static const char FLAG_NO_DUMP = '!';
|
||||
static const char FLAG_BAD_DUMP = '^';
|
||||
|
||||
// Check which functions we have a checksum of inside the data
|
||||
unsigned int hash_data_used_functions(const char* d);
|
||||
// construction/destruction
|
||||
hash_collection();
|
||||
hash_collection(const char *string);
|
||||
hash_collection(const hash_collection &src);
|
||||
~hash_collection();
|
||||
|
||||
// operators
|
||||
hash_collection &operator=(const hash_collection &src);
|
||||
bool operator==(const hash_collection &rhs) const;
|
||||
bool operator!=(const hash_collection &rhs) const { return !(*this == rhs); }
|
||||
|
||||
// Compute hash of a data chunk in memory. Parameter 'functions' specifies which hashing functions
|
||||
// we want the checksum of.
|
||||
void hash_compute(char* dst, const unsigned char* data, unsigned long length, unsigned int functions);
|
||||
// getters
|
||||
bool flag(char flag) const { return (m_flags.chr(0, flag) != -1); }
|
||||
hash_base *hash(char type) const;
|
||||
hash_base *first() const { return m_hashlist.first(); }
|
||||
const char *hash_types(astring &buffer) const;
|
||||
bool parse_errors() const;
|
||||
|
||||
// Verifies that a hash string is valid
|
||||
int hash_verify_string(const char *hash);
|
||||
// hash manipulators
|
||||
void reset();
|
||||
hash_base *add_from_buffer(char type, const UINT8 *buffer, int bufflen);
|
||||
hash_base *add_from_string(char type, const char *buffer, int length);
|
||||
bool remove(char type);
|
||||
|
||||
// CRC-specific helpers
|
||||
bool crc(UINT32 &result);
|
||||
hash_base *add_crc(UINT32 crc);
|
||||
|
||||
// string conversion
|
||||
const char *internal_string(astring &buffer) const;
|
||||
const char *macro_string(astring &buffer) const;
|
||||
bool from_internal_string(const char *string);
|
||||
|
||||
// creation
|
||||
void begin(const char *types = NULL);
|
||||
void buffer(const UINT8 *data, UINT32 length);
|
||||
void end();
|
||||
void compute(const UINT8 *data, UINT32 length, const char *types = NULL) { begin(types); buffer(data, length); end(); }
|
||||
|
||||
private:
|
||||
// internal helpers
|
||||
static hash_base *alloc_by_id(char id);
|
||||
void copyfrom(const hash_collection &src);
|
||||
|
||||
// internal state
|
||||
astring m_flags;
|
||||
simple_list<hash_base> m_hashlist;
|
||||
};
|
||||
|
||||
|
||||
#endif /* __HASH_H__ */
|
||||
|
@ -18,7 +18,7 @@ struct _hash_file
|
||||
{
|
||||
emu_file *file;
|
||||
object_pool *pool;
|
||||
unsigned int functions[IO_COUNT];
|
||||
astring functions[IO_COUNT];
|
||||
|
||||
hash_info **preloaded_hashes;
|
||||
int preloaded_hash_count;
|
||||
@ -43,7 +43,7 @@ struct hash_parse_state
|
||||
hash_file *hashfile;
|
||||
int done;
|
||||
|
||||
int (*selector_proc)(hash_file *hashfile, void *param, const char *name, const char *hash);
|
||||
int (*selector_proc)(hash_file *hashfile, void *param, const char *name, const hash_collection &hashes);
|
||||
void (*use_proc)(hash_file *hashfile, void *param, hash_info *hi);
|
||||
void (*error_proc)(const char *message);
|
||||
void *param;
|
||||
@ -142,8 +142,9 @@ static void start_handler(void *data, const char *tagname, const char **attribut
|
||||
const char *name;
|
||||
hash_info *hi;
|
||||
char **text_dest;
|
||||
char hash_string[HASH_BUF_SIZE];
|
||||
unsigned int functions, all_functions;
|
||||
hash_collection hashes;
|
||||
astring all_functions;
|
||||
char functions;
|
||||
iodevice_t device;
|
||||
int i;
|
||||
|
||||
@ -164,8 +165,6 @@ static void start_handler(void *data, const char *tagname, const char **attribut
|
||||
{
|
||||
// we are now examining a hash tag
|
||||
name = NULL;
|
||||
memset(hash_string, 0, sizeof(hash_string));
|
||||
all_functions = 0;
|
||||
device = IO_COUNT;
|
||||
|
||||
while(attributes[0])
|
||||
@ -179,17 +178,17 @@ static void start_handler(void *data, const char *tagname, const char **attribut
|
||||
else if (!strcmp(attributes[0], "crc32"))
|
||||
{
|
||||
/* crc32 attribute */
|
||||
functions = HASH_CRC;
|
||||
functions = hash_collection::HASH_CRC;
|
||||
}
|
||||
else if (!strcmp(attributes[0], "md5"))
|
||||
{
|
||||
/* md5 attribute */
|
||||
functions = HASH_MD5;
|
||||
functions = hash_collection::HASH_MD5;
|
||||
}
|
||||
else if (!strcmp(attributes[0], "sha1"))
|
||||
{
|
||||
/* sha1 attribute */
|
||||
functions = HASH_SHA1;
|
||||
functions = hash_collection::HASH_SHA1;
|
||||
}
|
||||
else if (!strcmp(attributes[0], "type"))
|
||||
{
|
||||
@ -208,23 +207,19 @@ static void start_handler(void *data, const char *tagname, const char **attribut
|
||||
|
||||
if (functions)
|
||||
{
|
||||
hash_data_insert_printable_checksum(hash_string, functions, attributes[1]);
|
||||
all_functions |= functions;
|
||||
hashes.add_from_string(functions, attributes[1], strlen(attributes[1]));
|
||||
all_functions.cat(functions);
|
||||
}
|
||||
|
||||
attributes += 2;
|
||||
}
|
||||
|
||||
if (device == IO_COUNT)
|
||||
{
|
||||
for (i = 0; i < IO_COUNT; i++)
|
||||
state->hashfile->functions[i] |= all_functions;
|
||||
}
|
||||
else
|
||||
state->hashfile->functions[device] |= all_functions;
|
||||
for (i = 0; i < IO_COUNT; i++)
|
||||
if (i == device || device == IO_COUNT)
|
||||
state->hashfile->functions[i] = all_functions;
|
||||
|
||||
/* do we use this hash? */
|
||||
if (!state->selector_proc || state->selector_proc(state->hashfile, state->param, name, hash_string))
|
||||
if (!state->selector_proc || state->selector_proc(state->hashfile, state->param, name, hashes))
|
||||
{
|
||||
hi = (hash_info*)pool_malloc_lib(state->hashfile->pool, sizeof(hash_info));
|
||||
if (!hi)
|
||||
@ -235,7 +230,7 @@ static void start_handler(void *data, const char *tagname, const char **attribut
|
||||
if (!hi->longname)
|
||||
return;
|
||||
|
||||
strcpy(hi->hash, hash_string);
|
||||
hi->hashes = hashes;
|
||||
state->hi = hi;
|
||||
}
|
||||
}
|
||||
@ -331,7 +326,7 @@ static void data_handler(void *data, const XML_Char *s, int len)
|
||||
-------------------------------------------------*/
|
||||
|
||||
static void hashfile_parse(hash_file *hashfile,
|
||||
int (*selector_proc)(hash_file *hashfile, void *param, const char *name, const char *hash),
|
||||
int (*selector_proc)(hash_file *hashfile, void *param, const char *name, const hash_collection &hashes),
|
||||
void (*use_proc)(hash_file *hashfile, void *param, hash_info *hi),
|
||||
void (*error_proc)(const char *message),
|
||||
void *param)
|
||||
@ -469,15 +464,14 @@ void hashfile_close(hash_file *hashfile)
|
||||
|
||||
struct hashlookup_params
|
||||
{
|
||||
const char *hash;
|
||||
hash_collection hashes;
|
||||
hash_info *hi;
|
||||
};
|
||||
|
||||
static int singular_selector_proc(hash_file *hashfile, void *param, const char *name, const char *hash)
|
||||
static int singular_selector_proc(hash_file *hashfile, void *param, const char *name, const hash_collection &hashes)
|
||||
{
|
||||
struct hashlookup_params *hlparams = (struct hashlookup_params *) param;
|
||||
return hash_data_is_equal(hash, hlparams->hash,
|
||||
hash_data_used_functions(hash)) == 1;
|
||||
return (hashes == hlparams->hashes);
|
||||
}
|
||||
|
||||
|
||||
@ -498,17 +492,17 @@ static void singular_use_proc(hash_file *hashfile, void *param, hash_info *hi)
|
||||
hashfile_lookup
|
||||
-------------------------------------------------*/
|
||||
|
||||
const hash_info *hashfile_lookup(hash_file *hashfile, const char *hash)
|
||||
const hash_info *hashfile_lookup(hash_file *hashfile, const hash_collection &hashes)
|
||||
{
|
||||
struct hashlookup_params param;
|
||||
int i;
|
||||
|
||||
param.hash = hash;
|
||||
param.hashes = hashes;
|
||||
param.hi = NULL;
|
||||
|
||||
for (i = 0; i < hashfile->preloaded_hash_count; i++)
|
||||
{
|
||||
if (singular_selector_proc(hashfile, ¶m, NULL, hashfile->preloaded_hashes[i]->hash))
|
||||
if (singular_selector_proc(hashfile, ¶m, NULL, hashfile->preloaded_hashes[i]->hashes))
|
||||
return hashfile->preloaded_hashes[i];
|
||||
}
|
||||
|
||||
@ -523,7 +517,7 @@ const hash_info *hashfile_lookup(hash_file *hashfile, const char *hash)
|
||||
hashfile_functions_used
|
||||
-------------------------------------------------*/
|
||||
|
||||
unsigned int hashfile_functions_used(hash_file *hashfile, iodevice_t devtype)
|
||||
const char *hashfile_functions_used(hash_file *hashfile, iodevice_t devtype)
|
||||
{
|
||||
assert(devtype >= 0);
|
||||
assert(devtype < IO_COUNT);
|
||||
|
@ -20,7 +20,7 @@
|
||||
typedef struct _hash_info hash_info;
|
||||
struct _hash_info
|
||||
{
|
||||
char hash[HASH_BUF_SIZE];
|
||||
hash_collection hashes;
|
||||
const char *longname;
|
||||
const char *manufacturer;
|
||||
const char *year;
|
||||
@ -46,13 +46,13 @@ hash_file *hashfile_open(core_options &options, const char *sysname, int is_prel
|
||||
void hashfile_close(hash_file *hashfile);
|
||||
|
||||
/* looks up information in a hash file */
|
||||
const hash_info *hashfile_lookup(hash_file *hashfile, const char *hash);
|
||||
const hash_info *hashfile_lookup(hash_file *hashfile, const hash_collection &hashes);
|
||||
|
||||
/* performs a syntax check on a hash file */
|
||||
int hashfile_verify(const char *sysname, void (*error_proc)(const char *message));
|
||||
|
||||
/* returns the functions used in this hash file */
|
||||
unsigned int hashfile_functions_used(hash_file *hashfile, iodevice_t devtype);
|
||||
const char *hashfile_functions_used(hash_file *hashfile, iodevice_t devtype);
|
||||
|
||||
|
||||
#endif /* __HASHFILE_H__ */
|
||||
|
@ -193,12 +193,13 @@ static multicart_open_error load_rom_resource(multicart_load_state *state, xml_d
|
||||
/* check SHA1 now */
|
||||
if ((sha1 = xml_get_attribute_string(resource_node, "sha1", NULL)))
|
||||
{
|
||||
char calc_sha[256];
|
||||
hash_collection actual_hashes;
|
||||
actual_hashes.compute((const UINT8 *)resource->ptr, resource->length, hash_collection::HASH_TYPES_CRC_SHA1);
|
||||
|
||||
hash_collection expected_hashes;
|
||||
expected_hashes.add_from_string(hash_collection::HASH_SHA1, sha1, strlen(sha1));
|
||||
|
||||
memset(calc_sha, 0, sizeof(calc_sha));
|
||||
hash_compute(&calc_sha[0], (const unsigned char*)resource->ptr, resource->length, HASH_SHA1);
|
||||
|
||||
if ((strncmp(sha1, &calc_sha[2], 20)))
|
||||
if (actual_hashes != expected_hashes)
|
||||
{
|
||||
return MCERR_INVALID_FILE_REF;
|
||||
}
|
||||
|
@ -452,11 +452,11 @@ static void print_game_bios(FILE *out, const game_driver *game)
|
||||
parent set
|
||||
-------------------------------------------------*/
|
||||
|
||||
static const char *get_merge_name(const rom_entry *rom, int parents, const parent_info **pinfoarray)
|
||||
static const char *get_merge_name(const hash_collection &romhashes, int parents, const parent_info **pinfoarray)
|
||||
{
|
||||
int parent;
|
||||
const char *merge_name = NULL;
|
||||
|
||||
|
||||
for (parent = 0; parent < parents; ++parent)
|
||||
{
|
||||
const machine_config *pconfig = &pinfoarray[parent]->mconfig;
|
||||
@ -467,7 +467,7 @@ static const char *get_merge_name(const rom_entry *rom, int parents, const paren
|
||||
for (psource = rom_first_source(*pconfig); psource != NULL; psource = rom_next_source(*psource))
|
||||
for (pregion = rom_first_region(*psource); pregion != NULL; pregion = rom_next_region(pregion))
|
||||
for (prom = rom_first_file(pregion); prom != NULL; prom = rom_next_file(prom))
|
||||
if (hash_data_is_equal(ROM_GETHASHDATA(rom), ROM_GETHASHDATA(prom), 0))
|
||||
if (romhashes == hash_collection(ROM_GETHASHDATA(prom)))
|
||||
{
|
||||
merge_name = ROM_GETNAME(prom);
|
||||
break;
|
||||
@ -528,9 +528,10 @@ static void print_game_rom(FILE *out, const game_driver *game, const machine_con
|
||||
continue;
|
||||
|
||||
/* if we have a valid ROM and we are a clone, see if we can find the parent ROM */
|
||||
if (!ROM_NOGOODDUMP(rom) && parents > 0)
|
||||
hash_collection hashes(ROM_GETHASHDATA(rom));
|
||||
if (!hashes.flag(hash_collection::FLAG_NO_DUMP) && parents > 0)
|
||||
{
|
||||
merge_name = get_merge_name(rom, parents, pinfoarray);
|
||||
merge_name = get_merge_name(hashes, parents, pinfoarray);
|
||||
}
|
||||
|
||||
/* scan for a BIOS name */
|
||||
@ -565,24 +566,21 @@ static void print_game_rom(FILE *out, const game_driver *game, const machine_con
|
||||
fprintf(out, " size=\"%d\"", rom_file_size(rom));
|
||||
|
||||
/* dump checksum information only if there is a known dump */
|
||||
if (!hash_data_has_info(ROM_GETHASHDATA(rom), HASH_INFO_NO_DUMP))
|
||||
if (!hashes.flag(hash_collection::FLAG_NO_DUMP))
|
||||
{
|
||||
char checksum[HASH_BUF_SIZE];
|
||||
int hashtype;
|
||||
|
||||
/* iterate over hash function types and print out their values */
|
||||
for (hashtype = 0; hashtype < HASH_NUM_FUNCTIONS; hashtype++)
|
||||
if (hash_data_extract_printable_checksum(ROM_GETHASHDATA(rom), 1 << hashtype, checksum))
|
||||
fprintf(out, " %s=\"%s\"", hash_function_name(1 << hashtype), checksum);
|
||||
astring tempstr;
|
||||
for (hash_base *hash = hashes.first(); hash != NULL; hash = hash->next())
|
||||
fprintf(out, " %s=\"%s\"", hash->name(), hash->string(tempstr));
|
||||
}
|
||||
|
||||
/* append a region name */
|
||||
fprintf(out, " region=\"%s\"", ROMREGION_GETTAG(region));
|
||||
|
||||
/* add nodump/baddump flags */
|
||||
if (hash_data_has_info(ROM_GETHASHDATA(rom), HASH_INFO_NO_DUMP))
|
||||
if (hashes.flag(hash_collection::FLAG_NO_DUMP))
|
||||
fprintf(out, " status=\"nodump\"");
|
||||
if (hash_data_has_info(ROM_GETHASHDATA(rom), HASH_INFO_BAD_DUMP))
|
||||
if (hashes.flag(hash_collection::FLAG_BAD_DUMP))
|
||||
fprintf(out, " status=\"baddump\"");
|
||||
|
||||
/* for non-disk entries, print offset */
|
||||
|
@ -434,7 +434,7 @@ static void handle_missing_file(rom_load_data *romdata, const rom_entry *romp)
|
||||
}
|
||||
|
||||
/* no good dumps are okay */
|
||||
else if (ROM_NOGOODDUMP(romp))
|
||||
else if (hash_collection(ROM_GETHASHDATA(romp)).flag(hash_collection::FLAG_NO_DUMP))
|
||||
{
|
||||
romdata->errorstring.catprintf("%s NOT FOUND (NO GOOD DUMP KNOWN)\n", ROM_GETNAME(romp));
|
||||
romdata->knownbad++;
|
||||
@ -455,46 +455,19 @@ static void handle_missing_file(rom_load_data *romdata, const rom_entry *romp)
|
||||
correct checksums for a given ROM
|
||||
-------------------------------------------------*/
|
||||
|
||||
static void dump_wrong_and_correct_checksums(rom_load_data *romdata, const char *hash, const char *acthash)
|
||||
static void dump_wrong_and_correct_checksums(rom_load_data *romdata, const hash_collection &hashes, const hash_collection &acthashes)
|
||||
{
|
||||
unsigned i;
|
||||
char chksum[256];
|
||||
unsigned found_functions;
|
||||
unsigned wrong_functions;
|
||||
astring tempstr;
|
||||
romdata->errorstring.catprintf(" EXPECTED: %s\n", hashes.macro_string(tempstr));
|
||||
romdata->errorstring.catprintf(" FOUND: %s\n", acthashes.macro_string(tempstr));
|
||||
|
||||
found_functions = hash_data_used_functions(hash) & hash_data_used_functions(acthash);
|
||||
|
||||
hash_data_print(hash, found_functions, chksum);
|
||||
romdata->errorstring.catprintf(" EXPECTED: %s\n", chksum);
|
||||
|
||||
/* We dump informations only of the functions for which MAME provided
|
||||
a correct checksum. Other functions we might have calculated are
|
||||
useless here */
|
||||
hash_data_print(acthash, found_functions, chksum);
|
||||
romdata->errorstring.catprintf(" FOUND: %s\n", chksum);
|
||||
|
||||
/* For debugging purposes, we check if the checksums available in the
|
||||
driver are correctly specified or not. This can be done by checking
|
||||
the return value of one of the extract functions. Maybe we want to
|
||||
activate this only in debug buils, but many developers only use
|
||||
release builds, so I keep it as is for now. */
|
||||
wrong_functions = 0;
|
||||
for (i = 0; i < HASH_NUM_FUNCTIONS; i++)
|
||||
if (hash_data_extract_printable_checksum(hash, 1 << i, chksum) == 2)
|
||||
wrong_functions |= 1 << i;
|
||||
|
||||
if (wrong_functions)
|
||||
{
|
||||
for (i = 0; i < HASH_NUM_FUNCTIONS; i++)
|
||||
if (wrong_functions & (1 << i))
|
||||
{
|
||||
romdata->errorstring.catprintf(
|
||||
"\tInvalid %s checksum treated as 0 (check leading zeros)\n",
|
||||
hash_function_name(1 << i));
|
||||
|
||||
romdata->warnings++;
|
||||
}
|
||||
}
|
||||
// warn about any ill-formed hashes
|
||||
for (hash_base *hash = hashes.first(); hash != NULL; hash = hash->next())
|
||||
if (hash->parse_error())
|
||||
{
|
||||
romdata->errorstring.catprintf("\tInvalid %s checksum treated as 0 (check leading zeros)\n", hash->name());
|
||||
romdata->warnings++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -503,20 +476,14 @@ static void dump_wrong_and_correct_checksums(rom_load_data *romdata, const char
|
||||
and hash signatures of a file
|
||||
-------------------------------------------------*/
|
||||
|
||||
static void verify_length_and_hash(rom_load_data *romdata, const char *name, UINT32 explength, const char *hash)
|
||||
static void verify_length_and_hash(rom_load_data *romdata, const char *name, UINT32 explength, const hash_collection &hashes)
|
||||
{
|
||||
UINT32 actlength;
|
||||
const char* acthash;
|
||||
|
||||
/* we've already complained if there is no file */
|
||||
if (romdata->file == NULL)
|
||||
return;
|
||||
|
||||
/* get the length and CRC from the file */
|
||||
actlength = romdata->file->size();
|
||||
acthash = romdata->file->hash_string(hash_data_used_functions(hash));
|
||||
|
||||
/* verify length */
|
||||
UINT32 actlength = romdata->file->size();
|
||||
if (explength != actlength)
|
||||
{
|
||||
romdata->errorstring.catprintf("%s WRONG LENGTH (expected: %08x found: %08x)\n", name, explength, actlength);
|
||||
@ -524,23 +491,23 @@ static void verify_length_and_hash(rom_load_data *romdata, const char *name, UIN
|
||||
}
|
||||
|
||||
/* If there is no good dump known, write it */
|
||||
if (hash_data_has_info(hash, HASH_INFO_NO_DUMP))
|
||||
astring tempstr;
|
||||
hash_collection &acthashes = romdata->file->hashes(hashes.hash_types(tempstr));
|
||||
if (hashes.flag(hash_collection::FLAG_NO_DUMP))
|
||||
{
|
||||
romdata->errorstring.catprintf("%s NO GOOD DUMP KNOWN\n", name);
|
||||
romdata->knownbad++;
|
||||
}
|
||||
/* verify checksums */
|
||||
else if (!hash_data_is_equal(hash, acthash, 0))
|
||||
else if (hashes != acthashes)
|
||||
{
|
||||
/* otherwise, it's just bad */
|
||||
romdata->errorstring.catprintf("%s WRONG CHECKSUMS:\n", name);
|
||||
|
||||
dump_wrong_and_correct_checksums(romdata, hash, acthash);
|
||||
|
||||
dump_wrong_and_correct_checksums(romdata, hashes, acthashes);
|
||||
romdata->warnings++;
|
||||
}
|
||||
/* If it matches, but it is actually a bad dump, write it */
|
||||
else if (hash_data_has_info(hash, HASH_INFO_BAD_DUMP))
|
||||
else if (hashes.flag(hash_collection::FLAG_BAD_DUMP))
|
||||
{
|
||||
romdata->errorstring.catprintf("%s ROM NEEDS REDUMP\n",name);
|
||||
romdata->knownbad++;
|
||||
@ -646,17 +613,13 @@ static int open_rom_file(rom_load_data *romdata, const char *regiontag, const ro
|
||||
file_error filerr = FILERR_NOT_FOUND;
|
||||
UINT32 romsize = rom_file_size(romp);
|
||||
const game_driver *drv;
|
||||
int has_crc = FALSE;
|
||||
UINT8 crcbytes[4];
|
||||
UINT32 crc = 0;
|
||||
|
||||
/* update status display */
|
||||
display_loading_rom_message(romdata, ROM_GETNAME(romp));
|
||||
|
||||
/* extract CRC to use for searching */
|
||||
has_crc = hash_data_extract_binary_checksum(ROM_GETHASHDATA(romp), HASH_CRC, crcbytes);
|
||||
if (has_crc)
|
||||
crc = (crcbytes[0] << 24) | (crcbytes[1] << 16) | (crcbytes[2] << 8) | crcbytes[3];
|
||||
UINT32 crc = 0;
|
||||
bool has_crc = hash_collection(ROM_GETHASHDATA(romp)).crc(crc);
|
||||
|
||||
/* attempt reading up the chain through the parents. It automatically also
|
||||
attempts any kind of load by checksum supported by the archives. */
|
||||
@ -1006,7 +969,7 @@ static void process_rom_entries(rom_load_data *romdata, const char *regiontag, c
|
||||
if (baserom)
|
||||
{
|
||||
LOG(("Verifying length (%X) and checksums\n", explength));
|
||||
verify_length_and_hash(romdata, ROM_GETNAME(baserom), explength, ROM_GETHASHDATA(baserom));
|
||||
verify_length_and_hash(romdata, ROM_GETNAME(baserom), explength, hash_collection(ROM_GETHASHDATA(baserom)));
|
||||
LOG(("Verify finished\n"));
|
||||
}
|
||||
|
||||
@ -1148,6 +1111,7 @@ chd_error open_disk_image(core_options &options, const game_driver *gamedrv, con
|
||||
|
||||
/* otherwise, look at our parents for a CHD with an identical checksum */
|
||||
/* and try to open that */
|
||||
hash_collection romphashes(ROM_GETHASHDATA(romp));
|
||||
for (drv = gamedrv; drv != NULL; drv = driver_get_clone(drv))
|
||||
{
|
||||
machine_config config(*drv);
|
||||
@ -1158,7 +1122,7 @@ chd_error open_disk_image(core_options &options, const game_driver *gamedrv, con
|
||||
|
||||
/* look for a differing name but with the same hash data */
|
||||
if (strcmp(ROM_GETNAME(romp), ROM_GETNAME(rom)) != 0 &&
|
||||
hash_data_is_equal(ROM_GETHASHDATA(romp), ROM_GETHASHDATA(rom), 0))
|
||||
romphashes == hash_collection(ROM_GETHASHDATA(rom)))
|
||||
{
|
||||
/* attempt to open the properly named file, scanning up through parent directories */
|
||||
filerr = FILERR_NOT_FOUND;
|
||||
@ -1249,7 +1213,7 @@ static void process_disk_entries(rom_load_data *romdata, const char *regiontag,
|
||||
/* handle files */
|
||||
if (ROMENTRY_ISFILE(romp))
|
||||
{
|
||||
char acthash[HASH_BUF_SIZE];
|
||||
hash_collection hashes(ROM_GETHASHDATA(romp));
|
||||
open_chd chd = { 0 };
|
||||
chd_header header;
|
||||
chd_error err;
|
||||
@ -1271,7 +1235,7 @@ static void process_disk_entries(rom_load_data *romdata, const char *regiontag,
|
||||
romdata->errorstring.catprintf("%s CHD ERROR: %s\n", filename.cstr(), chd_error_string(err));
|
||||
|
||||
/* if this is NO_DUMP, keep going, though the system may not be able to handle it */
|
||||
if (hash_data_has_info(ROM_GETHASHDATA(romp), HASH_INFO_NO_DUMP))
|
||||
if (hashes.flag(hash_collection::FLAG_NO_DUMP))
|
||||
romdata->knownbad++;
|
||||
else if (DISK_ISOPTIONAL(romp))
|
||||
romdata->warnings++;
|
||||
@ -1282,17 +1246,17 @@ static void process_disk_entries(rom_load_data *romdata, const char *regiontag,
|
||||
|
||||
/* get the header and extract the MD5/SHA1 */
|
||||
header = *chd_get_header(chd.origchd);
|
||||
hash_data_clear(acthash);
|
||||
hash_data_insert_binary_checksum(acthash, HASH_SHA1, header.sha1);
|
||||
hash_collection acthashes;
|
||||
acthashes.add_from_buffer(hash_collection::HASH_SHA1, header.sha1, sizeof(header.sha1));
|
||||
|
||||
/* verify the hash */
|
||||
if (!hash_data_is_equal(ROM_GETHASHDATA(romp), acthash, 0))
|
||||
if (hashes != acthashes)
|
||||
{
|
||||
romdata->errorstring.catprintf("%s WRONG CHECKSUMS:\n", filename.cstr());
|
||||
dump_wrong_and_correct_checksums(romdata, ROM_GETHASHDATA(romp), acthash);
|
||||
dump_wrong_and_correct_checksums(romdata, hashes, acthashes);
|
||||
romdata->warnings++;
|
||||
}
|
||||
else if (hash_data_has_info(ROM_GETHASHDATA(romp), HASH_INFO_BAD_DUMP))
|
||||
else if (hashes.flag(hash_collection::FLAG_BAD_DUMP))
|
||||
{
|
||||
romdata->errorstring.catprintf("%s CHD NEEDS REDUMP\n", filename.cstr());
|
||||
romdata->knownbad++;
|
||||
|
@ -189,7 +189,6 @@ struct rom_entry
|
||||
#define ROM_GETBITSHIFT(r) ((ROM_GETFLAGS(r) & ROM_BITSHIFTMASK) >> 20)
|
||||
#define ROM_INHERITSFLAGS(r) ((ROM_GETFLAGS(r) & ROM_INHERITFLAGSMASK) == ROM_INHERITFLAGS)
|
||||
#define ROM_GETBIOSFLAGS(r) ((ROM_GETFLAGS(r) & ROM_BIOSFLAGSMASK) >> 24)
|
||||
#define ROM_NOGOODDUMP(r) (hash_data_has_info((r)->_hashdata, HASH_INFO_NO_DUMP))
|
||||
|
||||
|
||||
/* ----- per-disk macros ----- */
|
||||
@ -257,14 +256,6 @@ struct rom_entry
|
||||
#define DISK_IMAGE_READONLY_OPTIONAL(name,idx,hash) ROMX_LOAD(name, idx, 0, hash, DISK_READONLY | ROM_OPTIONAL)
|
||||
|
||||
|
||||
/* ----- hash macros ----- */
|
||||
#define CRC(x) "c:" #x "#"
|
||||
#define SHA1(x) "s:" #x "#"
|
||||
#define MD5(x) "m:" #x "#"
|
||||
#define NO_DUMP "$ND$"
|
||||
#define BAD_DUMP "$BD$"
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
FUNCTION PROTOTYPES
|
||||
|
@ -670,7 +670,7 @@ static void start_handler(void *data, const char *tagname, const char **attribut
|
||||
return;
|
||||
|
||||
strcpy( s_name, str_name );
|
||||
sprintf( hashdata, "c:%s#s:%s#%s", str_crc, str_sha1, ( nodump ? NO_DUMP : ( baddump ? BAD_DUMP : "" ) ) );
|
||||
sprintf( hashdata, "%c%s%c%s%s", hash_collection::HASH_CRC, str_crc, hash_collection::HASH_SHA1, str_sha1, ( nodump ? NO_DUMP : ( baddump ? BAD_DUMP : "" ) ) );
|
||||
|
||||
/* Handle loadflag attribute */
|
||||
if ( str_loadflag && !strcmp(str_loadflag, "load16_word_swap") )
|
||||
@ -1689,7 +1689,8 @@ static DEVICE_VALIDITY_CHECK( software_list )
|
||||
}
|
||||
|
||||
/* make sure the hash is valid */
|
||||
if (!hash_verify_string(data->_hashdata))
|
||||
hash_collection hashes;
|
||||
if (!hashes.from_internal_string(data->_hashdata))
|
||||
{
|
||||
mame_printf_error("%s: %s has rom '%s' with an invalid hash string '%s'\n", swlist->list_name[i], swinfo->shortname, data->_name, data->_hashdata);
|
||||
error = TRUE;
|
||||
|
@ -523,7 +523,6 @@ static bool validate_roms(const machine_config &config, region_array *rgninfo, g
|
||||
/* if this is a file, make sure it is properly formatted */
|
||||
else if (ROMENTRY_ISFILE(romp))
|
||||
{
|
||||
const char *hash;
|
||||
const char *s;
|
||||
|
||||
items_since_region++;
|
||||
@ -541,10 +540,10 @@ static bool validate_roms(const machine_config &config, region_array *rgninfo, g
|
||||
}
|
||||
|
||||
/* make sure the hash is valid */
|
||||
hash = ROM_GETHASHDATA(romp);
|
||||
if (!hash_verify_string(hash))
|
||||
hash_collection hashes;
|
||||
if (!hashes.from_internal_string(ROM_GETHASHDATA(romp)))
|
||||
{
|
||||
mame_printf_error("%s: rom '%s' has an invalid hash string '%s'\n", driver.name, last_name, hash);
|
||||
mame_printf_error("%s: rom '%s' has an invalid hash string '%s'\n", driver.name, last_name, ROM_GETHASHDATA(romp));
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user