diff options
Diffstat (limited to 'src/emu/audit.c')
-rw-r--r-- | src/emu/audit.c | 693 |
1 files changed, 315 insertions, 378 deletions
diff --git a/src/emu/audit.c b/src/emu/audit.c index 76b9ab5dbee..1393a335737 100644 --- a/src/emu/audit.c +++ b/src/emu/audit.c @@ -4,8 +4,36 @@ ROM set auditing functions. - Copyright Nicola Salmoria and the MAME Team. - Visit http://mamedev.org for licensing and usage restrictions. +**************************************************************************** + + 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. ***************************************************************************/ @@ -17,510 +45,419 @@ #include "sound/samples.h" +//************************************************************************** +// CORE FUNCTIONS +//************************************************************************** -/*************************************************************************** - FUNCTION PROTOTYPES -***************************************************************************/ - -static void audit_one_rom(emu_options &options, const rom_entry *rom, const char *regiontag, const game_driver *gamedrv, const char *validation, audit_record *record); -static void audit_one_disk(emu_options &options, const rom_entry *rom, const game_driver *gamedrv, const char *validation, audit_record *record); -static int rom_used_by_parent(emu_options &options, const game_driver *gamedrv, const hash_collection &romhashes, const game_driver **parent); - - - -/*************************************************************************** - INLINE FUNCTIONS -***************************************************************************/ +//------------------------------------------------- +// media_auditor - constructor +//------------------------------------------------- -/*------------------------------------------------- - set_status - shortcut for setting status and - substatus values --------------------------------------------------*/ - -INLINE void set_status(audit_record *record, UINT8 status, UINT8 substatus) +media_auditor::media_auditor(const driver_enumerator &enumerator) + : m_enumerator(enumerator), + m_validation(AUDIT_VALIDATE_FULL), + m_searchpath(NULL) { - record->status = status; - record->substatus = substatus; } +//------------------------------------------------- +// audit_media - audit the media described by the +// currently-enumerated driver +//------------------------------------------------- -/*************************************************************************** - CORE FUNCTIONS -***************************************************************************/ - -/*------------------------------------------------- - audit_images - validate the ROM and disk - images for a game --------------------------------------------------*/ - -int audit_images(emu_options &options, const game_driver *gamedrv, const char *validation, audit_record **audit) +media_auditor::summary media_auditor::audit_media(const char *validation) { - machine_config config(*gamedrv, options); - const rom_entry *region, *rom; - const rom_source *source; - audit_record *record; - int anyfound = FALSE; - int anyrequired = FALSE; - int allshared = TRUE; - int records; - - /* determine the number of records we will generate */ - records = 0; - bool source_is_gamedrv = true; - 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)) - if (ROMREGION_ISROMDATA(region) || ROMREGION_ISDISKDATA(region)) - { - if (source_is_gamedrv && !ROM_ISOPTIONAL(rom)) - { - hash_collection hashes(ROM_GETHASHDATA(rom)); - if (!hashes.flag(hash_collection::FLAG_NO_DUMP)) - { - anyrequired = TRUE; - if (allshared && !rom_used_by_parent(options, gamedrv, hashes, NULL)) - allshared = FALSE; - } - } - records++; - } + // start fresh + m_record_list.reset(); - source_is_gamedrv = false; - } + // store validation for later + m_validation = validation; - if (records > 0) + // iterate over ROM sources and regions + bool anyfound = false; + bool anyrequired = false; + for (const rom_source *source = rom_first_source(m_enumerator.config()); source != NULL; source = rom_next_source(*source)) { - /* allocate memory for the records */ - *audit = global_alloc_array_clear(audit_record, records); - record = *audit; - - /* iterate over ROM sources and regions */ - bool source_is_gamedrv = true; - 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)) + // determine the search path for this source and iterate through the regions + m_searchpath = source->searchpath(); + + // also determine if this is the driver's specific ROMs or not + bool source_is_gamedrv = (dynamic_cast<const driver_device_config_base *>(source) != NULL); + + // now iterate over regions and ROMs within + 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; rom = rom_next_file(rom)) { - const char *regiontag = ROMREGION_ISLOADBYNAME(region) ? ROM_GETNAME(region) : NULL; - for (rom = rom_first_file(region); rom; rom = rom_next_file(rom)) - { - /* audit a file */ - if (ROMREGION_ISROMDATA(region)) - { - audit_one_rom(options, rom, regiontag, gamedrv, validation, record); - } - - /* audit a disk */ - else if (ROMREGION_ISDISKDATA(region)) - { - audit_one_disk(options, rom, gamedrv, validation, record); - } - - else - { - continue; - } - - if (source_is_gamedrv && record->status != AUDIT_STATUS_NOT_FOUND && (allshared || !rom_used_by_parent(options, gamedrv, record->exphashes, NULL))) - anyfound = TRUE; - - record++; - } + hash_collection hashes(ROM_GETHASHDATA(rom)); + + // if a dump exists, then at least one entry is required + if (!hashes.flag(hash_collection::FLAG_NO_DUMP)) + anyrequired = true; + + // audit a file + audit_record *record = NULL; + if (ROMREGION_ISROMDATA(region)) + record = audit_one_rom(rom); + + // audit a disk + else if (ROMREGION_ISDISKDATA(region)) + record = audit_one_disk(rom); + + // skip if no record + if (record == NULL) + continue; + + // if we got a record back, + if (record->status() != audit_record::STATUS_NOT_FOUND && source_is_gamedrv && also_used_by_parent(hashes) == -1) + anyfound = true; } - source_is_gamedrv = false; - } } - /* if we found nothing, we don't have the set at all */ + // if we found nothing, we don't have the set at all if (!anyfound && anyrequired) - { - global_free(*audit); - *audit = NULL; - records = 0; - } - - return records; + m_record_list.reset(); + + // return a summary + return summarize(); } -/*------------------------------------------------- - audit_samples - validate the samples for a - game --------------------------------------------------*/ +//------------------------------------------------- +// audit_samples - validate the samples for the +// currently-enumerated driver +//------------------------------------------------- -int audit_samples(emu_options &options, const game_driver *gamedrv, audit_record **audit) +media_auditor::summary media_auditor::audit_samples() { - machine_config config(*gamedrv, options); - audit_record *record; - int records = 0; - int sampnum; - - /* count the number of sample records attached to this driver */ - const device_config_sound_interface *sound = NULL; - for (bool gotone = config.m_devicelist.first(sound); gotone; gotone = sound->next(sound)) - if (sound->devconfig().type() == SAMPLES) - { - const samples_interface *intf = (const samples_interface *)sound->devconfig().static_config(); - - if (intf->samplenames != NULL) - { - /* iterate over samples in this entry */ - for (sampnum = 0; intf->samplenames[sampnum] != NULL; sampnum++) - if (intf->samplenames[sampnum][0] != '*') - records++; - } - } - - /* if no records, just quit now */ - if (records == 0) - goto skip; - - /* allocate memory for the records */ - *audit = global_alloc_array_clear(audit_record, records); - record = *audit; + // start fresh + m_record_list.reset(); - /* now iterate over sample entries */ - for (bool gotone = config.m_devicelist.first(sound); gotone; gotone = sound->next(sound)) - if (sound->devconfig().type() == SAMPLES) + // iterate over sample entries + for (const device_config *devconfig = m_enumerator.config().first_device(); devconfig != NULL; devconfig = devconfig->next()) + if (devconfig->type() == SAMPLES) { - const samples_interface *intf = (const samples_interface *)sound->devconfig().static_config(); - const char *sharedname = NULL; - + const samples_interface *intf = reinterpret_cast<const samples_interface *>(devconfig->static_config()); if (intf->samplenames != NULL) { - /* iterate over samples in this entry */ - for (sampnum = 0; intf->samplenames[sampnum] != NULL; sampnum++) + // by default we just search using the driver name + astring searchpath(m_enumerator.driver().name); + + // iterate over samples in this entry + for (int sampnum = 0; intf->samplenames[sampnum] != NULL; sampnum++) + { + // starred entries indicate an additional searchpath if (intf->samplenames[sampnum][0] == '*') - sharedname = &intf->samplenames[sampnum][1]; - else { - /* attempt to access the file from the game driver name */ - emu_file file(options.sample_path(), OPEN_FLAG_READ | OPEN_FLAG_NO_PRELOAD); - file_error filerr = file.open(gamedrv->name, PATH_SEPARATOR, intf->samplenames[sampnum]); - - /* attempt to access the file from the shared driver name */ - if (filerr != FILERR_NONE && sharedname != NULL) - filerr = file.open(sharedname, PATH_SEPARATOR, intf->samplenames[sampnum]); - - /* fill in the record */ - record->type = AUDIT_FILE_SAMPLE; - record->name = intf->samplenames[sampnum]; + searchpath.cat(";").cat(&intf->samplenames[sampnum][1]); + continue; + } + + // create a new record + audit_record &record = m_record_list.append(*global_alloc(audit_record(intf->samplenames[sampnum], audit_record::MEDIA_SAMPLE))); + + // look for the files + emu_file file(m_enumerator.options().sample_path(), OPEN_FLAG_READ | OPEN_FLAG_NO_PRELOAD); + path_iterator path(searchpath); + astring curpath; + while (path.next(curpath, intf->samplenames[sampnum])) + { + // attempt to access the file + file_error filerr = file.open(curpath); if (filerr == FILERR_NONE) - set_status(record++, AUDIT_STATUS_GOOD, SUBSTATUS_GOOD); + record.set_status(audit_record::STATUS_GOOD, audit_record::SUBSTATUS_GOOD); else - set_status(record++, AUDIT_STATUS_NOT_FOUND, SUBSTATUS_NOT_FOUND); + record.set_status(audit_record::STATUS_NOT_FOUND, audit_record::SUBSTATUS_NOT_FOUND); } + } } } - -skip: - return records; + + // return a summary + return summarize(); } -/*------------------------------------------------- - audit_summary - output a summary given a - list of audit records --------------------------------------------------*/ +//------------------------------------------------- +// summary - generate a summary, with an optional +// string format +//------------------------------------------------- -int audit_summary(const game_driver *gamedrv, int count, const audit_record *records, int output) +media_auditor::summary media_auditor::summarize(astring *string) { - int overall_status = CORRECT; - int recnum; - - /* no count AND no records means not found */ - if (count == 0 && records == NULL) + // no count AND no records means not found + if (m_record_list.count() == 0) return NOTFOUND; - /* loop over records */ - for (recnum = 0; recnum < count; recnum++) + // loop over records + summary overall_status = CORRECT; + for (audit_record *record = m_record_list.first(); record != NULL; record = record->next()) { - const audit_record *record = &records[recnum]; - int best_new_status = INCORRECT; + summary best_new_status = INCORRECT; - /* skip anything that's fine */ - if (record->substatus == SUBSTATUS_GOOD) + // skip anything that's fine + if (record->substatus() == audit_record::SUBSTATUS_GOOD) continue; - /* output the game name, file name, and length (if applicable) */ - if (output) + // output the game name, file name, and length (if applicable) + if (string != NULL) { - mame_printf_info("%-8s: %s", gamedrv->name, record->name); - if (record->explength > 0) - mame_printf_info(" (%d bytes)", record->explength); - mame_printf_info(" - "); + string->catprintf("%-12s: %s", m_enumerator.driver().name, record->name()); + if (record->expected_length() > 0) + string->catprintf(" (%d bytes)", record->expected_length()); + string->catprintf(" - "); } - /* use the substatus for finer details */ - switch (record->substatus) + // use the substatus for finer details + switch (record->substatus()) { - case SUBSTATUS_GOOD_NEEDS_REDUMP: - if (output) mame_printf_info("NEEDS REDUMP\n"); + case audit_record::SUBSTATUS_GOOD_NEEDS_REDUMP: + if (string != NULL) string->catprintf("NEEDS REDUMP\n"); best_new_status = BEST_AVAILABLE; break; - case SUBSTATUS_FOUND_NODUMP: - if (output) mame_printf_info("NO GOOD DUMP KNOWN\n"); + case audit_record::SUBSTATUS_FOUND_NODUMP: + if (string != NULL) string->catprintf("NO GOOD DUMP KNOWN\n"); best_new_status = BEST_AVAILABLE; break; - case SUBSTATUS_FOUND_BAD_CHECKSUM: - if (output) + case audit_record::SUBSTATUS_FOUND_BAD_CHECKSUM: + if (string != NULL) { astring tempstr; - mame_printf_info("INCORRECT CHECKSUM:\n"); - mame_printf_info("EXPECTED: %s\n", record->exphashes.macro_string(tempstr)); - mame_printf_info(" FOUND: %s\n", record->hashes.macro_string(tempstr)); + string->catprintf("INCORRECT CHECKSUM:\n"); + string->catprintf("EXPECTED: %s\n", record->expected_hashes().macro_string(tempstr)); + string->catprintf(" FOUND: %s\n", record->actual_hashes().macro_string(tempstr)); } break; - case SUBSTATUS_FOUND_WRONG_LENGTH: - if (output) mame_printf_info("INCORRECT LENGTH: %d bytes\n", record->length); + case audit_record::SUBSTATUS_FOUND_WRONG_LENGTH: + if (string != NULL) string->catprintf("INCORRECT LENGTH: %d bytes\n", record->actual_length()); break; - case SUBSTATUS_NOT_FOUND: - if (output) mame_printf_info("NOT FOUND\n"); + case audit_record::SUBSTATUS_NOT_FOUND: + if (string != NULL) string->catprintf("NOT FOUND\n"); break; - case SUBSTATUS_NOT_FOUND_NODUMP: - if (output) mame_printf_info("NOT FOUND - NO GOOD DUMP KNOWN\n"); + case audit_record::SUBSTATUS_NOT_FOUND_NODUMP: + if (string != NULL) string->catprintf("NOT FOUND - NO GOOD DUMP KNOWN\n"); best_new_status = BEST_AVAILABLE; break; - case SUBSTATUS_NOT_FOUND_OPTIONAL: - if (output) mame_printf_info("NOT FOUND BUT OPTIONAL\n"); + case audit_record::SUBSTATUS_NOT_FOUND_OPTIONAL: + if (string != NULL) string->catprintf("NOT FOUND BUT OPTIONAL\n"); best_new_status = BEST_AVAILABLE; break; - case SUBSTATUS_NOT_FOUND_PARENT: - if (output) mame_printf_info("NOT FOUND (shared with parent)\n"); + case audit_record::SUBSTATUS_NOT_FOUND_PARENT: + if (string != NULL) string->catprintf("NOT FOUND (shared with parent)\n"); break; - case SUBSTATUS_NOT_FOUND_BIOS: - if (output) mame_printf_info("NOT FOUND (BIOS)\n"); + case audit_record::SUBSTATUS_NOT_FOUND_BIOS: + if (string != NULL) string->catprintf("NOT FOUND (BIOS)\n"); break; + + default: + assert(false); } - /* downgrade the overall status if necessary */ + // downgrade the overall status if necessary overall_status = MAX(overall_status, best_new_status); } - return overall_status; } +//------------------------------------------------- +// audit_one_rom - validate a single ROM entry +//------------------------------------------------- -/*************************************************************************** - UTILITIES -***************************************************************************/ - -/*------------------------------------------------- - audit_one_rom - validate a single ROM entry --------------------------------------------------*/ - -static void audit_one_rom(emu_options &options, const rom_entry *rom, const char *regiontag, const game_driver *gamedrv, const char *validation, audit_record *record) +audit_record *media_auditor::audit_one_rom(const rom_entry *rom) { - const game_driver *drv; - UINT32 crc = 0; + // allocate and append a new record + audit_record &record = m_record_list.append(*global_alloc(audit_record(*rom, audit_record::MEDIA_ROM))); - /* fill in the record basics */ - record->type = AUDIT_FILE_ROM; - record->name = ROM_GETNAME(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 */ - bool has_crc = record->exphashes.crc(crc); + // see if we have a CRC and extract it if so + UINT32 crc = 0; + bool has_crc = record.expected_hashes().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)) + // find the file and checksum it, getting the file length along the way + emu_file file(m_enumerator.options().media_path(), OPEN_FLAG_READ | OPEN_FLAG_NO_PRELOAD); + path_iterator path(m_searchpath); + astring curpath; + while (path.next(curpath, record.name())) { - emu_file file(options.media_path(), OPEN_FLAG_READ | OPEN_FLAG_NO_PRELOAD); - - /* open the file if we can */ + // open the file if we can file_error filerr; if (has_crc) - filerr = file.open(drv->name, PATH_SEPARATOR, ROM_GETNAME(rom), crc); + filerr = file.open(curpath, crc); else - filerr = file.open(drv->name, PATH_SEPARATOR, ROM_GETNAME(rom)); + filerr = file.open(curpath); + + // if it worked, get the actual length and hashes, then stop if (filerr == FILERR_NONE) { - record->hashes = file.hashes(validation); - record->length = (UINT32)file.size(); + record.set_actual(file.hashes(m_validation), file.size()); break; } } + + // compute the final status + compute_status(record, rom, record.actual_length() != 0); + return &record; +} - /* if not found, check the region as a backup */ - if (record->length == 0 && regiontag != NULL) - { - emu_file file(options.media_path(), OPEN_FLAG_READ | OPEN_FLAG_NO_PRELOAD); - - /* open the file if we can */ - file_error filerr; - if (has_crc) - filerr = file.open(regiontag, PATH_SEPARATOR, ROM_GETNAME(rom), crc); - else - filerr = file.open(regiontag, PATH_SEPARATOR, ROM_GETNAME(rom)); - if (filerr == FILERR_NONE) - { - record->hashes = file.hashes(validation); - record->length = (UINT32)file.size(); - } - } - - /* if we failed to find the file, set the appropriate status */ - if (record->length == 0) - { - const game_driver *parent; - - /* no good dump */ - if (record->exphashes.flag(hash_collection::FLAG_NO_DUMP)) - set_status(record, AUDIT_STATUS_NOT_FOUND, SUBSTATUS_NOT_FOUND_NODUMP); - - /* optional ROM */ - else if (ROM_ISOPTIONAL(rom)) - set_status(record, AUDIT_STATUS_NOT_FOUND, SUBSTATUS_NOT_FOUND_OPTIONAL); - /* not found and used by parent */ - else if (rom_used_by_parent(options, 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); +//------------------------------------------------- +// audit_one_disk - validate a single disk entry +//------------------------------------------------- - /* just plain old not found */ - else - set_status(record, AUDIT_STATUS_NOT_FOUND, SUBSTATUS_NOT_FOUND); - } +audit_record *media_auditor::audit_one_disk(const rom_entry *rom) +{ + // allocate and append a new record + audit_record &record = m_record_list.append(*global_alloc(audit_record(*rom, audit_record::MEDIA_DISK))); - /* if we did find the file, do additional verification */ - else + // open the disk + emu_file *source_file; + chd_file *source; + chd_error err = open_disk_image(m_enumerator.options(), &m_enumerator.driver(), rom, &source_file, &source, NULL); + + // if we succeeded, get the hashes + if (err == CHDERR_NONE) { - /* length mismatch */ - if (record->explength != record->length) - set_status(record, AUDIT_STATUS_FOUND_INVALID, SUBSTATUS_FOUND_WRONG_LENGTH); - - /* found but needs a dump */ - else if (record->exphashes.flag(hash_collection::FLAG_NO_DUMP)) - set_status(record, AUDIT_STATUS_GOOD, SUBSTATUS_FOUND_NODUMP); - - /* incorrect hash */ - else if (record->exphashes != record->hashes) - set_status(record, AUDIT_STATUS_FOUND_INVALID, SUBSTATUS_FOUND_BAD_CHECKSUM); + static const UINT8 nullhash[20] = { 0 }; + chd_header header = *chd_get_header(source); + hash_collection hashes; - /* correct hash but needs a redump */ - else if (record->exphashes.flag(hash_collection::FLAG_BAD_DUMP)) - set_status(record, AUDIT_STATUS_GOOD, SUBSTATUS_GOOD_NEEDS_REDUMP); + // if there's an MD5 or SHA1 hash, add them to the output hash + if (memcmp(nullhash, header.md5, sizeof(header.md5)) != 0) + hashes.add_from_buffer(hash_collection::HASH_MD5, header.md5, sizeof(header.md5)); + if (memcmp(nullhash, header.sha1, sizeof(header.sha1)) != 0) + hashes.add_from_buffer(hash_collection::HASH_SHA1, header.sha1, sizeof(header.sha1)); + + // update the actual values + record.set_actual(hashes); - /* just plain old good */ - else - set_status(record, AUDIT_STATUS_GOOD, SUBSTATUS_GOOD); + // close the file and release the source + chd_close(source); + global_free(source_file); } + + // compute the final status + compute_status(record, rom, record.actual_length() != 0); + return &record; } -/*------------------------------------------------- - audit_one_disk - validate a single disk entry --------------------------------------------------*/ +//------------------------------------------------- +// compute_status - compute a detailed status +// based on the information we have +//------------------------------------------------- -static void audit_one_disk(emu_options &options, const rom_entry *rom, const game_driver *gamedrv, const char *validation, audit_record *record) +void media_auditor::compute_status(audit_record &record, const rom_entry *rom, bool found) { - emu_file *source_file; - chd_file *source; - chd_error err; - - /* fill in the record basics */ - record->type = AUDIT_FILE_DISK; - record->name = ROM_GETNAME(rom); - record->exphashes.from_internal_string(ROM_GETHASHDATA(rom)); - - /* open the disk */ - err = open_disk_image(options, gamedrv, rom, &source_file, &source, NULL); - - /* if we failed, report the error */ - if (err != CHDERR_NONE) + // if not found, provide more details + if (!found) { - /* out of memory */ - if (err == CHDERR_OUT_OF_MEMORY) - set_status(record, AUDIT_STATUS_ERROR, SUBSTATUS_ERROR); + int parent; + + // no good dump + if (record.expected_hashes().flag(hash_collection::FLAG_NO_DUMP)) + record.set_status(audit_record::STATUS_NOT_FOUND, audit_record::SUBSTATUS_NOT_FOUND_NODUMP); - /* not found but it's not good anyway */ - else if (record->exphashes.flag(hash_collection::FLAG_NO_DUMP)) - set_status(record, AUDIT_STATUS_NOT_FOUND, SUBSTATUS_NOT_FOUND_NODUMP); + // optional ROM + else if (ROM_ISOPTIONAL(rom)) + record.set_status(audit_record::STATUS_NOT_FOUND, audit_record::SUBSTATUS_NOT_FOUND_OPTIONAL); - /* not found but optional */ - else if (DISK_ISOPTIONAL(rom)) - set_status(record, AUDIT_STATUS_NOT_FOUND, SUBSTATUS_NOT_FOUND_OPTIONAL); + // not found and used by parent + else if ((parent = also_used_by_parent(record.expected_hashes())) != -1) + { + if (m_enumerator.driver(parent).flags & GAME_IS_BIOS_ROOT) + record.set_status(audit_record::STATUS_NOT_FOUND, audit_record::SUBSTATUS_NOT_FOUND_BIOS); + else + record.set_status(audit_record::STATUS_NOT_FOUND, audit_record::SUBSTATUS_NOT_FOUND_PARENT); + } - /* not found at all */ + // just plain old not found else - set_status(record, AUDIT_STATUS_NOT_FOUND, SUBSTATUS_NOT_FOUND); + record.set_status(audit_record::STATUS_NOT_FOUND, audit_record::SUBSTATUS_NOT_FOUND); } - - /* if we succeeded, validate it */ + + // if found, provide more details else { - 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) - record->hashes.add_from_buffer(hash_collection::HASH_MD5, header.md5, sizeof(header.md5)); - if (memcmp(nullhash, header.sha1, sizeof(header.sha1)) != 0) - record->hashes.add_from_buffer(hash_collection::HASH_SHA1, header.sha1, sizeof(header.sha1)); + // length mismatch + if (record.expected_length() != record.actual_length()) + record.set_status(audit_record::STATUS_FOUND_INVALID, audit_record::SUBSTATUS_FOUND_WRONG_LENGTH); - /* found but needs a dump */ - if (record->exphashes.flag(hash_collection::FLAG_NO_DUMP)) - set_status(record, AUDIT_STATUS_GOOD, SUBSTATUS_FOUND_NODUMP); + // found but needs a dump + else if (record.expected_hashes().flag(hash_collection::FLAG_NO_DUMP)) + record.set_status(audit_record::STATUS_GOOD, audit_record::SUBSTATUS_FOUND_NODUMP); - /* incorrect hash */ - else if (record->exphashes != record->hashes) - set_status(record, AUDIT_STATUS_FOUND_INVALID, SUBSTATUS_FOUND_BAD_CHECKSUM); + // incorrect hash + else if (record.expected_hashes() != record.actual_hashes()) + record.set_status(audit_record::STATUS_FOUND_INVALID, audit_record::SUBSTATUS_FOUND_BAD_CHECKSUM); - /* correct hash but needs a redump */ - else if (record->exphashes.flag(hash_collection::FLAG_BAD_DUMP)) - set_status(record, AUDIT_STATUS_GOOD, SUBSTATUS_GOOD_NEEDS_REDUMP); + // correct hash but needs a redump + else if (record.expected_hashes().flag(hash_collection::FLAG_BAD_DUMP)) + record.set_status(audit_record::STATUS_GOOD, audit_record::SUBSTATUS_GOOD_NEEDS_REDUMP); - /* just plain good */ + // just plain old good else - set_status(record, AUDIT_STATUS_GOOD, SUBSTATUS_GOOD); - - chd_close(source); - global_free(source_file); + record.set_status(audit_record::STATUS_GOOD, audit_record::SUBSTATUS_GOOD); } } -/*------------------------------------------------- - rom_used_by_parent - determine if a given - ROM is also used by the parent --------------------------------------------------*/ +//------------------------------------------------- +// also_used_by_parent - return the index in the +// enumerator of the parent who also owns a media +// entry with the same hashes +//------------------------------------------------- -static int rom_used_by_parent(emu_options &options, const game_driver *gamedrv, const hash_collection &romhashes, const game_driver **parent) +int media_auditor::also_used_by_parent(const hash_collection &romhashes) { - const game_driver *drv; + // iterate up the parent chain + for (int drvindex = m_enumerator.find(m_enumerator.driver().parent); drvindex != -1; drvindex = m_enumerator.find(m_enumerator.driver(drvindex).parent)) - /* iterate up the parent chain */ - for (drv = driver_get_clone(gamedrv); drv != NULL; drv = driver_get_clone(drv)) - { - machine_config config(*drv, options); - const rom_entry *region; - const rom_entry *rom; - - /* see if the parent has the same ROM or not */ - 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)) + // see if the parent has the same ROM or not + for (const rom_source *source = rom_first_source(m_enumerator.config(drvindex)); source != NULL; source = rom_next_source(*source)) + for (const rom_entry *region = rom_first_region(*source); region; region = rom_next_region(region)) + for (const rom_entry *rom = rom_first_file(region); rom; rom = rom_next_file(rom)) { hash_collection hashes(ROM_GETHASHDATA(rom)); if (!hashes.flag(hash_collection::FLAG_NO_DUMP) && hashes == romhashes) - { - if (parent != NULL) - *parent = drv; - return TRUE; - } + return drvindex; } - } - return FALSE; + // nope, return -1 + return -1; +} + + +//------------------------------------------------- +// audit_record - constructor +//------------------------------------------------- + +audit_record::audit_record(const rom_entry &media, media_type type) + : m_next(NULL), + m_type(type), + m_status(STATUS_ERROR), + m_substatus(SUBSTATUS_ERROR), + m_name(ROM_GETNAME(&media)), + m_explength(rom_file_size(&media)), + m_length(0) +{ + m_exphashes.from_internal_string(ROM_GETHASHDATA(&media)); +} + +audit_record::audit_record(const char *name, media_type type) + : m_next(NULL), + m_type(type), + m_status(STATUS_ERROR), + m_substatus(SUBSTATUS_ERROR), + m_name(name), + m_explength(0), + m_length(0) +{ } |