mirror of
https://github.com/holub/mame
synced 2025-05-19 12:18:56 +03:00
1559 lines
50 KiB
C
1559 lines
50 KiB
C
/***************************************************************************
|
|
|
|
clifront.c
|
|
|
|
Command-line interface frontend for MAME.
|
|
|
|
Copyright Nicola Salmoria and the MAME Team.
|
|
Visit http://mamedev.org for licensing and usage restrictions.
|
|
|
|
***************************************************************************/
|
|
|
|
#include "emu.h"
|
|
#include "emuopts.h"
|
|
#include "hash.h"
|
|
#include "jedparse.h"
|
|
#include "audit.h"
|
|
#include "info.h"
|
|
#include "unzip.h"
|
|
#include "validity.h"
|
|
#include "sound/samples.h"
|
|
#include "clifront.h"
|
|
#include "xmlfile.h"
|
|
|
|
#include <new>
|
|
#include <ctype.h>
|
|
#ifdef MESS
|
|
#include "mess.h"
|
|
#endif
|
|
|
|
|
|
/***************************************************************************
|
|
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);
|
|
static int info_listmedia(core_options *opts, const char *gamename);
|
|
static int info_listsoftware(core_options *options, const char *gamename);
|
|
|
|
/* utilities */
|
|
static void romident(core_options *options, const char *filename, romident_status *status);
|
|
static void identify_file(core_options *options, const char *name, romident_status *status);
|
|
static void identify_data(core_options *options, const char *name, const UINT8 *data, int length, romident_status *status);
|
|
static void match_roms(core_options *options, const char *hash, int length, int *found);
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
COMMAND-LINE OPTIONS
|
|
***************************************************************************/
|
|
|
|
static 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" },
|
|
{ "listbrothers;lb", "0", OPTION_COMMAND, "show \"brothers\", or other drivers from same sourcefile" },
|
|
{ "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" },
|
|
{ "listdevices;ld", "0", OPTION_COMMAND, "list available devices" },
|
|
{ "listmedia;lm", "0", OPTION_COMMAND, "list available media for the system" },
|
|
{ "listsoftware;lsoft", "0", OPTION_COMMAND, "list known software for the system" },
|
|
|
|
{ NULL }
|
|
};
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
CORE IMPLEMENTATION
|
|
***************************************************************************/
|
|
|
|
/*-------------------------------------------------
|
|
cli_execute - execute a game via the standard
|
|
command line interface
|
|
-------------------------------------------------*/
|
|
|
|
int cli_execute(int argc, char **argv, osd_interface &osd, const options_entry *osd_options)
|
|
{
|
|
core_options *options = NULL;
|
|
const char *gamename_option;
|
|
const game_driver *driver;
|
|
int result = MAMERR_FATALERROR;
|
|
astring gamename;
|
|
astring exename;
|
|
|
|
try
|
|
{
|
|
/* initialize the options manager and add the CLI-specific options */
|
|
options = mame_options_init(osd_options);
|
|
options_add_entries(options, cli_options);
|
|
|
|
gamename_option = "";
|
|
for (int arg = 1; arg < argc; arg++)
|
|
{
|
|
if ((argv[arg][0] != '-')) {
|
|
gamename_option = argv[arg];
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* find out what game we might be referring to */
|
|
core_filename_extract_base(&gamename, gamename_option, TRUE);
|
|
driver = driver_get_name(gamename);
|
|
|
|
/* if we don't have a valid driver selected, offer some suggestions */
|
|
if (strlen(gamename_option) > 0 && driver == NULL)
|
|
{
|
|
const game_driver *matches[10];
|
|
int drvnum;
|
|
|
|
/* get the top 10 approximate matches */
|
|
driver_list_get_approx_matches(drivers, gamename_option, ARRAY_LENGTH(matches), matches);
|
|
|
|
/* print them out */
|
|
fprintf(stderr, "\n\"%s\" approximately matches the following\n"
|
|
"supported " GAMESNOUN " (best match first):\n\n", gamename_option);
|
|
for (drvnum = 0; drvnum < ARRAY_LENGTH(matches); drvnum++)
|
|
if (matches[drvnum] != NULL)
|
|
fprintf(stderr, "%-18s%s\n", matches[drvnum]->name, matches[drvnum]->description);
|
|
|
|
/* exit with an error */
|
|
result = MAMERR_NO_SUCH_GAME;
|
|
goto error;
|
|
}
|
|
|
|
/* 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, exename);
|
|
if (result != -1)
|
|
goto error;
|
|
|
|
/* execute any commands specified */
|
|
result = execute_commands(options, exename, driver);
|
|
if (result != -1)
|
|
goto error;
|
|
|
|
/* run the game */
|
|
result = mame_execute(osd, options);
|
|
}
|
|
catch (emu_fatalerror &fatal)
|
|
{
|
|
fprintf(stderr, "%s\n", fatal.string());
|
|
if (fatal.exitcode() != 0)
|
|
result = fatal.exitcode();
|
|
}
|
|
catch (emu_exception &)
|
|
{
|
|
fprintf(stderr, "Caught unhandled emulator exception\n");
|
|
}
|
|
catch (std::bad_alloc &)
|
|
{
|
|
fprintf(stderr, "Out of memory!\n");
|
|
}
|
|
catch (...)
|
|
{
|
|
fprintf(stderr, "Caught unhandled exception\n");
|
|
}
|
|
|
|
error:
|
|
/* free our options and exit */
|
|
if (options != NULL)
|
|
options_free(options);
|
|
|
|
/* report any unfreed memory */
|
|
dump_unfreed_mem();
|
|
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))
|
|
{
|
|
set_mame_options(options);
|
|
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_LISTBROTHERS, cli_info_listbrothers },
|
|
{ CLIOPTION_LISTCRC, cli_info_listcrc },
|
|
{ CLIOPTION_LISTDEVICES, cli_info_listdevices },
|
|
{ CLIOPTION_LISTROMS, cli_info_listroms },
|
|
{ CLIOPTION_LISTSAMPLES, cli_info_listsamples },
|
|
{ CLIOPTION_VERIFYROMS, info_verifyroms },
|
|
{ CLIOPTION_VERIFYSAMPLES, info_verifysamples },
|
|
{ CLIOPTION_LISTMEDIA, info_listmedia },
|
|
{ CLIOPTION_LISTSOFTWARE, info_listsoftware },
|
|
{ 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 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)
|
|
{
|
|
print_mame_xml(stdout, drivers, gamename);
|
|
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] != NULL; 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("%-18s\"%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)
|
|
{
|
|
int drvindex, count = 0;
|
|
astring filename;
|
|
|
|
/* iterate over drivers */
|
|
for (drvindex = 0; drivers[drvindex] != NULL; drvindex++)
|
|
if (mame_strwildcmp(gamename, drivers[drvindex]->name) == 0)
|
|
{
|
|
/* output the remaining information */
|
|
mame_printf_info("%-16s %s\n", drivers[drvindex]->name, core_filename_extract_base(&filename, drivers[drvindex]->source_file, FALSE)->cstr());
|
|
count++;
|
|
}
|
|
|
|
/* return an error if none found */
|
|
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] != NULL; 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("%-16s %-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_listbrothers - output the name and
|
|
source filename of one or more games
|
|
-------------------------------------------------*/
|
|
|
|
int cli_info_listbrothers(core_options *options, const char *gamename)
|
|
{
|
|
UINT8 *didit = global_alloc_array_clear(UINT8, driver_list_get_count(drivers));
|
|
int drvindex, count = 0;
|
|
astring filename;
|
|
|
|
/* iterate over drivers */
|
|
for (drvindex = 0; drivers[drvindex] != NULL; drvindex++)
|
|
if (!didit[drvindex] && mame_strwildcmp(gamename, drivers[drvindex]->name) == 0)
|
|
{
|
|
int matchindex;
|
|
|
|
didit[drvindex] = TRUE;
|
|
if (count > 0)
|
|
mame_printf_info("\n");
|
|
mame_printf_info("%s ... other drivers in %s:\n", drivers[drvindex]->name, core_filename_extract_base(&filename, drivers[drvindex]->source_file, FALSE)->cstr());
|
|
|
|
/* now iterate again over drivers, finding those with the same source file */
|
|
for (matchindex = 0; drivers[matchindex]; matchindex++)
|
|
if (matchindex != drvindex && strcmp(drivers[drvindex]->source_file, drivers[matchindex]->source_file) == 0)
|
|
{
|
|
const char *matchstring = (mame_strwildcmp(gamename, drivers[matchindex]->name) == 0) ? "-> " : " ";
|
|
const game_driver *clone_of = driver_get_clone(drivers[matchindex]);
|
|
|
|
if (clone_of != NULL && (clone_of->flags & GAME_IS_BIOS_ROOT) == 0)
|
|
mame_printf_info("%s%-16s [%s]\n", matchstring, drivers[matchindex]->name, clone_of->name);
|
|
else
|
|
mame_printf_info("%s%s\n", matchstring, drivers[matchindex]->name);
|
|
didit[matchindex] = TRUE;
|
|
}
|
|
|
|
count++;
|
|
}
|
|
|
|
/* return an error if none found */
|
|
global_free(didit);
|
|
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] != NULL; drvindex++)
|
|
if (mame_strwildcmp(gamename, drivers[drvindex]->name) == 0)
|
|
{
|
|
machine_config config(*drivers[drvindex]);
|
|
const rom_entry *region, *rom;
|
|
const rom_source *source;
|
|
|
|
/* iterate over sources, regions, and then ROMs within the region */
|
|
for (source = rom_first_source(config); source != NULL; source = rom_next_source(*source))
|
|
for (region = rom_first_region(*source); region; 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] != NULL; drvindex++)
|
|
if (mame_strwildcmp(gamename, drivers[drvindex]->name) == 0)
|
|
{
|
|
machine_config config(*drivers[drvindex]);
|
|
const rom_entry *region, *rom;
|
|
const rom_source *source;
|
|
|
|
/* print the header */
|
|
if (count > 0)
|
|
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 sources, regions and then ROMs within the region */
|
|
for (source = rom_first_source(config); source != NULL; source = rom_next_source(*source))
|
|
for (region = rom_first_region(*source); region != NULL; region = rom_next_region(region))
|
|
for (rom = rom_first_file(region); rom != NULL; rom = rom_next_file(rom))
|
|
{
|
|
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 = rom_file_size(rom);
|
|
|
|
/* 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;
|
|
int drvindex;
|
|
|
|
/* iterate over drivers */
|
|
for (drvindex = 0; drivers[drvindex] != NULL; drvindex++)
|
|
if (mame_strwildcmp(gamename, drivers[drvindex]->name) == 0)
|
|
{
|
|
machine_config config(*drivers[drvindex]);
|
|
const device_config_sound_interface *sound = NULL;
|
|
|
|
/* find samples interfaces */
|
|
for (bool gotone = config.m_devicelist.first(sound); gotone; gotone = sound->next(sound))
|
|
if (sound->devconfig().type() == SAMPLES)
|
|
{
|
|
const char *const *samplenames = ((const samples_interface *)sound->devconfig().static_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++;
|
|
}
|
|
|
|
return (count > 0) ? MAMERR_NONE : MAMERR_NO_SUCH_GAME;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
cli_info_listdevices - output the list of
|
|
devices referenced by a given game or set of
|
|
games
|
|
-------------------------------------------------*/
|
|
|
|
int cli_info_listdevices(core_options *options, const char *gamename)
|
|
{
|
|
int count = 0;
|
|
int drvindex;
|
|
|
|
/* iterate over drivers */
|
|
for (drvindex = 0; drivers[drvindex] != NULL; drvindex++)
|
|
if (mame_strwildcmp(gamename, drivers[drvindex]->name) == 0)
|
|
{
|
|
machine_config config(*drivers[drvindex]);
|
|
const device_config *devconfig;
|
|
|
|
if (count != 0)
|
|
printf("\n");
|
|
printf("Driver %s (%s):\n", drivers[drvindex]->name, drivers[drvindex]->description);
|
|
|
|
/* iterate through devices */
|
|
for (devconfig = config.m_devicelist.first(); devconfig != NULL; devconfig = devconfig->next())
|
|
{
|
|
printf(" %s ('%s')", devconfig->name(), devconfig->tag());
|
|
|
|
UINT32 clock = devconfig->clock();
|
|
if (clock >= 1000000000)
|
|
printf(" @ %d.%02d GHz\n", clock / 1000000000, (clock / 10000000) % 100);
|
|
else if (clock >= 1000000)
|
|
printf(" @ %d.%02d MHz\n", clock / 1000000, (clock / 10000) % 100);
|
|
else if (clock >= 1000)
|
|
printf(" @ %d.%02d kHz\n", clock / 1000, (clock / 10) % 100);
|
|
else if (clock > 0)
|
|
printf(" @ %d Hz\n", clock);
|
|
else
|
|
printf("\n");
|
|
}
|
|
|
|
count++;
|
|
}
|
|
|
|
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] != NULL; 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)
|
|
global_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_listsoftware - output the list of
|
|
software supported by a given game or set of
|
|
games
|
|
TODO: Add all information read from the source files
|
|
Possible improvement: use a sorted list for
|
|
identifying duplicate lists.
|
|
-------------------------------------------------*/
|
|
|
|
static int info_listsoftware(core_options *options, const char *gamename)
|
|
{
|
|
FILE *out = stdout;
|
|
int nr_lists = 0;
|
|
char ** lists = NULL;
|
|
int list_idx = 0;
|
|
|
|
/* First determine the maximum number of lists we might encounter */
|
|
for ( int drvindex = 0; drivers[drvindex] != NULL; drvindex++ )
|
|
{
|
|
if ( mame_strwildcmp( gamename, drivers[drvindex]->name ) == 0 )
|
|
{
|
|
/* allocate the machine config */
|
|
machine_config config(*drivers[drvindex]);
|
|
|
|
for (const device_config *dev = config.m_devicelist.first(SOFTWARE_LIST); dev != NULL; dev = dev->typenext())
|
|
{
|
|
software_list_config *swlist = (software_list_config *)downcast<const legacy_device_config_base *>(dev)->inline_config();
|
|
|
|
for ( int i = 0; i < DEVINFO_STR_SWLIST_MAX - DEVINFO_STR_SWLIST_0; i++ )
|
|
{
|
|
if ( swlist->list_name[i] && *swlist->list_name[i] && (swlist->list_type == SOFTWARE_LIST_ORIGINAL_SYSTEM))
|
|
nr_lists++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
lists = global_alloc_array( char *, nr_lists );
|
|
|
|
if (nr_lists)
|
|
{
|
|
fprintf( out,
|
|
"<?xml version=\"1.0\"?>\n"
|
|
"<!DOCTYPE softwarelist [\n"
|
|
"<!ELEMENT softwarelists (softwarelist*)>\n"
|
|
"\t<!ELEMENT softwarelist (software+)>\n"
|
|
"\t\t<!ATTLIST softwarelist name CDATA #REQUIRED>\n"
|
|
"\t\t<!ATTLIST softwarelist description CDATA #IMPLIED>\n"
|
|
"\t\t<!ELEMENT software (description, year?, publisher, part*)>\n"
|
|
"\t\t\t<!ATTLIST software name CDATA #REQUIRED>\n"
|
|
"\t\t\t<!ATTLIST software cloneof CDATA #IMPLIED>\n"
|
|
"\t\t\t<!ATTLIST software supported (yes|partial|no) \"yes\">\n"
|
|
"\t\t\t<!ELEMENT description (#PCDATA)>\n"
|
|
"\t\t\t<!ELEMENT year (#PCDATA)>\n"
|
|
"\t\t\t<!ELEMENT publisher (#PCDATA)>\n"
|
|
"\t\t\t<!ELEMENT part (feature*, dataarea*, diskarea*, dipswitch*)>\n"
|
|
"\t\t\t\t<!ATTLIST part name CDATA #REQUIRED>\n"
|
|
"\t\t\t\t<!ATTLIST part interface CDATA #REQUIRED>\n"
|
|
"\t\t\t\t<!ELEMENT feature EMPTY>\n"
|
|
"\t\t\t\t\t<!ATTLIST feature name CDATA #REQUIRED>\n"
|
|
"\t\t\t\t\t<!ATTLIST feature value CDATA #IMPLIED>\n"
|
|
"\t\t\t\t<!ELEMENT dataarea (rom*)>\n"
|
|
"\t\t\t\t\t<!ATTLIST dataarea name CDATA #REQUIRED>\n"
|
|
"\t\t\t\t\t<!ATTLIST dataarea size CDATA #REQUIRED>\n"
|
|
"\t\t\t\t\t<!ATTLIST dataarea databits (8|16|32|64) \"8\">\n"
|
|
"\t\t\t\t\t<!ATTLIST dataarea endian (big|little) \"little\">\n"
|
|
"\t\t\t\t\t<!ELEMENT rom EMPTY>\n"
|
|
"\t\t\t\t\t\t<!ATTLIST rom name CDATA #IMPLIED>\n"
|
|
"\t\t\t\t\t\t<!ATTLIST rom size CDATA #REQUIRED>\n"
|
|
"\t\t\t\t\t\t<!ATTLIST rom crc CDATA #IMPLIED>\n"
|
|
"\t\t\t\t\t\t<!ATTLIST rom md5 CDATA #IMPLIED>\n"
|
|
"\t\t\t\t\t\t<!ATTLIST rom sha1 CDATA #IMPLIED>\n"
|
|
"\t\t\t\t\t\t<!ATTLIST rom offset CDATA #IMPLIED>\n"
|
|
"\t\t\t\t\t\t<!ATTLIST rom value CDATA #IMPLIED>\n"
|
|
"\t\t\t\t\t\t<!ATTLIST rom status (baddump|nodump|good) \"good\">\n"
|
|
"\t\t\t\t\t\t<!ATTLIST rom loadflag (load16_byte|load16_word|load16_word_swap|load32_byte|load32_word|load32_word_swap|load32_dword|load64_word|load64_word_swap|reload|fill|continue) #IMPLIED>\n"
|
|
"\t\t\t\t<!ELEMENT diskarea (disk*)>\n"
|
|
"\t\t\t\t\t<!ATTLIST diskarea name CDATA #REQUIRED>\n"
|
|
"\t\t\t\t\t<!ELEMENT disk EMPTY>\n"
|
|
"\t\t\t\t\t\t<!ATTLIST disk name CDATA #REQUIRED>\n"
|
|
"\t\t\t\t\t\t<!ATTLIST disk md5 CDATA #IMPLIED>\n"
|
|
"\t\t\t\t\t\t<!ATTLIST disk sha1 CDATA #IMPLIED>\n"
|
|
"\t\t\t\t\t\t<!ATTLIST disk status (baddump|nodump|good) \"good\">\n"
|
|
"\t\t\t\t\t\t<!ATTLIST disk writeable (yes|no) \"no\">\n"
|
|
// we still do not store the dipswitch values in softlist, so there is no output here
|
|
// TODO: add parsing dipsw in softlist.c and then add output here!
|
|
"\t\t\t\t<!ELEMENT dipswitch (dipvalue*)>\n"
|
|
"\t\t\t\t\t<!ATTLIST dipswitch name CDATA #REQUIRED>\n"
|
|
"\t\t\t\t\t<!ATTLIST dipswitch tag CDATA #REQUIRED>\n"
|
|
"\t\t\t\t\t<!ATTLIST dipswitch mask CDATA #REQUIRED>\n"
|
|
"\t\t\t\t\t<!ELEMENT dipvalue EMPTY>\n"
|
|
"\t\t\t\t\t\t<!ATTLIST dipvalue name CDATA #REQUIRED>\n"
|
|
"\t\t\t\t\t\t<!ATTLIST dipvalue value CDATA #REQUIRED>\n"
|
|
"\t\t\t\t\t\t<!ATTLIST dipvalue default (yes|no) \"no\">\n"
|
|
"]>\n\n"
|
|
"<softwarelists>\n"
|
|
);
|
|
}
|
|
|
|
for ( int drvindex = 0; drivers[drvindex] != NULL; drvindex++ )
|
|
{
|
|
if ( mame_strwildcmp( gamename, drivers[drvindex]->name ) == 0 )
|
|
{
|
|
/* allocate the machine config */
|
|
machine_config config(*drivers[drvindex]);
|
|
|
|
for (const device_config *dev = config.m_devicelist.first(SOFTWARE_LIST); dev != NULL; dev = dev->typenext())
|
|
{
|
|
software_list_config *swlist = (software_list_config *)downcast<const legacy_device_config_base *>(dev)->inline_config();
|
|
|
|
for ( int i = 0; i < DEVINFO_STR_SWLIST_MAX - DEVINFO_STR_SWLIST_0; i++ )
|
|
{
|
|
if ( swlist->list_name[i] && *swlist->list_name[i] && (swlist->list_type == SOFTWARE_LIST_ORIGINAL_SYSTEM))
|
|
{
|
|
software_list *list = software_list_open( options, swlist->list_name[i], FALSE, NULL );
|
|
|
|
if ( list )
|
|
{
|
|
/* Verify if we have encountered this list before */
|
|
bool seen_before = false;
|
|
for ( int l = 0; l < list_idx && !seen_before; l++ )
|
|
{
|
|
if ( ! strcmp( swlist->list_name[i], lists[l] ) )
|
|
{
|
|
seen_before = true;
|
|
}
|
|
}
|
|
|
|
if ( ! seen_before )
|
|
{
|
|
lists[list_idx] = core_strdup( swlist->list_name[i] );
|
|
list_idx++;
|
|
software_list_parse( list, NULL, NULL );
|
|
|
|
fprintf(out, "\t<softwarelist name=\"%s\" description=\"%s\">\n", swlist->list_name[i], xml_normalize_string(software_list_get_description(list)) );
|
|
|
|
for ( software_info *swinfo = software_list_find( list, "*", NULL ); swinfo != NULL; swinfo = software_list_find( list, "*", swinfo ) )
|
|
{
|
|
fprintf( out, "\t\t<software name=\"%s\"", swinfo->shortname );
|
|
if ( swinfo->parentname != NULL )
|
|
fprintf( out, " cloneof=\"%s\"", swinfo->parentname );
|
|
if ( swinfo->supported == SOFTWARE_SUPPORTED_PARTIAL )
|
|
fprintf( out, " supported=\"partial\"" );
|
|
if ( swinfo->supported == SOFTWARE_SUPPORTED_NO )
|
|
fprintf( out, " supported=\"no\"" );
|
|
fprintf( out, ">\n" );
|
|
fprintf( out, "\t\t\t<description>%s</description>\n", xml_normalize_string(swinfo->longname) );
|
|
fprintf( out, "\t\t\t<year>%s</year>\n", xml_normalize_string( swinfo->year ) );
|
|
fprintf( out, "\t\t\t<publisher>%s</publisher>\n", xml_normalize_string( swinfo->publisher ) );
|
|
|
|
for ( software_part *part = software_find_part( swinfo, NULL, NULL ); part != NULL; part = software_part_next( part ) )
|
|
{
|
|
fprintf( out, "\t\t\t<part name=\"%s\"", part->name );
|
|
if ( part->interface_ )
|
|
fprintf( out, " interface=\"%s\"", part->interface_ );
|
|
|
|
fprintf( out, ">\n");
|
|
|
|
if ( part->featurelist )
|
|
{
|
|
feature_list *list = part->featurelist;
|
|
|
|
while( list )
|
|
{
|
|
fprintf( out, "\t\t\t\t<feature name=\"%s\" value=\"%s\" />\n", list->name, list->value );
|
|
list = list->next;
|
|
}
|
|
}
|
|
|
|
/* TODO: display rom region information */
|
|
for ( const rom_entry *region = part->romdata; region; region = rom_next_region( region ) )
|
|
{
|
|
int is_disk = ROMREGION_ISDISKDATA(region);
|
|
|
|
if (!is_disk)
|
|
fprintf( out, "\t\t\t\t<dataarea name=\"%s\" size=\"%d\">\n", ROMREGION_GETTAG(region), ROMREGION_GETLENGTH(region) );
|
|
else
|
|
fprintf( out, "\t\t\t\t<diskarea name=\"%s\">\n", ROMREGION_GETTAG(region) );
|
|
|
|
for ( const rom_entry *rom = rom_first_file( region ); rom && !ROMENTRY_ISREGIONEND(rom); rom++ )
|
|
{
|
|
if ( ROMENTRY_ISFILE(rom) )
|
|
{
|
|
if (!is_disk)
|
|
fprintf( out, "\t\t\t\t\t<rom name=\"%s\" size=\"%d\"", xml_normalize_string(ROM_GETNAME(rom)), rom_file_size(rom) );
|
|
else
|
|
fprintf( out, "\t\t\t\t\t<disk name=\"%s\"", xml_normalize_string(ROM_GETNAME(rom)) );
|
|
|
|
/* dump checksum information only if there is a known dump */
|
|
if (!hash_data_has_info(ROM_GETHASHDATA(rom), HASH_INFO_NO_DUMP))
|
|
{
|
|
char checksum[HASH_BUF_SIZE];
|
|
int hashtype;
|
|
|
|
/* iterate over hash function types and print out their values */
|
|
for (hashtype = 0; hashtype < HASH_NUM_FUNCTIONS; hashtype++)
|
|
if (hash_data_extract_printable_checksum(ROM_GETHASHDATA(rom), 1 << hashtype, checksum))
|
|
fprintf(out, " %s=\"%s\"", hash_function_name(1 << hashtype), checksum);
|
|
}
|
|
|
|
if (!is_disk)
|
|
fprintf( out, " offset=\"0x%x\"", ROM_GETOFFSET(rom) );
|
|
|
|
if ( hash_data_has_info(ROM_GETHASHDATA(rom), HASH_INFO_BAD_DUMP) )
|
|
fprintf( out, " status=\"baddump\"" );
|
|
if ( hash_data_has_info(ROM_GETHASHDATA(rom), HASH_INFO_NO_DUMP) )
|
|
fprintf( out, " status=\"nodump\"" );
|
|
|
|
if (is_disk)
|
|
fprintf( out, " writable=\"%s\"", (ROM_GETFLAGS(rom) & DISK_READONLYMASK) ? "no" : "yes");
|
|
|
|
if ((ROM_GETFLAGS(rom) & ROM_SKIPMASK) == ROM_SKIP(1))
|
|
fprintf( out, " loadflag=\"load16_byte\"" );
|
|
|
|
if ((ROM_GETFLAGS(rom) & ROM_SKIPMASK) == ROM_SKIP(3))
|
|
fprintf( out, " loadflag=\"load32_byte\"" );
|
|
|
|
if (((ROM_GETFLAGS(rom) & ROM_SKIPMASK) == ROM_SKIP(2)) && ((ROM_GETFLAGS(rom) & ROM_GROUPMASK) == ROM_GROUPWORD))
|
|
{
|
|
if (!(ROM_GETFLAGS(rom) & ROM_REVERSEMASK))
|
|
fprintf( out, " loadflag=\"load32_word\"" );
|
|
else
|
|
fprintf( out, " loadflag=\"load32_word_swap\"" );
|
|
}
|
|
|
|
if (((ROM_GETFLAGS(rom) & ROM_SKIPMASK) == ROM_SKIP(6)) && ((ROM_GETFLAGS(rom) & ROM_GROUPMASK) == ROM_GROUPWORD))
|
|
{
|
|
if (!(ROM_GETFLAGS(rom) & ROM_REVERSEMASK))
|
|
fprintf( out, " loadflag=\"load64_word\"" );
|
|
else
|
|
fprintf( out, " loadflag=\"load64_word_swap\"" );
|
|
}
|
|
|
|
if (((ROM_GETFLAGS(rom) & ROM_SKIPMASK) == ROM_NOSKIP) && ((ROM_GETFLAGS(rom) & ROM_GROUPMASK) == ROM_GROUPWORD))
|
|
{
|
|
if (!(ROM_GETFLAGS(rom) & ROM_REVERSEMASK))
|
|
fprintf( out, " loadflag=\"load32_dword\"" );
|
|
else
|
|
fprintf( out, " loadflag=\"load16_word_swap\"" );
|
|
}
|
|
|
|
fprintf( out, "/>\n" );
|
|
}
|
|
else if ( ROMENTRY_ISRELOAD(rom) )
|
|
{
|
|
fprintf( out, "\t\t\t\t\t<rom size=\"%d\" offset=\"0x%x\" loadflag=\"reload\" />\n", ROM_GETLENGTH(rom), ROM_GETOFFSET(rom) );
|
|
}
|
|
else if ( ROMENTRY_ISCONTINUE(rom) )
|
|
{
|
|
fprintf( out, "\t\t\t\t\t<rom size=\"%d\" offset=\"0x%x\" loadflag=\"continue\" />\n", ROM_GETLENGTH(rom), ROM_GETOFFSET(rom) );
|
|
}
|
|
else if ( ROMENTRY_ISFILL(rom) )
|
|
{
|
|
fprintf( out, "\t\t\t\t\t<rom size=\"%d\" offset=\"0x%x\" loadflag=\"fill\" />\n", ROM_GETLENGTH(rom), ROM_GETOFFSET(rom) );
|
|
}
|
|
}
|
|
|
|
if (!is_disk)
|
|
fprintf( out, "\t\t\t\t</dataarea>\n" );
|
|
else
|
|
fprintf( out, "\t\t\t\t</diskarea>\n" );
|
|
}
|
|
|
|
fprintf( out, "\t\t\t</part>\n" );
|
|
}
|
|
|
|
fprintf( out, "\t\t</software>\n" );
|
|
}
|
|
|
|
fprintf(out, "\t</softwarelist>\n" );
|
|
}
|
|
|
|
software_list_close( list );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (nr_lists)
|
|
fprintf( out, "</softwarelists>\n" );
|
|
else
|
|
fprintf( out, "No software lists found for this system\n" );
|
|
|
|
global_free( lists );
|
|
|
|
return MAMERR_NONE;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
softlist_match_roms - scan for a matching
|
|
software ROM by hash
|
|
-------------------------------------------------*/
|
|
static void softlist_match_roms(core_options *options, const char *hash, int length, int *found)
|
|
{
|
|
int drvindex;
|
|
|
|
/* iterate over drivers */
|
|
for (drvindex = 0; drivers[drvindex] != NULL; drvindex++)
|
|
{
|
|
machine_config config(*drivers[drvindex]);
|
|
|
|
for (const device_config *dev = config.m_devicelist.first(SOFTWARE_LIST); dev != NULL; dev = dev->typenext())
|
|
{
|
|
software_list_config *swlist = (software_list_config *)downcast<const legacy_device_config_base *>(dev)->inline_config();
|
|
|
|
for ( int i = 0; i < DEVINFO_STR_SWLIST_MAX - DEVINFO_STR_SWLIST_0; i++ )
|
|
{
|
|
if ( swlist->list_name[i] )
|
|
{
|
|
software_list *list = software_list_open( options, swlist->list_name[i], FALSE, NULL );
|
|
|
|
for ( software_info *swinfo = software_list_find( list, "*", NULL ); swinfo != NULL; swinfo = software_list_find( list, "*", swinfo ) )
|
|
{
|
|
for ( software_part *part = software_find_part( swinfo, NULL, NULL ); part != NULL; part = software_part_next( part ) )
|
|
{
|
|
for ( const rom_entry *region = part->romdata; region != NULL; region = rom_next_region(region) )
|
|
{
|
|
for ( const rom_entry *rom = rom_first_file(region); rom != NULL; rom = rom_next_file(rom) )
|
|
{
|
|
if ( hash_data_is_equal(hash, ROM_GETHASHDATA(rom), 0) )
|
|
{
|
|
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:%s %s\n", baddump ? "(BAD) " : "", ROM_GETNAME(rom), swlist->list_name[i], swinfo->shortname, swinfo->longname);
|
|
(*found)++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
software_list_close( list );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------
|
|
info_listmedia - output the list of image
|
|
devices referenced by a given game or set of
|
|
games
|
|
-------------------------------------------------*/
|
|
|
|
static int info_listmedia(core_options *options, const char *gamename)
|
|
{
|
|
int count = 0, devcount;
|
|
int drvindex;
|
|
const device_config_image_interface *dev = NULL;
|
|
const char *src;
|
|
const char *driver_name;
|
|
const char *name;
|
|
const char *shortname;
|
|
char paren_shortname[16];
|
|
|
|
printf(" SYSTEM DEVICE NAME (brief) IMAGE FILE EXTENSIONS SUPPORTED \n");
|
|
printf("---------- -------------------- ------------------------------------\n");
|
|
|
|
/* iterate over drivers */
|
|
for (drvindex = 0; drivers[drvindex] != NULL; drvindex++)
|
|
if (mame_strwildcmp(gamename, drivers[drvindex]->name) == 0)
|
|
{
|
|
/* allocate the machine config */
|
|
machine_config config(*drivers[drvindex]);
|
|
|
|
driver_name = drivers[drvindex]->name;
|
|
|
|
devcount = 0;
|
|
|
|
for (bool gotone = config.m_devicelist.first(dev); gotone; gotone = dev->next(dev))
|
|
{
|
|
src = downcast<const legacy_image_device_config_base *>(dev)->file_extensions();
|
|
name = downcast<const legacy_image_device_config_base *>(dev)->instance_name();
|
|
shortname = downcast<const legacy_image_device_config_base *>(dev)->brief_instance_name();
|
|
|
|
sprintf(paren_shortname, "(%s)", shortname);
|
|
|
|
printf("%-13s%-12s%-8s ", driver_name, name, paren_shortname);
|
|
driver_name = " ";
|
|
|
|
astring extensions(src);
|
|
char *ext = strtok((char*)extensions.cstr(),",");
|
|
while (ext != NULL)
|
|
{
|
|
printf(".%-5s",ext);
|
|
ext = strtok (NULL, ",");
|
|
devcount++;
|
|
}
|
|
printf("\n");
|
|
}
|
|
if (!devcount)
|
|
printf("%-13s(none)\n",driver_name);
|
|
|
|
count++;
|
|
}
|
|
|
|
if (!count)
|
|
printf("There are no Computers or Consoles named %s\n", gamename);
|
|
|
|
return (count > 0) ? MAMERR_NONE : MAMERR_NO_SUCH_GAME;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
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 = FALSE;
|
|
int drvindex;
|
|
|
|
/* now iterate over drivers */
|
|
for (drvindex = 0; drivers[drvindex] != NULL; 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)
|
|
global_free(audit);
|
|
else
|
|
continue;
|
|
|
|
/* if not found, print a message and set the flag */
|
|
if (res == NOTFOUND)
|
|
{
|
|
mame_printf_error("sampleset \"%s\" not found!\n", drivers[drvindex]->name);
|
|
notfound = TRUE;
|
|
}
|
|
|
|
/* 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;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* clear out any cached files */
|
|
zip_file_cache_clear();
|
|
|
|
/* if we didn't get anything at all because of an unsupported set, display message */
|
|
if (correct + incorrect == 0)
|
|
{
|
|
if (!notfound)
|
|
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(options, 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(core_options *options, 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(filename, PATH_SEPARATOR, entry->name);
|
|
identify_file(options, curfile, status);
|
|
}
|
|
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 = global_alloc_array(UINT8, 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(options, entry->filename, data, entry->uncompressed_length, status);
|
|
global_free(data);
|
|
}
|
|
}
|
|
|
|
/* close up */
|
|
zip_file_close(zip);
|
|
}
|
|
}
|
|
|
|
/* otherwise, identify as a raw file */
|
|
else
|
|
identify_file(options, filename, status);
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
identify_file - identify a file; if it is a
|
|
ZIP file, scan it and identify all enclosed
|
|
files
|
|
-------------------------------------------------*/
|
|
|
|
static void identify_file(core_options *options, const char *name, romident_status *status)
|
|
{
|
|
file_error filerr;
|
|
osd_file *file;
|
|
UINT64 length;
|
|
|
|
if (core_filename_ends_with(name, ".chd"))
|
|
{
|
|
chd_file *chd;
|
|
chd_error err;
|
|
astring basename;
|
|
int found = 0;
|
|
|
|
core_filename_extract_base(&basename, name, FALSE);
|
|
mame_printf_info("%-20s", basename.cstr());
|
|
|
|
status->total++;
|
|
|
|
err = chd_open(name, CHD_OPEN_READ, NULL, &chd);
|
|
if (err != CHDERR_NONE)
|
|
{
|
|
mame_printf_info("NOT A CHD\n");
|
|
status->nonroms++;
|
|
}
|
|
else
|
|
{
|
|
chd_header header;
|
|
|
|
header = *chd_get_header(chd);
|
|
if (header.flags & CHDFLAGS_IS_WRITEABLE)
|
|
{
|
|
mame_printf_info("is a writable CHD\n");
|
|
}
|
|
else
|
|
{
|
|
static const UINT8 nullhash[HASH_BUF_SIZE] = { 0 };
|
|
char hash[HASH_BUF_SIZE]; /* actual hash information */
|
|
|
|
hash_data_clear(hash);
|
|
|
|
/* if there's an MD5 or SHA1 hash, add them to the output hash */
|
|
if (memcmp(nullhash, header.md5, sizeof(header.md5)) != 0)
|
|
hash_data_insert_binary_checksum(hash, HASH_MD5, header.md5);
|
|
if (memcmp(nullhash, header.sha1, sizeof(header.sha1)) != 0)
|
|
hash_data_insert_binary_checksum(hash, HASH_SHA1, header.sha1);
|
|
|
|
length = header.logicalbytes;
|
|
|
|
match_roms(options, hash, length, &found);
|
|
|
|
if (found == 0)
|
|
{
|
|
mame_printf_info("NO MATCH\n");
|
|
}
|
|
|
|
/* if we did find it, count it as a match */
|
|
else
|
|
status->matches++;
|
|
}
|
|
|
|
chd_close(chd);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* 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 = global_alloc_array(UINT8, 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(options, name, data, bytes, status);
|
|
global_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(core_options *options, const char *name, const UINT8 *data, int length, romident_status *status)
|
|
{
|
|
char hash[HASH_BUF_SIZE];
|
|
UINT8 *tempjed = NULL;
|
|
astring basename;
|
|
int found = 0;
|
|
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 = global_alloc_array(UINT8, 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++;
|
|
core_filename_extract_base(&basename, name, FALSE);
|
|
mame_printf_info("%-20s", basename.cstr());
|
|
|
|
/* see if we can find a match in the ROMs */
|
|
match_roms(options, 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)
|
|
global_free(tempjed);
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
match_roms - scan for a matching ROM by hash
|
|
-------------------------------------------------*/
|
|
|
|
static void match_roms(core_options *options, const char *hash, int length, int *found)
|
|
{
|
|
int drvindex;
|
|
|
|
/* iterate over drivers */
|
|
for (drvindex = 0; drivers[drvindex] != NULL; drvindex++)
|
|
{
|
|
machine_config config(*drivers[drvindex]);
|
|
const rom_entry *region, *rom;
|
|
const rom_source *source;
|
|
|
|
/* iterate over sources, regions and files within the region */
|
|
for (source = rom_first_source(config); source != NULL; source = rom_next_source(*source))
|
|
for (region = rom_first_region(*source); region; region = rom_next_region(region))
|
|
for (rom = rom_first_file(region); rom; rom = rom_next_file(rom))
|
|
if (hash_data_is_equal(hash, ROM_GETHASHDATA(rom), 0))
|
|
{
|
|
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 %-10s %s\n", baddump ? "(BAD) " : "", ROM_GETNAME(rom), drivers[drvindex]->name, drivers[drvindex]->description);
|
|
(*found)++;
|
|
}
|
|
}
|
|
|
|
softlist_match_roms( options, hash, length, found );
|
|
}
|