diff options
Diffstat (limited to 'src/emu/romload.cpp')
-rw-r--r-- | src/emu/romload.cpp | 1464 |
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 ®ion, + 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 ®ion, 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 ®ion, 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 ®ion, + 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 ¤t_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(), + [®iontag] (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); } } |