diff options
Diffstat (limited to 'src/emu/clifront.c')
-rw-r--r-- | src/emu/clifront.c | 977 |
1 files changed, 977 insertions, 0 deletions
diff --git a/src/emu/clifront.c b/src/emu/clifront.c new file mode 100644 index 00000000000..ad7c39a74d2 --- /dev/null +++ b/src/emu/clifront.c @@ -0,0 +1,977 @@ +/*************************************************************************** + + clifront.c + + Command-line interface frontend for MAME. + + Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team. + Visit http://mamedev.org for licensing and usage restrictions. + +***************************************************************************/ + +#include "driver.h" +#include "emuopts.h" +#include "clifront.h" +#include "hash.h" +#include "jedparse.h" +#include "audit.h" +#include "info.h" +#include "unzip.h" +#include "romload.h" +#include "sound/samples.h" + +#include <ctype.h> + +#ifdef MESS +#include "climess.h" +#endif /* MESS */ + + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +typedef struct _romident_status romident_status; +struct _romident_status +{ + int total; /* total files processed */ + int matches; /* number of matches found */ + int nonroms; /* number of non-ROM files found */ +}; + + + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +static int execute_simple_commands(core_options *options, const char *exename); +static int execute_commands(core_options *options, const char *exename, const game_driver *driver); +static void display_help(void); + +/* informational functions */ +static int info_verifyroms(core_options *options, const char *gamename); +static int info_verifysamples(core_options *options, const char *gamename); +static int info_romident(core_options *options, const char *gamename); + +/* utilities */ +static void romident(const char *filename, romident_status *status); +static void identify_file(const char *name, romident_status *status); +static void identify_data(const char *name, const UINT8 *data, int length, romident_status *status); +static void match_roms(const char *hash, int length, int *found); + + + +/*************************************************************************** + COMMAND-LINE OPTIONS +***************************************************************************/ + +const options_entry cli_options[] = +{ + /* core commands */ + { NULL, NULL, OPTION_HEADER, "CORE COMMANDS" }, + { "help;h;?", "0", OPTION_COMMAND, "show help message" }, + { "validate;valid", "0", OPTION_COMMAND, "perform driver validation on all game drivers" }, + + /* configuration commands */ + { NULL, NULL, OPTION_HEADER, "CONFIGURATION COMMANDS" }, + { "createconfig;cc", "0", OPTION_COMMAND, "create the default configuration file" }, + { "showconfig;sc", "0", OPTION_COMMAND, "display running parameters" }, + { "showusage;su", "0", OPTION_COMMAND, "show this help" }, + + /* frontend commands */ + { NULL, NULL, OPTION_HEADER, "FRONTEND COMMANDS" }, + { "listxml;lx", "0", OPTION_COMMAND, "all available info on driver in XML format" }, + { "listfull;ll", "0", OPTION_COMMAND, "short name, full name" }, + { "listsource;ls", "0", OPTION_COMMAND, "driver sourcefile" }, + { "listclones;lc", "0", OPTION_COMMAND, "show clones" }, + { "listcrc", "0", OPTION_COMMAND, "CRC-32s" }, + { "listroms", "0", OPTION_COMMAND, "list required roms for a driver" }, + { "listsamples", "0", OPTION_COMMAND, "list optional samples for a driver" }, + { "verifyroms", "0", OPTION_COMMAND, "report romsets that have problems" }, + { "verifysamples", "0", OPTION_COMMAND, "report samplesets that have problems" }, + { "romident", "0", OPTION_COMMAND, "compare files with known MAME roms" }, +#ifdef MESS + { "listdevices", "0", OPTION_COMMAND, "list available devices" }, +#endif + + { NULL } +}; + + + +/*************************************************************************** + CORE IMPLEMENTATION +***************************************************************************/ + +/*------------------------------------------------- + cli_execute - execute a game via the standard + command line interface +-------------------------------------------------*/ + +int cli_execute(int argc, char **argv, const options_entry *osd_options) +{ + core_options *options; + astring *gamename = astring_alloc(); + astring *exename = astring_alloc(); + const game_driver *driver; + int result; + + /* initialize the options manager and add the CLI-specific options */ + options = mame_options_init(osd_options); + options_add_entries(options, cli_options); + + /* parse the command line first; if we fail here, we're screwed */ + if (options_parse_command_line(options, argc, argv, OPTION_PRIORITY_CMDLINE)) + { + result = MAMERR_INVALID_CONFIG; + goto error; + } + + /* parse the simple commmands before we go any further */ + core_filename_extract_base(exename, argv[0], TRUE); + result = execute_simple_commands(options, astring_c(exename)); + if (result != -1) + goto error; + + /* find out what game we might be referring to */ + core_filename_extract_base(gamename, options_get_string(options, OPTION_GAMENAME), TRUE); + driver = driver_get_name(astring_c(gamename)); + + /* execute any commands specified */ + result = execute_commands(options, astring_c(exename), driver); + if (result != -1) + goto error; + + /* if we don't have a valid driver selected, offer some suggestions */ + if (astring_len(gamename) > 0 && driver == NULL) + { + const game_driver *matches[10]; + int drvnum; + + /* get the top 10 approximate matches */ + driver_list_get_approx_matches(drivers, astring_c(gamename), ARRAY_LENGTH(matches), matches); + + /* print them out */ + fprintf(stderr, "\n\"%s\" approximately matches the following\n" + "supported " GAMESNOUN " (best match first):\n\n", astring_c(gamename)); + for (drvnum = 0; drvnum < ARRAY_LENGTH(matches); drvnum++) + if (matches[drvnum] != NULL) + fprintf(stderr, "%-10s%s\n", matches[drvnum]->name, matches[drvnum]->description); + + /* exit with an error */ + result = MAMERR_NO_SUCH_GAME; + goto error; + } + + /* run the game */ + result = mame_execute(options); + +error: + /* free our options and exit */ + options_free(options); + astring_free(gamename); + astring_free(exename); + return result; +} + + +/*------------------------------------------------- + help_output - output callback for printing + requested help information +-------------------------------------------------*/ + +static void help_output(const char *s) +{ + mame_printf_info("%s", s); +} + + +/*------------------------------------------------- + execute_simple_commands - execute basic + commands that don't require any context +-------------------------------------------------*/ + +static int execute_simple_commands(core_options *options, const char *exename) +{ + /* help? */ + if (options_get_bool(options, CLIOPTION_HELP)) + { + display_help(); + return MAMERR_NONE; + } + + /* showusage? */ + if (options_get_bool(options, CLIOPTION_SHOWUSAGE)) + { + mame_printf_info("Usage: %s [%s] [options]\n\nOptions:\n", exename, GAMENOUN); + options_output_help(options, help_output); + return MAMERR_NONE; + } + + /* validate? */ + if (options_get_bool(options, CLIOPTION_VALIDATE)) + { + extern int mame_validitychecks(const game_driver *driver); + return mame_validitychecks(NULL); + } + + return -1; +} + + +/*------------------------------------------------- + execute_commands - execute various frontend + commands +-------------------------------------------------*/ + +static int execute_commands(core_options *options, const char *exename, const game_driver *driver) +{ + static const struct + { + const char *option; + int (*function)(core_options *options, const char *gamename); + } info_commands[] = + { + { CLIOPTION_LISTXML, cli_info_listxml }, + { CLIOPTION_LISTFULL, cli_info_listfull }, + { CLIOPTION_LISTSOURCE, cli_info_listsource }, + { CLIOPTION_LISTCLONES, cli_info_listclones }, + { CLIOPTION_LISTCRC, cli_info_listcrc }, +#ifdef MESS + { CLIOPTION_LISTDEVICES, info_listdevices }, +#endif + { CLIOPTION_LISTROMS, cli_info_listroms }, + { CLIOPTION_LISTSAMPLES, cli_info_listsamples }, + { CLIOPTION_VERIFYROMS, info_verifyroms }, + { CLIOPTION_VERIFYSAMPLES, info_verifysamples }, + { CLIOPTION_ROMIDENT, info_romident } + }; + int i; + + /* createconfig? */ + if (options_get_bool(options, CLIOPTION_CREATECONFIG)) + { + file_error filerr; + mame_file *file; + + /* parse any relevant INI files before proceeding */ + mame_parse_ini_files(options, driver); + + /* make the output filename */ + filerr = mame_fopen_options(options, NULL, CONFIGNAME ".ini", OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &file); + + /* error if unable to create the file */ + if (filerr != FILERR_NONE) + { + fprintf(stderr, "Unable to create file " CONFIGNAME ".ini\n"); + return MAMERR_FATALERROR; + } + + /* output the configuration and exit cleanly */ + options_output_ini_file(options, mame_core_file(file)); + mame_fclose(file); + return MAMERR_NONE; + } + + /* showconfig? */ + if (options_get_bool(options, CLIOPTION_SHOWCONFIG)) + { + /* parse any relevant INI files before proceeding */ + mame_parse_ini_files(options, driver); + options_output_ini_stdfile(options, stdout); + return MAMERR_NONE; + } + + /* informational commands? */ + for (i = 0; i < ARRAY_LENGTH(info_commands); i++) + if (options_get_bool(options, info_commands[i].option)) + { + const char *gamename = options_get_string(options, OPTION_GAMENAME); + + /* parse any relevant INI files before proceeding */ + mame_parse_ini_files(options, driver); + return (*info_commands[i].function)(options, (gamename[0] == 0) ? "*" : gamename); + } + + return -1; +} + + +/*------------------------------------------------- + display_help - display help to standard + output +-------------------------------------------------*/ + +static void display_help(void) +{ +#ifndef MESS + mame_printf_info("M.A.M.E. v%s - Multiple Arcade Machine Emulator\n" + "Copyright (C) 1997-2007 by Nicola Salmoria and the MAME Team\n\n", build_version); + mame_printf_info("%s\n", mame_disclaimer); + mame_printf_info("Usage: MAME gamename [options]\n\n" + " MAME -showusage for a brief list of options\n" + " MAME -showconfig for a list of configuration options\n" + " MAME -createconfig to create a " CONFIGNAME ".ini\n\n" + "For usage instructions, please consult the file windows.txt\n"); +#else + mess_display_help(); +#endif +} + + + +/*************************************************************************** + INFORMATIONAL FUNCTIONS +***************************************************************************/ + +/*------------------------------------------------- + cli_info_listxml - output the XML data for one + or more games +-------------------------------------------------*/ + +int cli_info_listxml(core_options *options, const char *gamename) +{ + /* since print_mame_xml expands the machine driver, we need to set things up */ + init_resource_tracking(); + cpuintrf_init(NULL); + sndintrf_init(NULL); + + print_mame_xml(stdout, drivers, gamename); + + /* clean up our tracked resources */ + exit_resource_tracking(); + return MAMERR_NONE; +} + + +/*------------------------------------------------- + cli_info_listfull - output the name and description + of one or more games +-------------------------------------------------*/ + +int cli_info_listfull(core_options *options, const char *gamename) +{ + int drvindex, count = 0; + + /* iterate over drivers */ + for (drvindex = 0; drivers[drvindex]; drvindex++) + if ((drivers[drvindex]->flags & GAME_NO_STANDALONE) == 0 && mame_strwildcmp(gamename, drivers[drvindex]->name) == 0) + { + /* print the header on the first one */ + if (count == 0) + mame_printf_info("Name: Description:\n"); + + /* output the remaining information */ + mame_printf_info("%-10s\"%s\"\n", drivers[drvindex]->name, drivers[drvindex]->description); + count++; + } + + /* return an error if none found */ + return (count > 0) ? MAMERR_NONE : MAMERR_NO_SUCH_GAME; +} + + +/*------------------------------------------------- + cli_info_listsource - output the name and source + filename of one or more games +-------------------------------------------------*/ + +int cli_info_listsource(core_options *options, const char *gamename) +{ + astring *filename = astring_alloc(); + int drvindex, count = 0; + + /* iterate over drivers */ + for (drvindex = 0; drivers[drvindex]; drvindex++) + if (mame_strwildcmp(gamename, drivers[drvindex]->name) == 0) + { + /* output the remaining information */ + mame_printf_info("%-8s %s\n", drivers[drvindex]->name, astring_c(core_filename_extract_base(filename, drivers[drvindex]->source_file, FALSE))); + count++; + } + + /* return an error if none found */ + astring_free(filename); + return (count > 0) ? MAMERR_NONE : MAMERR_NO_SUCH_GAME; +} + + +/*------------------------------------------------- + cli_info_listclones - output the name and source + filename of one or more games +-------------------------------------------------*/ + +int cli_info_listclones(core_options *options, const char *gamename) +{ + int drvindex, count = 0; + + /* iterate over drivers */ + for (drvindex = 0; drivers[drvindex]; drvindex++) + { + const game_driver *clone_of = driver_get_clone(drivers[drvindex]); + + /* if we are a clone, and either our name matches the gamename, or the clone's name matches, display us */ + if (clone_of != NULL && (clone_of->flags & GAME_IS_BIOS_ROOT) == 0) + if (mame_strwildcmp(gamename, drivers[drvindex]->name) == 0 || mame_strwildcmp(gamename, clone_of->name) == 0) + { + /* print the header on the first one */ + if (count == 0) + mame_printf_info("Name: Clone of:\n"); + + /* output the remaining information */ + mame_printf_info("%-8s %-8s\n", drivers[drvindex]->name, clone_of->name); + count++; + } + } + + /* return an error if none found */ + return (count > 0) ? MAMERR_NONE : MAMERR_NO_SUCH_GAME; +} + + +/*------------------------------------------------- + cli_info_listcrc - output the CRC and name of + all ROMs referenced by MAME +-------------------------------------------------*/ + +int cli_info_listcrc(core_options *options, const char *gamename) +{ + int drvindex, count = 0; + + /* iterate over drivers */ + for (drvindex = 0; drivers[drvindex]; drvindex++) + if (mame_strwildcmp(gamename, drivers[drvindex]->name) == 0) + { + const rom_entry *region, *rom; + + /* iterate over regions, and then ROMs within the region */ + for (region = rom_first_region(drivers[drvindex]); 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); + } + + count++; + } + + /* return an error if none found */ + return (count > 0) ? MAMERR_NONE : MAMERR_NO_SUCH_GAME; +} + + +/*------------------------------------------------- + cli_info_listroms - output the list of ROMs + referenced by a given game or set of games +-------------------------------------------------*/ + +int cli_info_listroms(core_options *options, const char *gamename) +{ + int drvindex, count = 0; + + /* iterate over drivers */ + for (drvindex = 0; drivers[drvindex]; drvindex++) + if (mame_strwildcmp(gamename, drivers[drvindex]->name) == 0) + { + const rom_entry *region, *rom, *chunk; + + /* print the header */ + if (count > 0) + mame_printf_info("\n"); + mame_printf_info("This is the list of the ROMs required for driver \"%s\".\n" + "Name Size Checksum\n", drivers[drvindex]->name); + + /* iterate over regions and then ROMs within the region */ + for (region = drivers[drvindex]->rom; region; region = rom_next_region(region)) + for (rom = rom_first_file(region); rom; 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 */ + if (ROMREGION_ISROMDATA(region)) + { + length = 0; + for (chunk = rom_first_chunk(rom); chunk; chunk = rom_next_chunk(chunk)) + length += ROM_GETLENGTH(chunk); + } + + /* start with the name */ + mame_printf_info("%-12s ", name); + + /* output the length next */ + if (length >= 0) + mame_printf_info("%7d", length); + else + mame_printf_info(" "); + + /* output the hash data */ + if (!hash_data_has_info(hash, HASH_INFO_NO_DUMP)) + { + if (hash_data_has_info(hash, HASH_INFO_BAD_DUMP)) + mame_printf_info(" BAD"); + + hash_data_print(hash, 0, hashbuf); + mame_printf_info(" %s", hashbuf); + } + else + mame_printf_info(" NO GOOD DUMP KNOWN"); + + /* end with a CR */ + mame_printf_info("\n"); + } + + count++; + } + + return (count > 0) ? MAMERR_NONE : MAMERR_NO_SUCH_GAME; +} + + +/*------------------------------------------------- + cli_info_listsamples - output the list of samples + referenced by a given game or set of games +-------------------------------------------------*/ + +int cli_info_listsamples(core_options *options, const char *gamename) +{ + int count = 0; + +#if (HAS_SAMPLES) + int drvindex; + + /* since we expand the machine driver, we need to set things up */ + init_resource_tracking(); + cpuintrf_init(NULL); + sndintrf_init(NULL); + + /* iterate over drivers */ + for (drvindex = 0; drivers[drvindex]; drvindex++) + if (mame_strwildcmp(gamename, drivers[drvindex]->name) == 0) + { + machine_config drv; + int sndnum; + + /* expand the machine driver */ + expand_machine_driver(drivers[drvindex]->drv, &drv); + + /* find samples interfaces */ + for (sndnum = 0; sndnum < MAX_SOUND && drv.sound[sndnum].type != SOUND_DUMMY; sndnum++) + if (drv.sound[sndnum].type == SOUND_SAMPLES) + { + const char **samplenames = ((struct Samplesinterface *)drv.sound[sndnum].config)->samplenames; + int sampnum; + + /* if the list is legit, walk it and print the sample info */ + if (samplenames != NULL) + for (sampnum = 0; samplenames[sampnum] != NULL; sampnum++) + mame_printf_info("%s\n", samplenames[sampnum]); + } + + count++; + } + + /* clean up our tracked resources */ + exit_resource_tracking(); +#else + mame_printf_error("Samples not supported in this build\n"); +#endif + + return (count > 0) ? MAMERR_NONE : MAMERR_NO_SUCH_GAME; +} + + +/*------------------------------------------------- + info_verifyroms - verify the ROM sets of + one or more games +-------------------------------------------------*/ + +static int info_verifyroms(core_options *options, const char *gamename) +{ + int correct = 0; + int incorrect = 0; + int notfound = 0; + int drvindex; + + /* iterate over drivers */ + for (drvindex = 0; drivers[drvindex]; drvindex++) + if (mame_strwildcmp(gamename, drivers[drvindex]->name) == 0) + { + audit_record *audit; + int audit_records; + int res; + + /* audit the ROMs in this set */ + audit_records = audit_images(options, drivers[drvindex], AUDIT_VALIDATE_FAST, &audit); + res = audit_summary(drivers[drvindex], audit_records, audit, TRUE); + if (audit_records > 0) + free(audit); + + /* if not found, count that and leave it at that */ + if (res == NOTFOUND) + notfound++; + + /* else display information about what we discovered */ + else + { + const game_driver *clone_of; + + /* output the name of the driver and its clone */ + mame_printf_info("romset %s ", drivers[drvindex]->name); + clone_of = driver_get_clone(drivers[drvindex]); + if (clone_of != NULL) + mame_printf_info("[%s] ", clone_of->name); + + /* switch off of the result */ + switch (res) + { + case INCORRECT: + mame_printf_info("is bad\n"); + incorrect++; + break; + + case CORRECT: + mame_printf_info("is good\n"); + correct++; + break; + + case BEST_AVAILABLE: + mame_printf_info("is best available\n"); + correct++; + break; + } + } + } + + /* clear out any cached files */ + zip_file_cache_clear(); + + /* if we didn't get anything at all, display a generic end message */ + if (correct + incorrect == 0) + { + if (notfound > 0) + mame_printf_info("romset \"%s\" not found!\n", gamename); + else + mame_printf_info("romset \"%s\" not supported!\n", gamename); + return MAMERR_NO_SUCH_GAME; + } + + /* otherwise, print a summary */ + else + { + mame_printf_info("%d romsets found, %d were OK.\n", correct + incorrect, correct); + return (incorrect > 0) ? MAMERR_MISSING_FILES : MAMERR_NONE; + } +} + + +/*------------------------------------------------- + info_verifysamples - verify the sample sets of + one or more games +-------------------------------------------------*/ + +static int info_verifysamples(core_options *options, const char *gamename) +{ + int correct = 0; + int incorrect = 0; + int notfound = 0; + int drvindex; + + /* now iterate over drivers */ + for (drvindex = 0; drivers[drvindex]; drvindex++) + if (mame_strwildcmp(gamename, drivers[drvindex]->name) == 0) + { + audit_record *audit; + int audit_records; + int res; + + /* audit the samples in this set */ + audit_records = audit_samples(options, drivers[drvindex], &audit); + res = audit_summary(drivers[drvindex], audit_records, audit, TRUE); + if (audit_records > 0) + free(audit); + else + continue; + + /* if not found, count that and leave it at that */ + if (res == NOTFOUND) + notfound++; + + /* else display information about what we discovered */ + else + { + mame_printf_info("sampleset %s ", drivers[drvindex]->name); + + /* switch off of the result */ + switch (res) + { + case INCORRECT: + mame_printf_info("is bad\n"); + incorrect++; + break; + + case CORRECT: + mame_printf_info("is good\n"); + correct++; + break; + + case BEST_AVAILABLE: + mame_printf_info("is best available\n"); + correct++; + break; + } + } + } + + /* if we didn't get anything at all, display a generic end message */ + if (correct + incorrect == 0) + { + if (notfound > 0) + mame_printf_error("sampleset \"%s\" not found!\n", gamename); + else + mame_printf_error("sampleset \"%s\" not supported!\n", gamename); + return MAMERR_NO_SUCH_GAME; + } + + /* otherwise, print a summary */ + else + { + mame_printf_info("%d samplesets found, %d were OK.\n", correct + incorrect, correct); + return (incorrect > 0) ? MAMERR_MISSING_FILES : MAMERR_NONE; + } +} + + +/*------------------------------------------------- + info_romident - identify ROMs by looking for + matches in our internal database +-------------------------------------------------*/ + +static int info_romident(core_options *options, const char *gamename) +{ + romident_status status; + + /* a NULL gamename is a fatal error */ + if (gamename == NULL) + return MAMERR_FATALERROR; + + /* do the identification */ + romident(gamename, &status); + + /* clear out any cached files */ + zip_file_cache_clear(); + + /* return the appropriate error code */ + if (status.matches == status.total) + return MAMERR_NONE; + else if (status.matches == status.total - status.nonroms) + return MAMERR_IDENT_NONROMS; + else if (status.matches > 0) + return MAMERR_IDENT_PARTIAL; + else + return MAMERR_IDENT_NONE; +} + + + +/*************************************************************************** + UTILITIES +***************************************************************************/ + +/*------------------------------------------------- + romident - identify files +-------------------------------------------------*/ + +static void romident(const char *filename, romident_status *status) +{ + osd_directory *directory; + + /* reset the status */ + memset(status, 0, sizeof(*status)); + + /* first try to open as a directory */ + directory = osd_opendir(filename); + if (directory != NULL) + { + const osd_directory_entry *entry; + + /* iterate over all files in the directory */ + while ((entry = osd_readdir(directory)) != NULL) + if (entry->type == ENTTYPE_FILE) + { + astring *curfile = astring_assemble_3(astring_alloc(), filename, PATH_SEPARATOR, entry->name); + identify_file(astring_c(curfile), status); + astring_free(curfile); + } + osd_closedir(directory); + } + + /* if that failed, and the filename ends with .zip, identify as a ZIP file */ + else if (core_filename_ends_with(filename, ".zip")) + { + /* first attempt to examine it as a valid ZIP file */ + zip_file *zip = NULL; + zip_error ziperr = zip_file_open(filename, &zip); + if (ziperr == ZIPERR_NONE && zip != NULL) + { + const zip_file_header *entry; + + /* loop over entries in the ZIP, skipping empty files and directories */ + for (entry = zip_file_first_file(zip); entry; entry = zip_file_next_file(zip)) + if (entry->uncompressed_length != 0) + { + UINT8 *data = (UINT8 *)malloc(entry->uncompressed_length); + if (data != NULL) + { + /* decompress data into RAM and identify it */ + ziperr = zip_file_decompress(zip, data, entry->uncompressed_length); + if (ziperr == ZIPERR_NONE) + identify_data(entry->filename, data, entry->uncompressed_length, status); + free(data); + } + } + + /* close up */ + zip_file_close(zip); + } + } + + /* otherwise, identify as a raw file */ + else + identify_file(filename, status); +} + + +/*------------------------------------------------- + identify_file - identify a file; if it is a + ZIP file, scan it and identify all enclosed + files +-------------------------------------------------*/ + +static void identify_file(const char *name, romident_status *status) +{ + file_error filerr; + osd_file *file; + UINT64 length; + + /* open for read and process if it opens and has a valid length */ + filerr = osd_open(name, OPEN_FLAG_READ, &file, &length); + if (filerr == FILERR_NONE && length > 0 && (UINT32)length == length) + { + UINT8 *data = (UINT8 *)malloc(length); + if (data != NULL) + { + UINT32 bytes; + + /* read file data into RAM and identify it */ + filerr = osd_read(file, data, 0, length, &bytes); + if (filerr == FILERR_NONE) + identify_data(name, data, bytes, status); + free(data); + } + osd_close(file); + } +} + + +/*------------------------------------------------- + identify_data - identify a buffer full of + data; if it comes from a .JED file, parse the + fusemap into raw data first +-------------------------------------------------*/ + +static void identify_data(const char *name, const UINT8 *data, int length, romident_status *status) +{ + char hash[HASH_BUF_SIZE]; + UINT8 *tempjed = NULL; + astring *basename; + int found = 0; + jed_data jed; + + /* if this is a '.jed' file, process it into raw bits first */ + if (core_filename_ends_with(name, ".jed") && jed_parse(data, length, &jed) == JEDERR_NONE) + { + /* now determine the new data length and allocate temporary memory for it */ + length = jedbin_output(&jed, NULL, 0); + tempjed = malloc(length); + if (tempjed == NULL) + return; + + /* create a binary output of the JED data and use that instead */ + jedbin_output(&jed, tempjed, length); + data = tempjed; + } + + /* compute the hash of the data */ + hash_data_clear(hash); + hash_compute(hash, data, length, HASH_SHA1 | HASH_CRC); + + /* output the name */ + status->total++; + basename = core_filename_extract_base(astring_alloc(), name, FALSE); + mame_printf_info("%-20s", astring_c(basename)); + astring_free(basename); + + /* see if we can find a match in the ROMs */ + match_roms(hash, length, &found); + + /* if we didn't find it, try to guess what it might be */ + if (found == 0) + { + /* if not a power of 2, assume it is a non-ROM file */ + if ((length & (length - 1)) != 0) + { + mame_printf_info("NOT A ROM\n"); + status->nonroms++; + } + + /* otherwise, it's just not a match */ + else + mame_printf_info("NO MATCH\n"); + } + + /* if we did find it, count it as a match */ + else + status->matches++; + + /* free any temporary JED data */ + if (tempjed != NULL) + free(tempjed); +} + + +/*------------------------------------------------- + match_roms - scan for a matching ROM by hash +-------------------------------------------------*/ + +static void match_roms(const char *hash, int length, int *found) +{ + int drvindex; + + /* iterate over drivers */ + for (drvindex = 0; drivers[drvindex]; drvindex++) + { + const rom_entry *region, *rom; + + /* iterate over regions and files within the region */ + for (region = rom_first_region(drivers[drvindex]); 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)) + { + int baddump = hash_data_has_info(ROM_GETHASHDATA(rom), HASH_INFO_BAD_DUMP); + + /* output information about the match */ + if (*found != 0) + mame_printf_info(" "); + mame_printf_info("= %s%-20s %s\n", baddump ? "(BAD) " : "", ROM_GETNAME(rom), drivers[drvindex]->description); + (*found)++; + } + } +} |