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:
Aaron Giles 2011-02-14 08:41:08 +00:00
parent 06d479c54f
commit 5e4df8c772
19 changed files with 1108 additions and 995 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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 );
}

View File

@ -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 "

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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"

View File

@ -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();
}

View 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

File diff suppressed because it is too large Load Diff

View File

@ -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__ */

View File

@ -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, &param, NULL, hashfile->preloaded_hashes[i]->hash))
if (singular_selector_proc(hashfile, &param, 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);

View File

@ -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__ */

View File

@ -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;
}

View File

@ -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 */

View File

@ -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++;

View File

@ -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

View File

@ -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;

View File

@ -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;
}
}