summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/audit.c
diff options
context:
space:
mode:
author Aaron Giles <aaron@aarongiles.com>2011-04-13 20:31:00 +0000
committer Aaron Giles <aaron@aarongiles.com>2011-04-13 20:31:00 +0000
commit00d745ca7752d2f96e842a7f23e157c0d2c40bdf (patch)
tree9b6a3dcda7d0ff05b098fe0823fe4d09f6d0e6b4 /src/emu/audit.c
parentf99e1a5da63f996cd07fae98d42c2e5ff389adef (diff)
(Big tangle of changes that all happened as I was looking into the ROM
loader rewrite, which is still in progress....) Replaced mamedriv.c with a new driver list mechanism that is generated by the build tools. The emulator core now expects the presence of a file called src/$(TARGET)/$(SUBTARGET).lst which is just a raw list of driver names, one per line. C and C++ comments are still permitted. This file is parsed by a new build tool makelist which extracts the driver names, sorts them, and generates a file called drivlist.c, which is consumed by the core. [Aaron Giles] Added new osdcore function osd_malloc_array() which is identical to osd_malloc() but obviously hints that the underlying allocation is for an array. Updated all callers to use the appropriate form. Modified the Windows allocator to only use guard pages for array-style allocations, allowing us to enable them once again in debug builds. [Aaron Giles] Created new static class driver_list to wrap accesses to the list of available drivers. Improved speed of driver lookups by relying on the presorting done by makelist. [Aaron Giles] Created helper class driver_enumerator as a helper for iterating through the list of drivers. This class supports basic filtering and iteration, and also serves as a temporary cache of machine_configs. [Aaron Giles] Created cli_frontend object to wrap all the CLI handling code in clifront.c. Updated/simplified all the code to take advantage of the driver_enumerator. [Aaron Giles] Created media_auditor object to wrap all the auditing functions in audit.c. Updated all users to the new interface. Note that the new auditing mechanism is slightly out of sync with the romload code in terms of finding ROMs owned by devices, so it may mis-report some issues until the new ROM loading code is in. [Aaron Giles] Added concept of a per-device searchpath. For most devices, their searchpath is just the short name of the device. For driver_devices, the searchpath is driver[;parent[;bios]]. This searchpath will eventually be used by the rom loader to find ROMs. For now it is used by the media auditor only. [Aaron Giles] Created info_xml_creator object to wrap all the info generation functions in info.c. Converted the file to C++ and cleaned up the input processing code. [Aaron Giles] (not for whatsnew ... Known issues: auditing of CHDs appears busted, and debug builds report unfreed memory if you use the built-in game picker)
Diffstat (limited to 'src/emu/audit.c')
-rw-r--r--src/emu/audit.c693
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)
+{
}