summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/romload.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/romload.cpp')
-rw-r--r--src/emu/romload.cpp1464
1 files changed, 780 insertions, 684 deletions
diff --git a/src/emu/romload.cpp b/src/emu/romload.cpp
index c5b03607509..33541aedce4 100644
--- a/src/emu/romload.cpp
+++ b/src/emu/romload.cpp
@@ -1,20 +1,31 @@
// license:BSD-3-Clause
-// copyright-holders:Nicola Salmoria,Paul Priest,Aaron Giles
+// copyright-holders:Nicola Salmoria,Paul Priest,Aaron Giles,Vas Crabb
/*********************************************************************
romload.cpp
ROM loading functions.
+
*********************************************************************/
#include "emu.h"
#include "romload.h"
-#include "emuopts.h"
#include "drivenum.h"
+#include "emuopts.h"
+#include "fileio.h"
+#include "main.h"
#include "softlist_dev.h"
+
#include "ui/uimain.h"
+#include "corestr.h"
+#include "path.h"
+
+#include <algorithm>
+#include <cstdarg>
+#include <set>
+
#define LOG_LOAD 0
#define LOG(...) do { if (LOG_LOAD) debugload(__VA_ARGS__); } while(0)
@@ -27,32 +38,245 @@
#define TEMPBUFFER_MAX_SIZE (1024 * 1024 * 1024)
/***************************************************************************
- HELPERS (also used by diimage.cpp)
- ***************************************************************************/
+ HELPERS
+****************************************************************************/
+
+namespace {
+
+/*-------------------------------------------------
+ debugload - log data to a file
+-------------------------------------------------*/
+
+void ATTR_PRINTF(1,2) debugload(const char *string, ...)
+{
+ static int opened = 0;
+ FILE *const f(fopen("romload.log", opened++ ? "a" : "w"));
+ if (f)
+ {
+ va_list arg;
+ va_start(arg, string);
+ vfprintf(f, string, arg);
+ va_end(arg);
+ fclose(f);
+ }
+}
-static osd_file::error common_process_file(emu_options &options, const char *location, const char *ext, const rom_entry *romp, emu_file &image_file)
+
+auto next_parent_system(game_driver const &system)
{
- return (location && *location)
- ? image_file.open(location, PATH_SEPARATOR, ROM_GETNAME(romp), ext)
- : image_file.open(ROM_GETNAME(romp), ext);
+ return
+ [sys = &system, roms = std::vector<rom_entry>()] () mutable -> rom_entry const *
+ {
+ if (!sys)
+ return nullptr;
+ int const parent(driver_list::find(sys->parent));
+ if (0 > parent)
+ {
+ sys = nullptr;
+ roms.clear();
+ roms.shrink_to_fit();
+ return nullptr;
+ }
+ else
+ {
+ sys = &driver_list::driver(parent);
+ roms = rom_build_entries(sys->rom);
+ return &roms.front();
+ }
+ };
}
-std::unique_ptr<emu_file> common_process_file(emu_options &options, const char *location, bool has_crc, u32 crc, const rom_entry *romp, osd_file::error &filerr)
+
+auto next_parent_device(device_t const &device, emu_options &options)
{
- auto image_file = std::make_unique<emu_file>(options.media_path(), OPEN_FLAG_READ);
+ return
+ [&options, type = &device.type(), roms = std::vector<rom_entry>()] () mutable -> rom_entry const *
+ {
+ if (!type)
+ return nullptr;
+ type = type->parent_rom_device_type();
+ if (!type)
+ {
+ roms.clear();
+ roms.shrink_to_fit();
+ return nullptr;
+ }
+ else
+ {
+ machine_config config(GAME_NAME(___empty), options);
+ machine_config::token const tok(config.begin_configuration(config.root_device()));
+ roms = config.device_add("_tmp", *type, 0)->rom_region_vector();
+ config.device_remove("_tmp");
+ return &roms.front();
+ }
+ };
+}
- if (has_crc)
- filerr = image_file->open(location, PATH_SEPARATOR, ROM_GETNAME(romp), crc);
- else
- filerr = image_file->open(location, PATH_SEPARATOR, ROM_GETNAME(romp));
- if (filerr != osd_file::error::NONE)
+auto next_parent_software(std::vector<software_info const *> const &parents)
+{
+ auto part(parents.front()->parts().end());
+ return
+ [&parents, current = parents.cbegin(), part, end = part] () mutable -> const rom_entry *
+ {
+ if (part == end)
+ {
+ if (parents.end() == current)
+ return nullptr;
+ part = (*current)->parts().cbegin();
+ end = (*current)->parts().cend();
+ do { ++current; } while ((parents.cend() != current) && (*current)->parts().empty());
+ }
+ return &(*part++).romdata()[0];
+ };
+}
+
+
+std::vector<std::string> make_software_searchpath(software_list_device &swlist, software_info const &swinfo, std::vector<software_info const *> &parents)
+{
+ std::vector<std::string> result;
+
+ // search <rompath>/<list>/<software> following parents
+ for (software_info const *i = &swinfo; i; )
{
- image_file = nullptr;
+ if (std::find(parents.begin(), parents.end(), i) != parents.end())
+ break;
+ parents.emplace_back(i);
+ result.emplace_back(util::path_concat(swlist.list_name(), i->shortname()));
+ i = i->parentname().empty() ? nullptr : swlist.find(i->parentname());
}
- return image_file;
+
+ // search <rompath>/<software> following parents
+ for (software_info const *i : parents)
+ result.emplace_back(i->shortname());
+
+ return result;
}
+
+std::error_condition do_open_disk(
+ emu_options const &options,
+ std::initializer_list<std::reference_wrapper<std::vector<std::string> const> > searchpath,
+ rom_entry const *romp,
+ chd_file &chd,
+ std::function<rom_entry const * ()> next_parent,
+ chd_file::open_parent_func const &open_parent)
+{
+ // hashes are fixed, but we might need to try multiple filenames
+ std::set<std::string> tried;
+ util::hash_collection const hashes(romp->hashdata());
+ std::string filename, fullpath;
+ rom_entry const *parent(nullptr);
+ std::error_condition result(std::errc::no_such_file_or_directory);
+ while (romp && result)
+ {
+ filename = romp->name() + ".chd";
+ if (tried.insert(filename).second)
+ {
+ // piggyback on emu_file to find the disk image file
+ std::unique_ptr<emu_file> imgfile;
+ for (std::vector<std::string> const &paths : searchpath)
+ {
+ imgfile.reset(new emu_file(options.media_path(), paths, OPEN_FLAG_READ));
+ imgfile->set_restrict_to_mediapath(1);
+ std::error_condition const filerr(imgfile->open(filename, OPEN_FLAG_READ));
+ if (!filerr)
+ break;
+ else
+ imgfile.reset();
+ }
+
+ // if we couldn't open a candidate file, report an error; otherwise reopen it as a CHD
+ if (imgfile)
+ {
+ fullpath = imgfile->fullpath();
+ imgfile.reset();
+ result = chd.open(fullpath, false, nullptr, open_parent);
+ }
+ }
+
+ // walk the parents looking for a CHD with the same hashes but a different name
+ if (result)
+ {
+ while (romp)
+ {
+ // find a file in a disk region
+ if (parent)
+ romp = rom_next_file(romp);
+ while (!parent || !romp)
+ {
+ if (!parent)
+ {
+ parent = next_parent();
+ if (!parent)
+ {
+ romp = nullptr;
+ break;
+ }
+ parent = rom_first_region(parent);
+ }
+ else
+ {
+ parent = rom_next_region(parent);
+ }
+ while (parent && !ROMREGION_ISDISKDATA(parent))
+ parent = rom_next_region(parent);
+ if (parent)
+ romp = rom_first_file(parent);
+ }
+
+ // try it if it matches the hashes
+ if (romp && (util::hash_collection(romp->hashdata()) == hashes))
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+
+auto open_parent_disk(
+ emu_options const &options,
+ std::initializer_list<std::reference_wrapper<std::vector<std::string> const> > searchpath,
+ std::function<rom_entry const * ()> const &next_parent)
+{
+ return
+ [&options, searchpath, next_parent] (util::sha1_t const &sha1) -> std::unique_ptr<chd_file>
+ {
+ util::hash_collection hashes;
+ hashes.add_sha1(sha1);
+ std::function<rom_entry const * ()> np(next_parent); // important - copy mutable lambda
+ for (rom_entry const *parent = np(); parent; parent = np())
+ {
+ parent = rom_first_region(parent);
+ while (parent)
+ {
+ while (parent && !ROMREGION_ISDISKDATA(parent))
+ parent = rom_next_region(parent);
+ if (parent)
+ {
+ rom_entry const *romp(rom_first_file(parent));
+ while (romp)
+ {
+ if (util::hash_collection(romp->hashdata()) == hashes)
+ {
+ std::unique_ptr<chd_file> chd(new chd_file);
+ if (!do_open_disk(options, searchpath, romp, *chd, next_parent, nullptr))
+ return chd;
+ }
+ romp = rom_next_file(romp);
+ }
+ parent = rom_next_region(parent);
+ }
+ }
+ }
+ return nullptr;
+ };
+}
+
+} // anonymous namespace
+
+
/***************************************************************************
ROM LOADING
***************************************************************************/
@@ -64,7 +288,11 @@ std::unique_ptr<emu_file> common_process_file(emu_options &options, const char *
const rom_entry *rom_first_region(const device_t &device)
{
- const rom_entry *romp = &device.rom_region_vector().front();
+ return rom_first_region(&device.rom_region_vector().front());
+}
+
+const rom_entry *rom_first_region(const rom_entry *romp)
+{
while (ROMENTRY_ISPARAMETER(romp) || ROMENTRY_ISSYSTEM_BIOS(romp) || ROMENTRY_ISDEFAULT_BIOS(romp))
romp++;
return !ROMENTRY_ISEND(romp) ? romp : nullptr;
@@ -125,7 +353,7 @@ const rom_entry *rom_first_parameter(const device_t &device)
const rom_entry *romp = &device.rom_region_vector().front();
while (romp && !ROMENTRY_ISEND(romp) && !ROMENTRY_ISPARAMETER(romp))
romp++;
- return (romp != nullptr && !ROMENTRY_ISEND(romp)) ? romp : nullptr;
+ return (romp && !ROMENTRY_ISEND(romp)) ? romp : nullptr;
}
@@ -144,56 +372,23 @@ const rom_entry *rom_next_parameter(const rom_entry *romp)
/*-------------------------------------------------
- rom_region_name - return the appropriate name
- for a rom region
--------------------------------------------------*/
-
-std::string rom_region_name(const device_t &device, const rom_entry *romp)
-{
- return device.subtag(ROM_GETNAME(romp));
-}
-
-
-/*-------------------------------------------------
- rom_parameter_name - return the appropriate name
- for a per-game parameter
--------------------------------------------------*/
-
-std::string rom_parameter_name(const device_t &device, const rom_entry *romp)
-{
- return device.subtag(romp->name().c_str());
-}
-
-
-/*-------------------------------------------------
- rom_parameter_name - return the value for a
- per-game parameter
--------------------------------------------------*/
-
-std::string rom_parameter_value(const rom_entry *romp)
-{
- return romp->hashdata();
-}
-
-
-/*-------------------------------------------------
rom_file_size - return the expected size of a
file given the ROM description
-------------------------------------------------*/
u32 rom_file_size(const rom_entry *romp)
{
- u32 maxlength = 0;
+ u32 maxlength(0);
- /* loop until we run out of reloads */
+ // loop until we run out of reloads
do
{
- /* loop until we run out of continues/ignores */
+ // loop until we run out of continues/ignores
u32 curlength = ROM_GETLENGTH(romp++);
while (ROMENTRY_ISCONTINUE(romp) || ROMENTRY_ISIGNORE(romp))
curlength += ROM_GETLENGTH(romp++);
- /* track the maximum length */
+ // track the maximum length
maxlength = std::max(maxlength, curlength);
}
while (ROMENTRY_ISRELOAD(romp));
@@ -202,27 +397,6 @@ u32 rom_file_size(const rom_entry *romp)
}
-/*-------------------------------------------------
- debugload - log data to a file
--------------------------------------------------*/
-
-static void CLIB_DECL ATTR_PRINTF(1,2) debugload(const char *string, ...)
-{
- static int opened;
- va_list arg;
- FILE *f;
-
- f = fopen("romload.log", opened++ ? "a" : "w");
- if (f)
- {
- va_start(arg, string);
- vfprintf(f, string, arg);
- va_end(arg);
- fclose(f);
- }
-}
-
-
/***************************************************************************
HARD DISK HANDLING
***************************************************************************/
@@ -232,11 +406,13 @@ static void CLIB_DECL ATTR_PRINTF(1,2) debugload(const char *string, ...)
CHD file associated with the given region
-------------------------------------------------*/
-chd_file *rom_load_manager::get_disk_handle(const char *region)
+chd_file *rom_load_manager::get_disk_handle(std::string_view region)
{
for (auto &curdisk : m_chd_list)
- if (strcmp(curdisk->region(), region) == 0)
+ {
+ if (curdisk->region() == region)
return &curdisk->chd();
+ }
return nullptr;
}
@@ -246,37 +422,36 @@ chd_file *rom_load_manager::get_disk_handle(const char *region)
file associated with the given region
-------------------------------------------------*/
-int rom_load_manager::set_disk_handle(const char *region, const char *fullpath)
+std::error_condition rom_load_manager::set_disk_handle(std::string_view region, std::string_view fullpath)
{
- auto chd = std::make_unique<open_chd>(region);
- auto err = chd->orig_chd().open(fullpath);
- if (err == CHDERR_NONE)
- m_chd_list.push_back(std::move(chd));
+ auto chd(std::make_unique<open_chd>(region));
+ std::error_condition const err(chd->orig_chd().open(fullpath));
+ if (!err)
+ m_chd_list.emplace_back(std::move(chd));
return err;
}
/*-------------------------------------------------
determine_bios_rom - determine system_bios
- from SystemBios structure and OPTION_BIOS
+ from SYSTEM_BIOS structure and OPTION_BIOS
-------------------------------------------------*/
-void rom_load_manager::determine_bios_rom(device_t &device, const char *specbios)
+void rom_load_manager::determine_bios_rom(device_t &device, std::string_view specbios)
{
// default is applied by the device at config complete time
- if (specbios && *specbios && core_stricmp(specbios, "default"))
+ using namespace std::literals;
+ if (!specbios.empty() && !util::streqlower(specbios, "default"sv))
{
bool found(false);
- for (const rom_entry &rom : device.rom_region_vector())
+ for (rom_entry const &rom : device.rom_region_vector())
{
if (ROMENTRY_ISSYSTEM_BIOS(&rom))
{
char const *const biosname = ROM_GETNAME(&rom);
int const bios_flags = ROM_GETBIOSFLAGS(&rom);
- char bios_number[20];
// Allow '-bios n' to still be used
- sprintf(bios_number, "%d", bios_flags - 1);
- if (!core_stricmp(bios_number, specbios) || !core_stricmp(biosname, specbios))
+ if ((specbios == std::to_string(bios_flags - 1)) || util::streqlower(specbios, biosname))
{
found = true;
device.set_system_bios(bios_flags);
@@ -287,7 +462,10 @@ void rom_load_manager::determine_bios_rom(device_t &device, const char *specbios
// if we got neither an empty string nor 'default' then warn the user
if (!found)
+ {
m_errorstring.append(util::string_format("%s: invalid BIOS \"%s\", reverting to default\n", device.tag(), specbios));
+ m_warnings++;
+ }
}
// log final result
@@ -302,21 +480,29 @@ void rom_load_manager::determine_bios_rom(device_t &device, const char *specbios
void rom_load_manager::count_roms()
{
- const rom_entry *region, *rom;
-
- /* start with 0 */
+ // start with 0
m_romstotal = 0;
m_romstotalsize = 0;
- /* loop over regions, then over files */
- for (device_t &device : device_iterator(machine().config().root_device()))
- for (region = rom_first_region(device); region != nullptr; region = rom_next_region(region))
- for (rom = rom_first_file(region); rom != nullptr; rom = rom_next_file(rom))
- if (ROM_GETBIOSFLAGS(rom) == 0 || ROM_GETBIOSFLAGS(rom) == device.system_bios())
+ // loop over regions, and files within regions
+ for (device_t &device : device_enumerator(machine().config().root_device()))
+ {
+ rom_entry const *region(rom_first_region(device));
+ while (region)
+ {
+ rom_entry const *rom(rom_first_file(region));
+ while (rom)
+ {
+ if ((ROM_GETBIOSFLAGS(rom) == 0) || (ROM_GETBIOSFLAGS(rom) == device.system_bios()))
{
m_romstotal++;
m_romstotalsize += rom_file_size(rom);
}
+ rom = rom_next_file(rom);
+ }
+ region = rom_next_region(region);
+ }
+ }
}
@@ -337,42 +523,46 @@ void rom_load_manager::fill_random(u8 *base, u32 length)
for missing files
-------------------------------------------------*/
-void rom_load_manager::handle_missing_file(const rom_entry *romp, std::string tried_file_names, chd_error chderr)
+void rom_load_manager::handle_missing_file(const rom_entry *romp, const std::vector<std::string> &tried_file_names, std::error_condition chderr)
{
- if(tried_file_names.length() != 0)
- tried_file_names = " (tried in " + tried_file_names + ")";
-
- std::string name(ROM_GETNAME(romp));
+ std::string tried;
+ if (!tried_file_names.empty())
+ {
+ tried = " (tried in";
+ for (const std::string &path : tried_file_names)
+ {
+ tried += ' ';
+ tried += path;
+ }
+ tried += ')';
+ }
- bool is_chd = (chderr != CHDERR_NONE);
- if (is_chd)
- name += ".chd";
+ const bool is_chd(chderr);
+ const std::string name(is_chd ? romp->name() + ".chd" : romp->name());
- bool is_chd_error = (is_chd && chderr != CHDERR_FILE_NOT_FOUND);
+ const bool is_chd_error(is_chd && (chderr != std::errc::no_such_file_or_directory));
if (is_chd_error)
- m_errorstring.append(string_format("%s CHD ERROR: %s\n", name.c_str(), chd_file::error_string(chderr)));
+ m_errorstring.append(string_format("%s CHD ERROR: %s\n", name, chderr.message()));
- /* optional files are okay */
if (ROM_ISOPTIONAL(romp))
{
+ // optional files are okay
if (!is_chd_error)
- m_errorstring.append(string_format("OPTIONAL %s NOT FOUND%s\n", name.c_str(), tried_file_names.c_str()));
+ m_errorstring.append(string_format("OPTIONAL %s NOT FOUND%s\n", name, tried));
m_warnings++;
}
-
- /* no good dumps are okay */
- else if (util::hash_collection(ROM_GETHASHDATA(romp)).flag(util::hash_collection::FLAG_NO_DUMP))
+ else if (util::hash_collection(romp->hashdata()).flag(util::hash_collection::FLAG_NO_DUMP))
{
+ // no good dumps are okay
if (!is_chd_error)
- m_errorstring.append(string_format("%s NOT FOUND (NO GOOD DUMP KNOWN)%s\n", name, tried_file_names));
+ m_errorstring.append(string_format("%s NOT FOUND (NO GOOD DUMP KNOWN)%s\n", name, tried));
m_knownbad++;
}
-
- /* anything else is bad */
else
{
+ // anything else is bad
if (!is_chd_error)
- m_errorstring.append(string_format("%s NOT FOUND%s\n", name.c_str(), tried_file_names));
+ m_errorstring.append(string_format("%s NOT FOUND%s\n", name, tried));
m_errors++;
}
}
@@ -386,8 +576,8 @@ void rom_load_manager::handle_missing_file(const rom_entry *romp, std::string tr
void rom_load_manager::dump_wrong_and_correct_checksums(const util::hash_collection &hashes, const util::hash_collection &acthashes)
{
- m_errorstring.append(string_format(" EXPECTED: %s\n", hashes.macro_string().c_str()));
- m_errorstring.append(string_format(" FOUND: %s\n", acthashes.macro_string().c_str()));
+ m_errorstring.append(string_format(" EXPECTED: %s\n", hashes.macro_string()));
+ m_errorstring.append(string_format(" FOUND: %s\n", acthashes.macro_string()));
}
@@ -396,43 +586,46 @@ void rom_load_manager::dump_wrong_and_correct_checksums(const util::hash_collect
and hash signatures of a file
-------------------------------------------------*/
-void rom_load_manager::verify_length_and_hash(const char *name, u32 explength, const util::hash_collection &hashes)
+void rom_load_manager::verify_length_and_hash(emu_file *file, std::string_view name, u32 explength, const util::hash_collection &hashes)
{
- /* we've already complained if there is no file */
- if (m_file == nullptr)
+ // we've already complained if there is no file
+ if (!file)
return;
- /* verify length */
- u32 actlength = m_file->size();
+ // verify length
+ u64 const actlength(file->size());
if (explength != actlength)
{
m_errorstring.append(string_format("%s WRONG LENGTH (expected: %08x found: %08x)\n", name, explength, actlength));
m_warnings++;
}
- /* If there is no good dump known, write it */
- util::hash_collection &acthashes = m_file->hashes(hashes.hash_types().c_str());
if (hashes.flag(util::hash_collection::FLAG_NO_DUMP))
{
+ // If there is no good dump known, write it
m_errorstring.append(string_format("%s NO GOOD DUMP KNOWN\n", name));
m_knownbad++;
}
- /* verify checksums */
- else if (hashes != acthashes)
- {
- /* otherwise, it's just bad */
- util::hash_collection &all_acthashes = acthashes.hash_types() == util::hash_collection::HASH_TYPES_ALL
- ? acthashes
- : m_file->hashes(util::hash_collection::HASH_TYPES_ALL);
- m_errorstring.append(string_format("%s WRONG CHECKSUMS:\n", name));
- dump_wrong_and_correct_checksums(hashes, all_acthashes);
- m_warnings++;
- }
- /* If it matches, but it is actually a bad dump, write it */
- else if (hashes.flag(util::hash_collection::FLAG_BAD_DUMP))
+ else
{
- m_errorstring.append(string_format("%s ROM NEEDS REDUMP\n", name));
- m_knownbad++;
+ // verify checksums
+ util::hash_collection const &acthashes(file->hashes(hashes.hash_types()));
+ if (hashes != acthashes)
+ {
+ // otherwise, it's just bad
+ util::hash_collection const &all_acthashes = (acthashes.hash_types() == util::hash_collection::HASH_TYPES_ALL)
+ ? acthashes
+ : file->hashes(util::hash_collection::HASH_TYPES_ALL);
+ m_errorstring.append(string_format("%s WRONG CHECKSUMS:\n", name));
+ dump_wrong_and_correct_checksums(hashes, all_acthashes);
+ m_warnings++;
+ }
+ else if (hashes.flag(util::hash_collection::FLAG_BAD_DUMP))
+ {
+ // If it matches, but it is actually a bad dump, write it
+ m_errorstring.append(string_format("%s ROM NEEDS REDUMP\n", name));
+ m_knownbad++;
+ }
}
}
@@ -444,15 +637,14 @@ void rom_load_manager::verify_length_and_hash(const char *name, u32 explength, c
void rom_load_manager::display_loading_rom_message(const char *name, bool from_list)
{
- char buffer[200];
-
- if (name != nullptr)
- sprintf(buffer, "%s (%d%%)", from_list ? "Loading Software" : "Loading Machine", u32(100 * u64(m_romsloadedsize) / u64(m_romstotalsize)));
+ std::string buffer;
+ if (name)
+ buffer = util::string_format("%s (%d%%)", from_list ? "Loading Software" : "Loading Machine", u32(100 * m_romsloadedsize / m_romstotalsize));
else
- sprintf(buffer, "Loading Complete");
+ buffer = "Loading Complete";
if (!machine().ui().is_menu_active())
- machine().ui().set_startup_text(buffer, false);
+ machine().ui().set_startup_text(buffer.c_str(), false);
}
@@ -463,22 +655,22 @@ void rom_load_manager::display_loading_rom_message(const char *name, bool from_l
void rom_load_manager::display_rom_load_results(bool from_list)
{
- /* final status display */
+ // final status display
display_loading_rom_message(nullptr, from_list);
- /* if we had errors, they are fatal */
+ // if we had errors, they are fatal
if (m_errors != 0)
{
- /* create the error message and exit fatally */
- osd_printf_error("%s", m_errorstring.c_str());
- fatalerror_exitcode(machine(), EMU_ERR_MISSING_FILES, "Required files are missing, the machine cannot be run.");
+ // create the error message and exit fatally
+ osd_printf_error("%s", m_errorstring);
+ throw emu_fatalerror(EMU_ERR_MISSING_FILES, "Required files are missing, the machine cannot be run.");
}
- /* if we had warnings, output them, but continue */
- if ((m_warnings) || (m_knownbad))
+ // if we had warnings, output them, but continue
+ if (m_warnings || m_knownbad)
{
m_errorstring.append("WARNING: the machine might not run correctly.");
- osd_printf_warning("%s\n", m_errorstring.c_str());
+ osd_printf_warning("%s\n", m_errorstring);
}
}
@@ -488,37 +680,36 @@ void rom_load_manager::display_rom_load_results(bool from_list)
byte swapping and inverting data as necessary
-------------------------------------------------*/
-void rom_load_manager::region_post_process(const char *rgntag, bool invert)
+void rom_load_manager::region_post_process(memory_region *region, bool invert)
{
- memory_region *region = machine().root_device().memregion(rgntag);
- u8 *base;
- int i, j;
-
// do nothing if no region
- if (region == nullptr)
+ if (!region)
return;
- LOG("+ datawidth=%dbit endian=%s\n", region->bitwidth(),
- region->endianness() == ENDIANNESS_LITTLE ? "little" : "big");
+ LOG("+ datawidth=%dbit endian=%s\n",
+ region->bitwidth(),
+ (region->endianness() == ENDIANNESS_LITTLE) ? "little" : "big");
- /* if the region is inverted, do that now */
+ // if the region is inverted, do that now
if (invert)
{
LOG("+ Inverting region\n");
- for (i = 0, base = region->base(); i < region->bytes(); i++)
+ u8 *base(region->base());
+ for (int i = 0; i < region->bytes(); i++)
*base++ ^= 0xff;
}
- /* swap the endianness if we need to */
- if (region->bytewidth() > 1 && region->endianness() != ENDIANNESS_NATIVE)
+ // swap the endianness if we need to
+ int const datawidth(region->bytewidth());
+ if ((datawidth > 1) && (region->endianness() != ENDIANNESS_NATIVE))
{
LOG("+ Byte swapping region\n");
- int datawidth = region->bytewidth();
- for (i = 0, base = region->base(); i < region->bytes(); i += datawidth)
+ u8 *base(region->base());
+ for (int i = 0; i < region->bytes(); i += datawidth)
{
u8 temp[8];
memcpy(temp, base, datawidth);
- for (j = datawidth - 1; j >= 0; j--)
+ for (int j = datawidth - 1; j >= 0; j--)
*base++ = temp[j];
}
}
@@ -530,116 +721,64 @@ void rom_load_manager::region_post_process(const char *rgntag, bool invert)
up the parent and loading by checksum
-------------------------------------------------*/
-int rom_load_manager::open_rom_file(const char *regiontag, const rom_entry *romp, std::string &tried_file_names, bool from_list)
+std::unique_ptr<emu_file> rom_load_manager::open_rom_file(
+ const std::vector<std::string> &searchpath,
+ const rom_entry *romp,
+ std::vector<std::string> &tried_file_names,
+ bool from_list)
{
- osd_file::error filerr = osd_file::error::NOT_FOUND;
- u32 romsize = rom_file_size(romp);
- tried_file_names = "";
+ std::error_condition filerr = std::errc::no_such_file_or_directory;
+ u32 const romsize = rom_file_size(romp);
+ tried_file_names.clear();
- /* update status display */
+ // update status display
display_loading_rom_message(ROM_GETNAME(romp), from_list);
- /* extract CRC to use for searching */
+ // extract CRC to use for searching
u32 crc = 0;
- bool has_crc = util::hash_collection(ROM_GETHASHDATA(romp)).crc(crc);
-
- /* attempt reading up the chain through the parents. It automatically also
- attempts any kind of load by checksum supported by the archives. */
- m_file = nullptr;
- for (int drv = driver_list::find(machine().system()); m_file == nullptr && drv != -1; drv = driver_list::clone(drv)) {
- if (tried_file_names.length() != 0)
- tried_file_names += " ";
- tried_file_names += driver_list::driver(drv).name;
- m_file = common_process_file(machine().options(), driver_list::driver(drv).name, has_crc, crc, romp, filerr);
- }
-
- /* if the region is load by name, load the ROM from there */
- if (m_file == nullptr && regiontag != nullptr)
- {
- // check if we are dealing with softwarelists. if so, locationtag
- // is actually a concatenation of: listname + setname + parentname
- // separated by '%' (parentname being present only for clones)
- std::string tag1(regiontag), tag2, tag3, tag4, tag5;
- bool is_list = false;
- bool has_parent = false;
-
- int separator1 = tag1.find_first_of('%');
- if (separator1 != -1)
- {
- is_list = true;
-
- // we are loading through softlists, split the listname from the regiontag
- tag4.assign(tag1.substr(separator1 + 1, tag1.length() - separator1 + 1));
- tag1.erase(separator1, tag1.length() - separator1);
- tag1.append(PATH_SEPARATOR);
+ bool const has_crc = util::hash_collection(romp->hashdata()).crc(crc);
- // check if we are loading a clone (if this is the case also tag1 have a separator '%')
- int separator2 = tag4.find_first_of('%');
- if (separator2 != -1)
- {
- has_parent = true;
+ // attempt reading up the chain through the parents
+ // it also automatically attempts any kind of load by checksum supported by the archives.
+ std::unique_ptr<emu_file> result(
+ open_rom_file(searchpath, tried_file_names, has_crc, crc, ROM_GETNAME(romp), filerr));
- // we are loading a clone through softlists, split the setname from the parentname
- tag5.assign(tag4.substr(separator2 + 1, tag4.length() - separator2 + 1));
- tag4.erase(separator2, tag4.length() - separator2);
- }
+ // update counters
+ m_romsloaded++;
+ m_romsloadedsize += romsize;
- // prepare locations where we have to load from: list/parentname & list/clonename
- std::string swlist(tag1);
- tag2.assign(swlist.append(tag4));
- if (has_parent)
- {
- swlist.assign(tag1);
- tag3.assign(swlist.append(tag5));
- }
- }
+ // return the result
+ if (filerr)
+ return nullptr;
+ else
+ return result;
+}
- if (tag5.find_first_of('%') != -1)
- fatalerror("We do not support clones of clones!\n");
- // try to load from the available location(s):
- // - if we are not using lists, we have regiontag only;
- // - if we are using lists, we have: list/clonename, list/parentname, clonename, parentname
- if (!is_list)
- {
- tried_file_names += " " + tag1;
- m_file = common_process_file(machine().options(), tag1.c_str(), has_crc, crc, romp, filerr);
- }
- else
- {
- // try to load from list/setname
- if ((m_file == nullptr) && (tag2.c_str() != nullptr))
- {
- tried_file_names += " " + tag2;
- m_file = common_process_file(machine().options(), tag2.c_str(), has_crc, crc, romp, filerr);
- }
- // try to load from list/parentname
- if ((m_file == nullptr) && has_parent && (tag3.c_str() != nullptr))
- {
- tried_file_names += " " + tag3;
- m_file = common_process_file(machine().options(), tag3.c_str(), has_crc, crc, romp, filerr);
- }
- // try to load from setname
- if ((m_file == nullptr) && (tag4.c_str() != nullptr))
- {
- tried_file_names += " " + tag4;
- m_file = common_process_file(machine().options(), tag4.c_str(), has_crc, crc, romp, filerr);
- }
- // try to load from parentname
- if ((m_file == nullptr) && has_parent && (tag5.c_str() != nullptr))
- {
- tried_file_names += " " + tag5;
- m_file = common_process_file(machine().options(), tag5.c_str(), has_crc, crc, romp, filerr);
- }
- }
- }
+std::unique_ptr<emu_file> rom_load_manager::open_rom_file(
+ const std::vector<std::string> &paths,
+ std::vector<std::string> &tried,
+ bool has_crc,
+ u32 crc,
+ std::string_view name,
+ std::error_condition &filerr)
+{
+ // record the set names we search
+ tried.insert(tried.end(), paths.begin(), paths.end());
- /* update counters */
- m_romsloaded++;
- m_romsloadedsize += romsize;
+ // attempt to open the file
+ std::unique_ptr<emu_file> result(new emu_file(machine().options().media_path(), paths, OPEN_FLAG_READ));
+ result->set_restrict_to_mediapath(1);
+ if (has_crc)
+ filerr = result->open(name, crc);
+ else
+ filerr = result->open(name);
- /* return the result */
- return (filerr == osd_file::error::NONE);
+ // don't return anything if unsuccessful
+ if (filerr)
+ return nullptr;
+ else
+ return result;
}
@@ -648,14 +787,12 @@ int rom_load_manager::open_rom_file(const char *regiontag, const rom_entry *romp
random data for a nullptr file
-------------------------------------------------*/
-int rom_load_manager::rom_fread(u8 *buffer, int length, const rom_entry *parent_region)
+int rom_load_manager::rom_fread(emu_file *file, u8 *buffer, int length, const rom_entry *parent_region)
{
- /* files just pass through */
- if (m_file != nullptr)
- return m_file->read(buffer, length);
+ if (file) // files just pass through
+ return file->read(buffer, length);
- /* otherwise, fill with randomness unless it was already specifically erased */
- else if (!ROMREGION_ISERASE(parent_region))
+ if (!ROMREGION_ISERASE(parent_region)) // otherwise, fill with randomness unless it was already specifically erased
fill_random(buffer, length);
return length;
@@ -667,109 +804,118 @@ int rom_load_manager::rom_fread(u8 *buffer, int length, const rom_entry *parent_
entry
-------------------------------------------------*/
-int rom_load_manager::read_rom_data(const rom_entry *parent_region, const rom_entry *romp)
+int rom_load_manager::read_rom_data(
+ emu_file *file,
+ memory_region &region,
+ const rom_entry *parent_region,
+ const rom_entry *romp)
{
- int datashift = ROM_GETBITSHIFT(romp);
- int datamask = ((1 << ROM_GETBITWIDTH(romp)) - 1) << datashift;
- int numbytes = ROM_GETLENGTH(romp);
- int groupsize = ROM_GETGROUPSIZE(romp);
- int skip = ROM_GETSKIPCOUNT(romp);
- int reversed = ROM_ISREVERSED(romp);
- int numgroups = (numbytes + groupsize - 1) / groupsize;
- u8 *base = m_region->base() + ROM_GETOFFSET(romp);
- u32 tempbufsize;
- int i;
+ int const datashift(ROM_GETBITSHIFT(romp));
+ int const datamask(((1 << ROM_GETBITWIDTH(romp)) - 1) << datashift);
+ int numbytes(ROM_GETLENGTH(romp));
+ int const groupsize(ROM_GETGROUPSIZE(romp));
+ int skip(ROM_GETSKIPCOUNT(romp));
+ int const reversed(ROM_ISREVERSED(romp));
+ int const numgroups((numbytes + groupsize - 1) / groupsize);
+ u8 *base = region.base() + ROM_GETOFFSET(romp);
LOG("Loading ROM data: offs=%X len=%X mask=%02X group=%d skip=%d reverse=%d\n", ROM_GETOFFSET(romp), numbytes, datamask, groupsize, skip, reversed);
- /* make sure the length was an even multiple of the group size */
- if (numbytes % groupsize != 0)
- osd_printf_warning("Warning in RomModule definition: %s length not an even multiple of group size\n", ROM_GETNAME(romp));
+ // make sure the length was a whole multiple of the group size
+ if ((numbytes % groupsize) != 0)
+ osd_printf_warning("Warning in RomModule definition: %s length not an even multiple of group size\n", romp->name());
- /* make sure we only fill within the region space */
- if (ROM_GETOFFSET(romp) + numgroups * groupsize + (numgroups - 1) * skip > m_region->bytes())
- fatalerror("Error in RomModule definition: %s out of memory region space\n", ROM_GETNAME(romp));
+ // make sure we only fill within the region space
+ if (ROM_GETOFFSET(romp) + numgroups * groupsize + (numgroups - 1) * skip > region.bytes())
+ throw emu_fatalerror("Error in RomModule definition: %s out of memory region space\n", romp->name());
- /* make sure the length was valid */
+ // make sure the length was valid
if (numbytes == 0)
- fatalerror("Error in RomModule definition: %s has an invalid length\n", ROM_GETNAME(romp));
+ throw emu_fatalerror("Error in RomModule definition: %s has an invalid length\n", romp->name());
- /* special case for simple loads */
- if (datamask == 0xff && (groupsize == 1 || !reversed) && skip == 0)
- return rom_fread(base, numbytes, parent_region);
+ // special case for simple loads
+ if ((datamask == 0xff) && ((groupsize == 1) || !reversed) && (skip == 0))
+ return rom_fread(file, base, numbytes, parent_region);
- /* use a temporary buffer for complex loads */
- tempbufsize = std::min(TEMPBUFFER_MAX_SIZE, numbytes);
- std::vector<u8> tempbuf(tempbufsize);
+ // use a temporary buffer for complex loads
+ u32 const tempbufsize(std::min(TEMPBUFFER_MAX_SIZE, numbytes));
+ std::unique_ptr<u8 []> const tempbuf(new u8 [tempbufsize]);
- /* chunky reads for complex loads */
+ // chunky reads for complex loads
skip += groupsize;
while (numbytes > 0)
{
- int evengroupcount = (tempbufsize / groupsize) * groupsize;
- int bytesleft = (numbytes > evengroupcount) ? evengroupcount : numbytes;
- u8 *bufptr = &tempbuf[0];
+ int evengroupcount((tempbufsize / groupsize) * groupsize);
+ int bytesleft((numbytes > evengroupcount) ? evengroupcount : numbytes);
+ u8 *bufptr(tempbuf.get());
- /* read as much as we can */
+ // read as much as we can
LOG(" Reading %X bytes into buffer\n", bytesleft);
- if (rom_fread(bufptr, bytesleft, parent_region) != bytesleft)
+ if (rom_fread(file, bufptr, bytesleft, parent_region) != bytesleft)
return 0;
numbytes -= bytesleft;
LOG(" Copying to %p\n", base);
- /* unmasked cases */
if (datamask == 0xff)
{
- /* non-grouped data */
+ // unmasked cases
if (groupsize == 1)
- for (i = 0; i < bytesleft; i++, base += skip)
+ {
+ // non-grouped data
+ for (int i = 0; i < bytesleft; i++, base += skip)
*base = *bufptr++;
-
- /* grouped data -- non-reversed case */
+ }
else if (!reversed)
+ {
+ // grouped data -- non-reversed case
while (bytesleft)
{
- for (i = 0; i < groupsize && bytesleft; i++, bytesleft--)
+ for (int i = 0; i < groupsize && bytesleft; i++, bytesleft--)
base[i] = *bufptr++;
base += skip;
}
-
- /* grouped data -- reversed case */
+ }
else
+ {
+ // grouped data -- reversed case
while (bytesleft)
{
- for (i = groupsize - 1; i >= 0 && bytesleft; i--, bytesleft--)
+ for (int i = groupsize - 1; i >= 0 && bytesleft; i--, bytesleft--)
base[i] = *bufptr++;
base += skip;
}
+ }
}
-
- /* masked cases */
else
{
- /* non-grouped data */
+ // masked cases
if (groupsize == 1)
- for (i = 0; i < bytesleft; i++, base += skip)
+ {
+ // non-grouped data
+ for (int i = 0; i < bytesleft; i++, base += skip)
*base = (*base & ~datamask) | ((*bufptr++ << datashift) & datamask);
-
- /* grouped data -- non-reversed case */
+ }
else if (!reversed)
+ {
+ // grouped data -- non-reversed case
while (bytesleft)
{
- for (i = 0; i < groupsize && bytesleft; i++, bytesleft--)
+ for (int i = 0; i < groupsize && bytesleft; i++, bytesleft--)
base[i] = (base[i] & ~datamask) | ((*bufptr++ << datashift) & datamask);
base += skip;
}
-
- /* grouped data -- reversed case */
+ }
else
+ {
+ // grouped data -- reversed case
while (bytesleft)
{
- for (i = groupsize - 1; i >= 0 && bytesleft; i--, bytesleft--)
+ for (int i = groupsize - 1; i >= 0 && bytesleft; i--, bytesleft--)
base[i] = (base[i] & ~datamask) | ((*bufptr++ << datashift) & datamask);
base += skip;
}
+ }
}
}
@@ -782,22 +928,22 @@ int rom_load_manager::read_rom_data(const rom_entry *parent_region, const rom_en
fill_rom_data - fill a region of ROM space
-------------------------------------------------*/
-void rom_load_manager::fill_rom_data(const rom_entry *romp)
+void rom_load_manager::fill_rom_data(memory_region &region, const rom_entry *romp)
{
u32 numbytes = ROM_GETLENGTH(romp);
int skip = ROM_GETSKIPCOUNT(romp);
- u8 *base = m_region->base() + ROM_GETOFFSET(romp);
+ u8 *base = region.base() + ROM_GETOFFSET(romp);
// make sure we fill within the region space
- if (ROM_GETOFFSET(romp) + numbytes > m_region->bytes())
- fatalerror("Error in RomModule definition: FILL out of memory region space\n");
+ if (ROM_GETOFFSET(romp) + numbytes > region.bytes())
+ throw emu_fatalerror("Error in RomModule definition: FILL out of memory region space\n");
// make sure the length was valid
if (numbytes == 0)
- fatalerror("Error in RomModule definition: FILL has an invalid length\n");
+ throw emu_fatalerror("Error in RomModule definition: FILL has an invalid length\n");
// for fill bytes, the byte that gets filled is the first byte of the hashdata string
- u8 fill_byte = u8(strtol(ROM_GETHASHDATA(romp), nullptr, 0));
+ u8 fill_byte = u8(strtol(romp->hashdata().c_str(), nullptr, 0));
// fill the data (filling value is stored in place of the hashdata)
if(skip != 0)
@@ -814,32 +960,32 @@ void rom_load_manager::fill_rom_data(const rom_entry *romp)
copy_rom_data - copy a region of ROM space
-------------------------------------------------*/
-void rom_load_manager::copy_rom_data(const rom_entry *romp)
+void rom_load_manager::copy_rom_data(device_t &device, memory_region &region, const rom_entry *romp)
{
- u8 *base = m_region->base() + ROM_GETOFFSET(romp);
- const char *srcrgntag = ROM_GETNAME(romp);
+ u8 *base = region.base() + ROM_GETOFFSET(romp);
+ const std::string srcrgntag = device.subtag(romp->name());
u32 numbytes = ROM_GETLENGTH(romp);
- u32 srcoffs = u32(strtol(ROM_GETHASHDATA(romp), nullptr, 0)); /* srcoffset in place of hashdata */
+ u32 srcoffs = u32(strtol(romp->hashdata().c_str(), nullptr, 0)); /* srcoffset in place of hashdata */
/* make sure we copy within the region space */
- if (ROM_GETOFFSET(romp) + numbytes > m_region->bytes())
- fatalerror("Error in RomModule definition: COPY out of target memory region space\n");
+ if (ROM_GETOFFSET(romp) + numbytes > region.bytes())
+ throw emu_fatalerror("Error in RomModule definition: COPY out of target memory region space\n");
/* make sure the length was valid */
if (numbytes == 0)
- fatalerror("Error in RomModule definition: COPY has an invalid length\n");
+ throw emu_fatalerror("Error in RomModule definition: COPY has an invalid length\n");
/* make sure the source was valid */
- memory_region *region = machine().root_device().memregion(srcrgntag);
- if (region == nullptr)
- fatalerror("Error in RomModule definition: COPY from an invalid region\n");
+ memory_region *src = machine().root_device().memregion(srcrgntag);
+ if (!src)
+ throw emu_fatalerror("Error in RomModule definition: COPY from an invalid region\n");
/* make sure we find within the region space */
- if (srcoffs + numbytes > region->bytes())
- fatalerror("Error in RomModule definition: COPY out of source memory region space\n");
+ if (srcoffs + numbytes > src->bytes())
+ throw emu_fatalerror("Error in RomModule definition: COPY out of source memory region space\n");
/* fill the data */
- memcpy(base, region->base() + srcoffs, numbytes);
+ memcpy(base, src->base() + srcoffs, numbytes);
}
@@ -848,56 +994,70 @@ void rom_load_manager::copy_rom_data(const rom_entry *romp)
for a region
-------------------------------------------------*/
-void rom_load_manager::process_rom_entries(const char *regiontag, const rom_entry *parent_region, const rom_entry *romp, device_t *device, bool from_list)
+void rom_load_manager::process_rom_entries(
+ device_t &device,
+ const std::vector<std::string> &searchpath,
+ u8 bios,
+ memory_region &region,
+ const rom_entry *parent_region,
+ const rom_entry *romp,
+ bool from_list)
{
u32 lastflags = 0;
+ std::vector<std::string> tried_file_names;
- /* loop until we hit the end of this region */
+ // loop until we hit the end of this region
while (!ROMENTRY_ISREGIONEND(romp))
{
+ tried_file_names.clear();
+
if (ROMENTRY_ISCONTINUE(romp))
- fatalerror("Error in RomModule definition: ROM_CONTINUE not preceded by ROM_LOAD\n");
+ throw emu_fatalerror("Error in RomModule definition: ROM_CONTINUE not preceded by ROM_LOAD\n");
if (ROMENTRY_ISIGNORE(romp))
- fatalerror("Error in RomModule definition: ROM_IGNORE not preceded by ROM_LOAD\n");
+ throw emu_fatalerror("Error in RomModule definition: ROM_IGNORE not preceded by ROM_LOAD\n");
if (ROMENTRY_ISRELOAD(romp))
- fatalerror("Error in RomModule definition: ROM_RELOAD not preceded by ROM_LOAD\n");
+ throw emu_fatalerror("Error in RomModule definition: ROM_RELOAD not preceded by ROM_LOAD\n");
if (ROMENTRY_ISFILL(romp))
{
- if (!ROM_GETBIOSFLAGS(romp) || ROM_GETBIOSFLAGS(romp) == device->system_bios())
- fill_rom_data(romp);
+ if (!ROM_GETBIOSFLAGS(romp) || (ROM_GETBIOSFLAGS(romp) == bios))
+ fill_rom_data(region, romp);
romp++;
}
else if (ROMENTRY_ISCOPY(romp))
{
- copy_rom_data(romp++);
+ copy_rom_data(device, region, romp++);
}
else if (ROMENTRY_ISFILE(romp))
{
- /* handle files */
- int irrelevantbios = (ROM_GETBIOSFLAGS(romp) != 0 && ROM_GETBIOSFLAGS(romp) != device->system_bios());
- const rom_entry *baserom = romp;
+ // handle files
+ bool const irrelevantbios = (ROM_GETBIOSFLAGS(romp) != 0) && (ROM_GETBIOSFLAGS(romp) != bios);
+ rom_entry const *baserom = romp;
int explength = 0;
- /* open the file if it is a non-BIOS or matches the current BIOS */
+ // open the file if it is a non-BIOS or matches the current BIOS
LOG("Opening ROM file: %s\n", ROM_GETNAME(romp));
- std::string tried_file_names;
- if (!irrelevantbios && !open_rom_file(regiontag, romp, tried_file_names, from_list))
- handle_missing_file(romp, tried_file_names, CHDERR_NONE);
+ std::unique_ptr<emu_file> file;
+ if (!irrelevantbios)
+ {
+ file = open_rom_file(searchpath, romp, tried_file_names, from_list);
+ if (!file)
+ handle_missing_file(romp, tried_file_names, std::error_condition());
+ }
- /* loop until we run out of reloads */
+ // loop until we run out of reloads
do
{
- /* loop until we run out of continues/ignores */
+ // loop until we run out of continues/ignores
do
{
rom_entry modified_romp = *romp++;
//int readresult;
- /* handle flag inheritance */
+ // handle flag inheritance
if (!ROM_INHERITSFLAGS(&modified_romp))
lastflags = modified_romp.get_flags();
else
@@ -905,33 +1065,33 @@ void rom_load_manager::process_rom_entries(const char *regiontag, const rom_entr
explength += ROM_GETLENGTH(&modified_romp);
- /* attempt to read using the modified entry */
+ // attempt to read using the modified entry
if (!ROMENTRY_ISIGNORE(&modified_romp) && !irrelevantbios)
- /*readresult = */read_rom_data(parent_region, &modified_romp);
+ /*readresult = */read_rom_data(file.get(), region, parent_region, &modified_romp);
}
while (ROMENTRY_ISCONTINUE(romp) || ROMENTRY_ISIGNORE(romp));
- /* if this was the first use of this file, verify the length and CRC */
+ // if this was the first use of this file, verify the length and CRC
if (baserom)
{
LOG("Verifying length (%X) and checksums\n", explength);
- verify_length_and_hash(ROM_GETNAME(baserom), explength, util::hash_collection(ROM_GETHASHDATA(baserom)));
+ verify_length_and_hash(file.get(), baserom->name(), explength, util::hash_collection(baserom->hashdata()));
LOG("Verify finished\n");
}
- /* reseek to the start and clear the baserom so we don't reverify */
- if (m_file != nullptr)
- m_file->seek(0, SEEK_SET);
+ // re-seek to the start and clear the baserom so we don't reverify
+ if (file)
+ file->seek(0, SEEK_SET);
baserom = nullptr;
explength = 0;
}
while (ROMENTRY_ISRELOAD(romp));
- /* close the file */
- if (m_file != nullptr)
+ // close the file
+ if (file)
{
LOG("Closing ROM file\n");
- m_file = nullptr;
+ file.reset();
}
}
else
@@ -943,221 +1103,51 @@ void rom_load_manager::process_rom_entries(const char *regiontag, const rom_entr
/*-------------------------------------------------
- open_disk_image - open a disk image,
- searching up the parent and loading by
- checksum
--------------------------------------------------*/
-
-int open_disk_image(emu_options &options, const game_driver *gamedrv, const rom_entry *romp, chd_file &image_chd, const char *locationtag)
-{
- emu_file image_file(options.media_path(), OPEN_FLAG_READ);
- const rom_entry *region, *rom;
- osd_file::error filerr;
- chd_error err;
-
- /* attempt to open the properly named file, scanning up through parent directories */
- filerr = osd_file::error::NOT_FOUND;
- for (int searchdrv = driver_list::find(*gamedrv); searchdrv != -1 && filerr != osd_file::error::NONE; searchdrv = driver_list::clone(searchdrv))
- filerr = common_process_file(options, driver_list::driver(searchdrv).name, ".chd", romp, image_file);
-
- if (filerr != osd_file::error::NONE)
- filerr = common_process_file(options, nullptr, ".chd", romp, image_file);
-
- /* look for the disk in the locationtag too */
- if (filerr != osd_file::error::NONE && locationtag != nullptr)
- {
- // check if we are dealing with softwarelists. if so, locationtag
- // is actually a concatenation of: listname + setname + parentname
- // separated by '%' (parentname being present only for clones)
- std::string tag1(locationtag), tag2, tag3, tag4, tag5;
- bool is_list = false;
- bool has_parent = false;
-
- int separator1 = tag1.find_first_of('%');
- if (separator1 != -1)
- {
- is_list = true;
-
- // we are loading through softlists, split the listname from the regiontag
- tag4.assign(tag1.substr(separator1 + 1, tag1.length() - separator1 + 1));
- tag1.erase(separator1, tag1.length() - separator1);
- tag1.append(PATH_SEPARATOR);
-
- // check if we are loading a clone (if this is the case also tag1 have a separator '%')
- int separator2 = tag4.find_first_of('%');
- if (separator2 != -1)
- {
- has_parent = true;
-
- // we are loading a clone through softlists, split the setname from the parentname
- tag5.assign(tag4.substr(separator2 + 1, tag4.length() - separator2 + 1));
- tag4.erase(separator2, tag4.length() - separator2);
- }
-
- // prepare locations where we have to load from: list/parentname (if any) & list/clonename
- std::string swlist(tag1);
- tag2.assign(swlist.append(tag4));
- if (has_parent)
- {
- swlist.assign(tag1);
- tag3.assign(swlist.append(tag5));
- }
- }
-
- if (tag5.find_first_of('%') != -1)
- fatalerror("We do not support clones of clones!\n");
-
- // try to load from the available location(s):
- // - if we are not using lists, we have locationtag only;
- // - if we are using lists, we have: list/clonename, list/parentname, clonename, parentname
- if (!is_list)
- filerr = common_process_file(options, locationtag, ".chd", romp, image_file);
- else
- {
- // try to load from list/setname
- if ((filerr != osd_file::error::NONE) && (tag2.c_str() != nullptr))
- filerr = common_process_file(options, tag2.c_str(), ".chd", romp, image_file);
- // try to load from list/parentname (if any)
- if ((filerr != osd_file::error::NONE) && has_parent && (tag3.c_str() != nullptr))
- filerr = common_process_file(options, tag3.c_str(), ".chd", romp, image_file);
- // try to load from setname
- if ((filerr != osd_file::error::NONE) && (tag4.c_str() != nullptr))
- filerr = common_process_file(options, tag4.c_str(), ".chd", romp, image_file);
- // try to load from parentname (if any)
- if ((filerr != osd_file::error::NONE) && has_parent && (tag5.c_str() != nullptr))
- filerr = common_process_file(options, tag5.c_str(), ".chd", romp, image_file);
- // only for CHD we also try to load from list/
- if ((filerr != osd_file::error::NONE) && (tag1.c_str() != nullptr))
- {
- tag1.erase(tag1.length() - 1, 1); // remove the PATH_SEPARATOR
- filerr = common_process_file(options, tag1.c_str(), ".chd", romp, image_file);
- }
- }
- }
-
- /* did the file open succeed? */
- if (filerr == osd_file::error::NONE)
- {
- std::string fullpath(image_file.fullpath());
- image_file.close();
-
- /* try to open the CHD */
- err = image_chd.open(fullpath.c_str());
- if (err == CHDERR_NONE)
- return err;
- }
- else
- err = CHDERR_FILE_NOT_FOUND;
-
- // Otherwise, look at our parents for a CHD with an identical checksum
- // and try to open that
- //
- // An example of a system that requires this is src/mame/drivers/ksys673.cpp, that has declarations like this:
- // ...
- // DISK_IMAGE_READONLY("889aa", 0, BAD_DUMP SHA1(0b567bf2f03ee8089e0b021ea502a53b3f6fe7ac))
- // ...
- // DISK_IMAGE_READONLY("889ea", 0, BAD_DUMP SHA1(0b567bf2f03ee8089e0b021ea502a53b3f6fe7ac))
- // ...
- // DISK_IMAGE_READONLY("889ja", 0, BAD_DUMP SHA1(0b567bf2f03ee8089e0b021ea502a53b3f6fe7ac))
- // ...
- // DISK_IMAGE_READONLY("889ua", 0, BAD_DUMP SHA1(0b567bf2f03ee8089e0b021ea502a53b3f6fe7ac))
- // ...
- util::hash_collection romphashes(ROM_GETHASHDATA(romp));
- for (int drv = driver_list::find(*gamedrv); drv != -1; drv = driver_list::clone(drv))
- {
- const game_driver &current_driver(driver_list::driver(drv));
-
- // Create a single use emu_option structure for the purposes of this lookup, just
- // carrying forward the options that are necessary for CHD lookup. This is because the
- // options passed to us may have slot/image configurations that are "poisonous" for these
- // other drivers
- //
- // A side effect of this approach is that the "dragnet" to find CHDs with identical hashes
- // will only find CHDs for the default configuration. I believe that this in practice will
- // be acceptable.
- emu_options driver_specific_options;
- driver_specific_options.set_system_name(current_driver.name);
- driver_specific_options.set_value(OPTION_MEDIAPATH, options.media_path(), OPTION_PRIORITY_DEFAULT);
- driver_specific_options.set_value(OPTION_DIFF_DIRECTORY, options.diff_directory(), OPTION_PRIORITY_DEFAULT);
-
- // Now that we have an emu_options structure properly set up, we can create a machine_config
- machine_config config(current_driver, driver_specific_options);
-
- for (device_t &device : device_iterator(config.root_device()))
- for (region = rom_first_region(device); region != nullptr; region = rom_next_region(region))
- if (ROMREGION_ISDISKDATA(region))
- for (rom = rom_first_file(region); rom != nullptr; rom = rom_next_file(rom))
-
- // Look for a differing name but with the same hash data
- if (strcmp(ROM_GETNAME(romp), ROM_GETNAME(rom)) != 0 &&
- romphashes == util::hash_collection(ROM_GETHASHDATA(rom)))
- {
- // Attempt to open the properly named file, scanning up through parent directories
- filerr = osd_file::error::NOT_FOUND;
- for (int searchdrv = drv; searchdrv != -1 && filerr != osd_file::error::NONE; searchdrv = driver_list::clone(searchdrv))
- filerr = common_process_file(driver_specific_options, driver_list::driver(searchdrv).name, ".chd", rom, image_file);
-
- if (filerr != osd_file::error::NONE)
- filerr = common_process_file(driver_specific_options, nullptr, ".chd", rom, image_file);
-
- // Did the file open succeed?
- if (filerr == osd_file::error::NONE)
- {
- std::string fullpath(image_file.fullpath());
- image_file.close();
-
- // try to open the CHD
- err = image_chd.open(fullpath.c_str());
- if (err == CHDERR_NONE)
- return err;
- }
- }
- }
- return err;
-}
-
-
-/*-------------------------------------------------
open_disk_diff - open a DISK diff file
-------------------------------------------------*/
-chd_error rom_load_manager::open_disk_diff(emu_options &options, const rom_entry *romp, chd_file &source, chd_file &diff_chd)
+std::error_condition rom_load_manager::open_disk_diff(
+ emu_options &options,
+ const rom_entry *romp,
+ chd_file &source,
+ chd_file &diff_chd)
{
- std::string fname = std::string(ROM_GETNAME(romp)).append(".dif");
+ // TODO: use system name and/or software list name in the path - the current setup doesn't scale
+ std::string fname = romp->name() + ".dif";
- /* try to open the diff */
+ // try to open the diff
LOG("Opening differencing image file: %s\n", fname.c_str());
emu_file diff_file(options.diff_directory(), OPEN_FLAG_READ | OPEN_FLAG_WRITE);
- osd_file::error filerr = diff_file.open(fname.c_str());
- if (filerr == osd_file::error::NONE)
+ std::error_condition filerr = diff_file.open(fname);
+ if (!filerr)
{
std::string fullpath(diff_file.fullpath());
diff_file.close();
LOG("Opening differencing image file: %s\n", fullpath.c_str());
- return diff_chd.open(fullpath.c_str(), true, &source);
+ return diff_chd.open(fullpath, true, &source);
}
- /* didn't work; try creating it instead */
+ // didn't work; try creating it instead
LOG("Creating differencing image: %s\n", fname.c_str());
diff_file.set_openflags(OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
- filerr = diff_file.open(fname.c_str());
- if (filerr == osd_file::error::NONE)
+ filerr = diff_file.open(fname);
+ if (!filerr)
{
std::string fullpath(diff_file.fullpath());
diff_file.close();
- /* create the CHD */
+ // create the CHD
LOG("Creating differencing image file: %s\n", fullpath.c_str());
chd_codec_type compression[4] = { CHD_CODEC_NONE };
- chd_error err = diff_chd.create(fullpath.c_str(), source.logical_bytes(), source.hunk_bytes(), compression, source);
- if (err != CHDERR_NONE)
+ std::error_condition err = diff_chd.create(fullpath, source.logical_bytes(), source.hunk_bytes(), compression, source);
+ if (err)
return err;
return diff_chd.clone_all_metadata(source);
}
- return CHDERR_FILE_NOT_FOUND;
+ return std::errc::no_such_file_or_directory;
}
@@ -1166,41 +1156,55 @@ chd_error rom_load_manager::open_disk_diff(emu_options &options, const rom_entry
for a region
-------------------------------------------------*/
-void rom_load_manager::process_disk_entries(const char *regiontag, const rom_entry *parent_region, const rom_entry *romp, const char *locationtag)
+void rom_load_manager::process_disk_entries(
+ search_paths searchpath,
+ std::string_view regiontag,
+ rom_entry const *romp,
+ std::function<rom_entry const * ()> next_parent,
+ chd_file::open_parent_func const &open_parent)
{
- /* remove existing disk entries for this region */
- m_chd_list.erase(std::remove_if(m_chd_list.begin(), m_chd_list.end(),
- [regiontag](std::unique_ptr<open_chd> &chd){ return !strcmp(chd->region(), regiontag); }), m_chd_list.end());
-
- /* loop until we hit the end of this region */
+ // remove existing disk entries for this region
+ m_chd_list.erase(
+ std::remove_if(
+ m_chd_list.begin(),
+ m_chd_list.end(),
+ [&regiontag] (std::unique_ptr<open_chd> &chd) { return chd->region() == regiontag; }),
+ m_chd_list.end());
+
+ // loop until we hit the end of this region
for ( ; !ROMENTRY_ISREGIONEND(romp); romp++)
{
- /* handle files */
+ // handle files
if (ROMENTRY_ISFILE(romp))
{
- auto chd = std::make_unique<open_chd>(regiontag);
-
- util::hash_collection hashes(ROM_GETHASHDATA(romp));
- chd_error err;
+ auto chd(std::make_unique<open_chd>(regiontag));
+ std::error_condition err;
- /* make the filename of the source */
- std::string filename = std::string(ROM_GETNAME(romp)).append(".chd");
+ // make the filename of the source
+ std::string const filename(romp->name() + ".chd");
- /* first open the source drive */
+ // first open the reference disk image
LOG("Opening disk image: %s\n", filename.c_str());
- err = chd_error(open_disk_image(machine().options(), &machine().system(), romp, chd->orig_chd(), locationtag));
- if (err != CHDERR_NONE)
+ err = do_open_disk(machine().options(), searchpath, romp, chd->orig_chd(), next_parent, open_parent);
+ if (!err && chd->orig_chd().parent_missing())
+ err = chd_file::error::REQUIRES_PARENT;
+ if (err)
{
- handle_missing_file(romp, std::string(), err);
- chd = nullptr;
+ std::vector<std::string> tried;
+ for (auto const &paths : searchpath)
+ {
+ for (std::string const &path : paths.get())
+ tried.emplace_back(path);
+ }
+ handle_missing_file(romp, tried, err);
+ chd.reset();
continue;
}
- /* get the header and extract the SHA1 */
+ // get the header and verify the SHA1 digest
util::hash_collection acthashes;
acthashes.add_sha1(chd->orig_chd().sha1());
-
- /* verify the hash */
+ util::hash_collection const hashes(romp->hashdata());
if (hashes != acthashes)
{
m_errorstring.append(string_format("%s WRONG CHECKSUMS:\n", filename));
@@ -1213,34 +1217,100 @@ void rom_load_manager::process_disk_entries(const char *regiontag, const rom_ent
m_knownbad++;
}
- /* if not read-only, make the diff file */
+ // if not read-only, open or create the diff file
if (!DISK_ISREADONLY(romp))
{
- /* try to open or create the diff */
err = open_disk_diff(machine().options(), romp, chd->orig_chd(), chd->diff_chd());
- if (err != CHDERR_NONE)
+ if (err)
{
- m_errorstring.append(string_format("%s DIFF CHD ERROR: %s\n", filename, chd_file::error_string(err)));
+ m_errorstring.append(string_format("%s DIFF CHD ERROR: %s\n", filename, err.message()));
m_errors++;
- chd = nullptr;
+ chd.reset();
continue;
}
}
- /* we're okay, add to the list of disks */
+ // we're okay, add to the list of disks
LOG("Assigning to handle %d\n", DISK_GETINDEX(romp));
- m_chd_list.push_back(std::move(chd));
+ m_chd_list.emplace_back(std::move(chd));
}
}
}
/*-------------------------------------------------
+ get_software_searchpath - get search path
+ for a software list item
+-------------------------------------------------*/
+
+std::vector<std::string> rom_load_manager::get_software_searchpath(software_list_device &swlist, const software_info &swinfo)
+{
+ std::vector<software_info const *> parents;
+ return make_software_searchpath(swlist, swinfo, parents);
+}
+
+
+/*-------------------------------------------------
+ open_disk_image - open a disk image for a
+ device
+-------------------------------------------------*/
+
+std::error_condition rom_load_manager::open_disk_image(
+ emu_options &options,
+ const device_t &device,
+ const rom_entry *romp,
+ chd_file &image_chd)
+{
+ const std::vector<std::string> searchpath(device.searchpath());
+
+ driver_device const *const driver(dynamic_cast<driver_device const *>(&device));
+ std::function<const rom_entry * ()> next_parent;
+ if (driver)
+ next_parent = next_parent_system(driver->system());
+ else
+ next_parent = next_parent_device(device, options);
+ chd_file::open_parent_func open_parent(open_parent_disk(options, { searchpath }, next_parent));
+ std::error_condition const err(
+ do_open_disk(options, { searchpath }, romp, image_chd, std::move(next_parent), open_parent));
+ if (!err && image_chd.parent_missing())
+ return chd_file::error::REQUIRES_PARENT;
+ else
+ return err;
+}
+
+
+/*-------------------------------------------------
+ open_disk_image - open a disk image for a
+ software item
+-------------------------------------------------*/
+
+std::error_condition rom_load_manager::open_disk_image(
+ emu_options &options,
+ software_list_device &swlist,
+ const software_info &swinfo,
+ const rom_entry *romp,
+ chd_file &image_chd)
+{
+ std::vector<software_info const *> parents;
+ std::vector<std::string> searchpath(make_software_searchpath(swlist, swinfo, parents));
+ searchpath.emplace_back(swlist.list_name()); // look for loose disk images in software list directory
+ std::function<const rom_entry * ()> next_parent(next_parent_software(parents));
+ chd_file::open_parent_func open_parent(open_parent_disk(options, { searchpath }, next_parent));
+ std::error_condition const err(
+ do_open_disk(options, { searchpath }, romp, image_chd, std::move(next_parent), open_parent));
+ if (!err && image_chd.parent_missing())
+ return chd_file::error::REQUIRES_PARENT;
+ else
+ return err;
+}
+
+
+/*-------------------------------------------------
normalize_flags_for_device - modify the region
flags for the given device
-------------------------------------------------*/
-void rom_load_manager::normalize_flags_for_device(const char *rgntag, u8 &width, endianness_t &endian)
+void rom_load_manager::normalize_flags_for_device(std::string_view rgntag, u8 &width, endianness_t &endian)
{
device_t *device = machine().root_device().subdevice(rgntag);
device_memory_interface *memory;
@@ -1275,18 +1345,14 @@ void rom_load_manager::normalize_flags_for_device(const char *rgntag, u8 &width,
/*-------------------------------------------------
load_software_part_region - load a software part
- This is used by MESS when loading a piece of
+ This is used by MAME when loading a piece of
software. The code should be merged with
process_region_list or updated to use a slight
more general process_region_list.
-------------------------------------------------*/
-void rom_load_manager::load_software_part_region(device_t &device, software_list_device &swlist, const char *swname, const rom_entry *start_region)
+void rom_load_manager::load_software_part_region(device_t &device, software_list_device &swlist, std::string_view swname, const rom_entry *start_region)
{
- std::string locationtag(swlist.list_name()), breakstr("%");
- const rom_entry *region;
- std::string regiontag;
-
m_errorstring.clear();
m_softwarningstring.clear();
@@ -1294,100 +1360,105 @@ void rom_load_manager::load_software_part_region(device_t &device, software_list
m_romstotalsize = 0;
m_romsloadedsize = 0;
- const software_info *swinfo = swlist.find(swname);
- if (swinfo != nullptr)
+ std::vector<const software_info *> parents;
+ std::vector<std::string> swsearch, disksearch;
+ const software_info *const swinfo = swlist.find(std::string(swname));
+ if (swinfo)
{
- u32 supported = swinfo->supported();
- if (supported == SOFTWARE_SUPPORTED_PARTIAL)
+ // display a warning for unsupported software
+ // TODO: list supported clones like we do for machines?
+ if (swinfo->supported() == software_support::PARTIALLY_SUPPORTED)
{
m_errorstring.append(string_format("WARNING: support for software %s (in list %s) is only partial\n", swname, swlist.list_name()));
m_softwarningstring.append(string_format("Support for software %s (in list %s) is only partial\n", swname, swlist.list_name()));
}
- if (supported == SOFTWARE_SUPPORTED_NO)
+ else if (swinfo->supported() == software_support::UNSUPPORTED)
{
m_errorstring.append(string_format("WARNING: support for software %s (in list %s) is only preliminary\n", swname, swlist.list_name()));
m_softwarningstring.append(string_format("Support for software %s (in list %s) is only preliminary\n", swname, swlist.list_name()));
}
- // attempt reading up the chain through the parents and create a locationtag std::string in the format
- // " swlist % clonename % parentname "
- // open_rom_file contains the code to split the elements and to create paths to load from
-
- locationtag.append(breakstr);
-
- while (swinfo != nullptr)
- {
- locationtag.append(swinfo->shortname()).append(breakstr);
- swinfo = !swinfo->parentname().empty() ? swlist.find(swinfo->parentname().c_str()) : nullptr;
- }
- // strip the final '%'
- locationtag.erase(locationtag.length() - 1, 1);
+ // walk the chain of parents and add them to the search path
+ swsearch = make_software_searchpath(swlist, *swinfo, parents);
+ }
+ else
+ {
+ swsearch.emplace_back(util::string_format("%s" PATH_SEPARATOR "%s", swlist.list_name(), swname));
+ swsearch.emplace_back(swname);
}
+ // this is convenient for CD-only lists so you don't need an extra level of directories containing one file each
+ disksearch.emplace_back(swlist.list_name());
- /* loop until we hit the end */
- for (region = start_region; region != nullptr; region = rom_next_region(region))
+ // loop until we hit the end
+ std::function<const rom_entry * ()> next_parent;
+ chd_file::open_parent_func open_parent;
+ for (const rom_entry *region = start_region; region != nullptr; region = rom_next_region(region))
{
u32 regionlength = ROMREGION_GETLENGTH(region);
- regiontag = device.subtag(ROMREGION_GETTAG(region));
+ std::string regiontag = device.subtag(region->name());
LOG("Processing region \"%s\" (length=%X)\n", regiontag.c_str(), regionlength);
- /* the first entry must be a region */
+ // the first entry must be a region
assert(ROMENTRY_ISREGION(region));
- /* if this is a device region, override with the device width and endianness */
+ // if this is a device region, override with the device width and endianness
endianness_t endianness = ROMREGION_ISBIGENDIAN(region) ? ENDIANNESS_BIG : ENDIANNESS_LITTLE;
u8 width = ROMREGION_GETWIDTH(region) / 8;
- memory_region *memregion = machine().root_device().memregion(regiontag.c_str());
- if (memregion != nullptr)
+ memory_region *memregion = machine().root_device().memregion(regiontag);
+ if (memregion)
{
- normalize_flags_for_device(regiontag.c_str(), width, endianness);
+ normalize_flags_for_device(regiontag, width, endianness);
- /* clear old region (todo: should be moved to an image unload function) */
+ // clear old region (TODO: should be moved to an image unload function)
machine().memory().region_free(memregion->name());
}
- /* remember the base and length */
- m_region = machine().memory().region_alloc(regiontag.c_str(), regionlength, width, endianness);
- LOG("Allocated %X bytes @ %p\n", m_region->bytes(), m_region->base());
-
- /* clear the region if it's requested */
- if (ROMREGION_ISERASE(region))
- memset(m_region->base(), ROMREGION_GETERASEVAL(region), m_region->bytes());
-
- /* or if it's sufficiently small (<= 4MB) */
- else if (m_region->bytes() <= 0x400000)
- memset(m_region->base(), 0, m_region->bytes());
+ // remember the base and length
+ memregion = machine().memory().region_alloc(regiontag, regionlength, width, endianness);
+ LOG("Allocated %X bytes @ %p\n", memregion->bytes(), memregion->base());
+ if (ROMREGION_ISERASE(region)) // clear the region if it's requested
+ memset(memregion->base(), ROMREGION_GETERASEVAL(region), memregion->bytes());
+ else if (memregion->bytes() <= 0x400000) // or if it's sufficiently small (<= 4MB)
+ memset(memregion->base(), 0, memregion->bytes());
#ifdef MAME_DEBUG
- /* if we're debugging, fill region with random data to catch errors */
- else
- fill_random(m_region->base(), m_region->bytes());
+ else // if we're debugging, fill region with random data to catch errors
+ fill_random(memregion->base(), memregion->bytes());
#endif
- /* update total number of roms */
+ // update total number of roms
for (const rom_entry *rom = rom_first_file(region); rom != nullptr; rom = rom_next_file(rom))
{
m_romstotal++;
m_romstotalsize += rom_file_size(rom);
}
- /* now process the entries in the region */
+ // now process the entries in the region
if (ROMREGION_ISROMDATA(region))
- process_rom_entries(locationtag.c_str(), region, region + 1, &device, true);
+ {
+ process_rom_entries(device, swsearch, 0U, *memregion, region, region + 1, true);
+ }
else if (ROMREGION_ISDISKDATA(region))
- process_disk_entries(regiontag.c_str(), region, region + 1, locationtag.c_str());
+ {
+ if (!next_parent)
+ {
+ if (!parents.empty())
+ next_parent = next_parent_software(parents);
+ else
+ next_parent = [] () { return nullptr; };
+ open_parent = open_parent_disk(machine().options(), { swsearch, disksearch }, next_parent);
+ }
+ process_disk_entries({ swsearch, disksearch }, regiontag, region + 1, next_parent, open_parent);
+ }
}
- /* now go back and post-process all the regions */
- for (region = start_region; region != nullptr; region = rom_next_region(region))
- {
- regiontag = device.subtag(ROMREGION_GETTAG(region));
- region_post_process(regiontag.c_str(), ROMREGION_ISINVERTED(region));
- }
+ // now go back and post-process all the regions
+ for (const rom_entry *region = start_region; region != nullptr; region = rom_next_region(region))
+ region_post_process(device.memregion(region->name()), ROMREGION_ISINVERTED(region));
- /* display the results and exit */
+ // display the results and exit
display_rom_load_results(true);
}
@@ -1398,68 +1469,83 @@ void rom_load_manager::load_software_part_region(device_t &device, software_list
void rom_load_manager::process_region_list()
{
- std::string regiontag;
-
- /* loop until we hit the end */
- device_iterator deviter(machine().root_device());
+ // loop until we hit the end
+ device_enumerator deviter(machine().root_device());
+ std::vector<std::string> searchpath;
for (device_t &device : deviter)
+ {
+ searchpath.clear();
+ std::function<const rom_entry * ()> next_parent;
+ chd_file::open_parent_func open_parent;
for (const rom_entry *region = rom_first_region(device); region != nullptr; region = rom_next_region(region))
{
u32 regionlength = ROMREGION_GETLENGTH(region);
- regiontag = rom_region_name(device, region);
+ std::string regiontag = device.subtag(region->name());
LOG("Processing region \"%s\" (length=%X)\n", regiontag.c_str(), regionlength);
- /* the first entry must be a region */
+ // the first entry must be a region
assert(ROMENTRY_ISREGION(region));
if (ROMREGION_ISROMDATA(region))
{
- /* if this is a device region, override with the device width and endianness */
+ // if this is a device region, override with the device width and endianness
u8 width = ROMREGION_GETWIDTH(region) / 8;
endianness_t endianness = ROMREGION_ISBIGENDIAN(region) ? ENDIANNESS_BIG : ENDIANNESS_LITTLE;
- normalize_flags_for_device(regiontag.c_str(), width, endianness);
-
- /* remember the base and length */
- m_region = machine().memory().region_alloc(regiontag.c_str(), regionlength, width, endianness);
- LOG("Allocated %X bytes @ %p\n", m_region->bytes(), m_region->base());
+ normalize_flags_for_device(regiontag, width, endianness);
- /* clear the region if it's requested */
- if (ROMREGION_ISERASE(region))
- memset(m_region->base(), ROMREGION_GETERASEVAL(region), m_region->bytes());
-
- /* or if it's sufficiently small (<= 4MB) */
- else if (m_region->bytes() <= 0x400000)
- memset(m_region->base(), 0, m_region->bytes());
+ // remember the base and length
+ memory_region *const memregion = machine().memory().region_alloc(regiontag, regionlength, width, endianness);
+ LOG("Allocated %X bytes @ %p\n", memregion->bytes(), memregion->base());
+ if (ROMREGION_ISERASE(region)) // clear the region if it's requested
+ memset(memregion->base(), ROMREGION_GETERASEVAL(region), memregion->bytes());
+ else if (memregion->bytes() <= 0x400000) // or if it's sufficiently small (<= 4MB)
+ memset(memregion->base(), 0, memregion->bytes());
#ifdef MAME_DEBUG
- /* if we're debugging, fill region with random data to catch errors */
- else
- fill_random(m_region->base(), m_region->bytes());
+ else // if we're debugging, fill region with random data to catch errors
+ fill_random(memregion->base(), memregion->bytes());
#endif
- /* now process the entries in the region */
- process_rom_entries(device.shortname(), region, region + 1, &device, false);
+ // now process the entries in the region
+ if (searchpath.empty())
+ searchpath = device.searchpath();
+ assert(!searchpath.empty());
+ process_rom_entries(device, searchpath, device.system_bios(), *memregion, region, region + 1, false);
}
else if (ROMREGION_ISDISKDATA(region))
- process_disk_entries(regiontag.c_str(), region, region + 1, nullptr);
+ {
+ if (searchpath.empty())
+ searchpath = device.searchpath();
+ assert(!searchpath.empty());
+ if (!next_parent)
+ {
+ driver_device const *const driver(dynamic_cast<driver_device const *>(&device));
+ if (driver)
+ next_parent = next_parent_system(driver->system());
+ else
+ next_parent = next_parent_device(device, machine().options());
+ open_parent = open_parent_disk(machine().options(), { searchpath }, next_parent);
+ }
+ process_disk_entries({ searchpath }, regiontag, region + 1, next_parent, open_parent);
+ }
}
+ }
- /* now go back and post-process all the regions */
+ // now go back and post-process all the regions
for (device_t &device : deviter)
for (const rom_entry *region = rom_first_region(device); region != nullptr; region = rom_next_region(region))
- {
- regiontag = rom_region_name(device, region);
- region_post_process(regiontag.c_str(), ROMREGION_ISINVERTED(region));
- }
+ region_post_process(device.memregion(region->name()), ROMREGION_ISINVERTED(region));
- /* and finally register all per-game parameters */
+ // and finally register all per-game parameters
for (device_t &device : deviter)
+ {
for (const rom_entry *param = rom_first_parameter(device); param != nullptr; param = rom_next_parameter(param))
{
- regiontag = rom_parameter_name(device, param);
- machine().parameters().add(regiontag, rom_parameter_value(param));
+ std::string regiontag = device.subtag(param->name());
+ machine().parameters().add(regiontag, param->hashdata());
}
+ }
}
@@ -1470,10 +1556,20 @@ void rom_load_manager::process_region_list()
rom_load_manager::rom_load_manager(running_machine &machine)
: m_machine(machine)
+ , m_warnings(0)
+ , m_knownbad(0)
+ , m_errors(0)
+ , m_romsloaded(0)
+ , m_romstotal(0)
+ , m_romsloadedsize(0)
+ , m_romstotalsize(0)
+ , m_chd_list()
+ , m_errorstring()
+ , m_softwarningstring()
{
// figure out which BIOS we are using
- std::map<std::string, std::string> card_bios;
- for (device_t &device : device_iterator(machine.config().root_device()))
+ std::map<std::string_view, std::string> card_bios;
+ for (device_t &device : device_enumerator(machine.config().root_device()))
{
device_slot_interface const *const slot(dynamic_cast<device_slot_interface *>(&device));
if (slot)
@@ -1481,7 +1577,7 @@ rom_load_manager::rom_load_manager(running_machine &machine)
device_t const *const card(slot->get_card_device());
slot_option const &slot_opt(machine.options().slot_option(slot->slot_name()));
if (card && !slot_opt.bios().empty())
- card_bios.emplace(std::make_pair(std::string(card->tag()), slot_opt.bios()));
+ card_bios.emplace(card->tag(), slot_opt.bios());
}
if (device.rom_region())
@@ -1500,7 +1596,7 @@ rom_load_manager::rom_load_manager(running_machine &machine)
card_bios.erase(found);
}
}
- determine_bios_rom(device, specbios.c_str());
+ determine_bios_rom(device, specbios);
}
}