/***************************************************************************
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)++;
}
}
}