summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2023-10-20 05:47:15 +1100
committer Vas Crabb <vas@vastheman.com>2023-10-20 05:47:15 +1100
commitd1172bf710f2a7b1777ed7687f5ba65748d90ee9 (patch)
tree0df8d9465cf52b4727679a5cbdebe154ea71b7df /src
parent4dfc36ae47d77207045f218fbc11bfbbe32744ab (diff)
Allow clone CHDs to use parent CHDs as parents.
* util/chd.cpp: Allow caller to provide a helper for finding parent CHDs and expose (recursive) missing parent status. * emu/romload.cpp: Search parent systems/devices/software for parent CHDs on encountering a delta CHD. * emu/romload.cpp: Report error on delta CHDs when parent can't be found. * emu/romload.cpp: Check parents for matching CHDs with different names for devices as well as systems and software.
Diffstat (limited to 'src')
-rw-r--r--src/emu/romload.cpp250
-rw-r--r--src/emu/romload.h66
-rw-r--r--src/frontend/mame/audit.cpp3
-rw-r--r--src/lib/util/chd.cpp82
-rw-r--r--src/lib/util/chd.h31
5 files changed, 319 insertions, 113 deletions
diff --git a/src/emu/romload.cpp b/src/emu/romload.cpp
index c7053b9a3b7..5b76dfeefde 100644
--- a/src/emu/romload.cpp
+++ b/src/emu/romload.cpp
@@ -53,13 +53,41 @@ auto next_parent_system(game_driver const &system)
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[0];
+ return &roms.front();
+ }
+ };
+}
+
+
+auto next_parent_device(device_t const &device, emu_options &options)
+{
+ 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();
}
};
}
@@ -106,7 +134,13 @@ std::vector<std::string> make_software_searchpath(software_list_device &swlist,
}
-std::error_condition do_open_disk(const emu_options &options, std::initializer_list<std::reference_wrapper<const std::vector<std::string> > > searchpath, const rom_entry *romp, chd_file &chd, std::function<const rom_entry * ()> next_parent)
+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;
@@ -137,7 +171,7 @@ std::error_condition do_open_disk(const emu_options &options, std::initializer_l
{
fullpath = imgfile->fullpath();
imgfile.reset();
- result = chd.open(fullpath);
+ result = chd.open(fullpath, false, nullptr, open_parent);
}
}
@@ -159,10 +193,7 @@ std::error_condition do_open_disk(const emu_options &options, std::initializer_l
romp = nullptr;
break;
}
- while (ROMENTRY_ISPARAMETER(parent) || ROMENTRY_ISSYSTEM_BIOS(parent) || ROMENTRY_ISDEFAULT_BIOS(parent))
- ++parent;
- if (ROMENTRY_ISEND(parent))
- parent = nullptr;
+ parent = rom_first_region(parent);
}
else
{
@@ -183,6 +214,46 @@ std::error_condition do_open_disk(const emu_options &options, std::initializer_l
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);
+ 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
@@ -640,7 +711,11 @@ void rom_load_manager::region_post_process(memory_region *region, bool invert)
up the parent and loading by checksum
-------------------------------------------------*/
-std::unique_ptr<emu_file> rom_load_manager::open_rom_file(std::initializer_list<std::reference_wrapper<const std::vector<std::string> > > searchpath, const rom_entry *romp, std::vector<std::string> &tried_file_names, bool from_list)
+std::unique_ptr<emu_file> rom_load_manager::open_rom_file(
+ search_paths searchpath,
+ const rom_entry *romp,
+ std::vector<std::string> &tried_file_names,
+ bool from_list)
{
std::error_condition filerr = std::errc::no_such_file_or_directory;
u32 const romsize = rom_file_size(romp);
@@ -675,7 +750,13 @@ std::unique_ptr<emu_file> rom_load_manager::open_rom_file(std::initializer_list<
}
-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)
+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());
@@ -718,7 +799,11 @@ int rom_load_manager::rom_fread(emu_file *file, u8 *buffer, int length, const ro
entry
-------------------------------------------------*/
-int rom_load_manager::read_rom_data(emu_file *file, 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;
@@ -727,7 +812,7 @@ int rom_load_manager::read_rom_data(emu_file *file, const rom_entry *parent_regi
int skip = ROM_GETSKIPCOUNT(romp);
int reversed = ROM_ISREVERSED(romp);
int numgroups = (numbytes + groupsize - 1) / groupsize;
- u8 *base = m_region->base() + ROM_GETOFFSET(romp);
+ u8 *base = region.base() + ROM_GETOFFSET(romp);
u32 tempbufsize;
int i;
@@ -738,7 +823,7 @@ int rom_load_manager::read_rom_data(emu_file *file, const rom_entry *parent_regi
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())
+ 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 */
@@ -833,14 +918,14 @@ int rom_load_manager::read_rom_data(emu_file *file, const rom_entry *parent_regi
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())
+ 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
@@ -865,15 +950,15 @@ 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(memory_region &region, const rom_entry *romp)
{
- u8 *base = m_region->base() + ROM_GETOFFSET(romp);
+ u8 *base = region.base() + ROM_GETOFFSET(romp);
const std::string &srcrgntag = romp->name();
u32 numbytes = ROM_GETLENGTH(romp);
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())
+ 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 */
@@ -881,16 +966,16 @@ void rom_load_manager::copy_rom_data(const rom_entry *romp)
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)
+ 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())
+ 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);
}
@@ -899,7 +984,13 @@ void rom_load_manager::copy_rom_data(const rom_entry *romp)
for a region
-------------------------------------------------*/
-void rom_load_manager::process_rom_entries(std::initializer_list<std::reference_wrapper<const std::vector<std::string> > > searchpath, u8 bios, const rom_entry *parent_region, const rom_entry *romp, bool from_list)
+void rom_load_manager::process_rom_entries(
+ search_paths 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;
@@ -921,13 +1012,13 @@ void rom_load_manager::process_rom_entries(std::initializer_list<std::reference_
if (ROMENTRY_ISFILL(romp))
{
if (!ROM_GETBIOSFLAGS(romp) || (ROM_GETBIOSFLAGS(romp) == bios))
- fill_rom_data(romp);
+ fill_rom_data(region, romp);
romp++;
}
else if (ROMENTRY_ISCOPY(romp))
{
- copy_rom_data(romp++);
+ copy_rom_data(region, romp++);
}
else if (ROMENTRY_ISFILE(romp))
{
@@ -965,7 +1056,7 @@ void rom_load_manager::process_rom_entries(std::initializer_list<std::reference_
// attempt to read using the modified entry
if (!ROMENTRY_ISIGNORE(&modified_romp) && !irrelevantbios)
- /*readresult = */read_rom_data(file.get(), parent_region, &modified_romp);
+ /*readresult = */read_rom_data(file.get(), region, parent_region, &modified_romp);
}
while (ROMENTRY_ISCONTINUE(romp) || ROMENTRY_ISIGNORE(romp));
@@ -1004,7 +1095,11 @@ void rom_load_manager::process_rom_entries(std::initializer_list<std::reference_
open_disk_diff - open a DISK diff file
-------------------------------------------------*/
-std::error_condition 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)
{
// TODO: use system name and/or software list name in the path - the current setup doesn't scale
std::string fname = romp->name() + ".dif";
@@ -1050,11 +1145,20 @@ std::error_condition rom_load_manager::open_disk_diff(emu_options &options, cons
for a region
-------------------------------------------------*/
-void rom_load_manager::process_disk_entries(std::initializer_list<std::reference_wrapper<const std::vector<std::string> > > searchpath, std::string_view regiontag, const rom_entry *romp, std::function<const rom_entry * ()> next_parent)
+void rom_load_manager::process_disk_entries(
+ search_paths searchpath,
+ std::string_view regiontag,
+ const rom_entry *romp,
+ std::function<const rom_entry * ()> 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 chd->region() == regiontag; }), m_chd_list.end());
+ 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++)
@@ -1071,7 +1175,9 @@ void rom_load_manager::process_disk_entries(std::initializer_list<std::reference
/* first open the source drive */
// FIXME: we've lost the ability to search parents here
LOG("Opening disk image: %s\n", filename.c_str());
- err = do_open_disk(machine().options(), searchpath, romp, chd->orig_chd(), next_parent);
+ 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)
{
std::vector<std::string> tried;
@@ -1142,7 +1248,11 @@ std::vector<std::string> rom_load_manager::get_software_searchpath(software_list
device
-------------------------------------------------*/
-std::error_condition rom_load_manager::open_disk_image(const emu_options &options, const device_t &device, const rom_entry *romp, chd_file &image_chd)
+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());
@@ -1151,8 +1261,14 @@ std::error_condition rom_load_manager::open_disk_image(const emu_options &option
if (driver)
next_parent = next_parent_system(driver->system());
else
- next_parent = [] () { return nullptr; };
- return do_open_disk(options, { searchpath }, romp, image_chd, std::move(next_parent));
+ 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;
}
@@ -1161,12 +1277,24 @@ std::error_condition rom_load_manager::open_disk_image(const emu_options &option
software item
-------------------------------------------------*/
-std::error_condition rom_load_manager::open_disk_image(const emu_options &options, software_list_device &swlist, const software_info &swinfo, const rom_entry *romp, chd_file &image_chd)
+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);
+ 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
- return do_open_disk(options, { searchpath }, romp, image_chd, next_parent_software(parents));
+ 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;
}
@@ -1262,6 +1390,7 @@ void rom_load_manager::load_software_part_region(device_t &device, software_list
// 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);
@@ -1276,7 +1405,7 @@ void rom_load_manager::load_software_part_region(device_t &device, software_list
endianness_t endianness = ROMREGION_ISBIGENDIAN(region) ? ENDIANNESS_BIG : ENDIANNESS_LITTLE;
u8 width = ROMREGION_GETWIDTH(region) / 8;
memory_region *memregion = machine().root_device().memregion(regiontag);
- if (memregion != nullptr)
+ if (memregion)
{
normalize_flags_for_device(regiontag, width, endianness);
@@ -1285,16 +1414,16 @@ void rom_load_manager::load_software_part_region(device_t &device, software_list
}
// remember the base and length
- m_region = machine().memory().region_alloc(regiontag, regionlength, width, endianness);
- LOG("Allocated %X bytes @ %p\n", m_region->bytes(), m_region->base());
+ 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(m_region->base(), ROMREGION_GETERASEVAL(region), m_region->bytes());
- else if (m_region->bytes() <= 0x400000) // or if it's sufficiently small (<= 4MB)
- memset(m_region->base(), 0, m_region->bytes());
+ 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
else // if we're debugging, fill region with random data to catch errors
- fill_random(m_region->base(), m_region->bytes());
+ fill_random(memregion->base(), memregion->bytes());
#endif
// update total number of roms
@@ -1308,9 +1437,9 @@ void rom_load_manager::load_software_part_region(device_t &device, software_list
if (ROMREGION_ISROMDATA(region))
{
if (devsearch.empty())
- process_rom_entries({ swsearch }, 0U, region, region + 1, true);
+ process_rom_entries({ swsearch }, 0U, *memregion, region, region + 1, true);
else
- process_rom_entries({ swsearch, devsearch }, 0U, region, region + 1, true);
+ process_rom_entries({ swsearch, devsearch }, 0U, *memregion, region, region + 1, true);
}
else if (ROMREGION_ISDISKDATA(region))
{
@@ -1320,11 +1449,15 @@ void rom_load_manager::load_software_part_region(device_t &device, software_list
next_parent = next_parent_software(parents);
else
next_parent = [] () { return nullptr; };
+ if (devsearch.empty())
+ open_parent = open_parent_disk(machine().options(), { swsearch, disksearch }, next_parent);
+ else
+ open_parent = open_parent_disk(machine().options(), { swsearch, disksearch, devsearch }, next_parent);
}
if (devsearch.empty())
- process_disk_entries({ swsearch, disksearch }, regiontag, region + 1, next_parent);
+ process_disk_entries({ swsearch, disksearch }, regiontag, region + 1, next_parent, open_parent);
else
- process_disk_entries({ swsearch, disksearch, devsearch }, regiontag, region + 1, next_parent);
+ process_disk_entries({ swsearch, disksearch, devsearch }, regiontag, region + 1, next_parent, open_parent);
}
}
@@ -1350,6 +1483,7 @@ void rom_load_manager::process_region_list()
{
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);
@@ -1368,23 +1502,23 @@ void rom_load_manager::process_region_list()
normalize_flags_for_device(regiontag, width, endianness);
// remember the base and length
- m_region = machine().memory().region_alloc(regiontag, regionlength, width, endianness);
- LOG("Allocated %X bytes @ %p\n", m_region->bytes(), m_region->base());
+ 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(m_region->base(), ROMREGION_GETERASEVAL(region), m_region->bytes());
- else if (m_region->bytes() <= 0x400000) // or if it's sufficiently small (<= 4MB)
- memset(m_region->base(), 0, m_region->bytes());
+ 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
else // if we're debugging, fill region with random data to catch errors
- fill_random(m_region->base(), m_region->bytes());
+ fill_random(memregion->base(), memregion->bytes());
#endif
// now process the entries in the region
if (searchpath.empty())
searchpath = device.searchpath();
assert(!searchpath.empty());
- process_rom_entries({ searchpath }, device.system_bios(), region, region + 1, false);
+ process_rom_entries({ searchpath }, device.system_bios(), *memregion, region, region + 1, false);
}
else if (ROMREGION_ISDISKDATA(region))
{
@@ -1397,9 +1531,10 @@ void rom_load_manager::process_region_list()
if (driver)
next_parent = next_parent_system(driver->system());
else
- next_parent = [] () { return nullptr; };
+ 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);
+ process_disk_entries({ searchpath }, regiontag, region + 1, next_parent, open_parent);
}
}
}
@@ -1436,7 +1571,6 @@ rom_load_manager::rom_load_manager(running_machine &machine)
, m_romsloadedsize(0)
, m_romstotalsize(0)
, m_chd_list()
- , m_region(nullptr)
, m_errorstring()
, m_softwarningstring()
{
diff --git a/src/emu/romload.h b/src/emu/romload.h
index c273a08b743..001f27aba83 100644
--- a/src/emu/romload.h
+++ b/src/emu/romload.h
@@ -102,11 +102,11 @@ protected:
const_entry_iterator &operator=(const_entry_iterator &&) noexcept = default;
public:
- typedef T value_type;
- typedef value_type const *pointer;
- typedef value_type const &reference;
- typedef std::ptrdiff_t difference_type;
- typedef std::forward_iterator_tag iterator_category;
+ using value_type = T;
+ using pointer = value_type const *;
+ using reference = value_type const &;
+ using difference_type = std::ptrdiff_t;
+ using iterator_category = std::forward_iterator_tag;
reference operator*() const noexcept { return reinterpret_cast<reference>(*m_data); }
pointer operator->() const noexcept { return reinterpret_cast<pointer>(m_data); }
@@ -387,6 +387,7 @@ class rom_load_manager
{
public:
open_chd(std::string_view region) : m_region(region) { }
+ open_chd(std::string &&region) : m_region(std::move(region)) { }
std::string_view region() const { return m_region; }
chd_file &chd() { return m_diffchd.opened() ? m_diffchd : m_origchd; }
@@ -394,9 +395,9 @@ class rom_load_manager
chd_file &diff_chd() { return m_diffchd; }
private:
- std::string m_region; /* disk region we came from */
- chd_file m_origchd; /* handle to the original CHD */
- chd_file m_diffchd; /* handle to the diff CHD */
+ std::string m_region; // disk region we came from
+ chd_file m_origchd; // handle to the original CHD
+ chd_file m_diffchd; // handle to the diff CHD
};
public:
@@ -428,10 +429,12 @@ public:
static std::vector<std::string> get_software_searchpath(software_list_device &swlist, const software_info &swinfo);
/* open a disk image, searching up the parent and loading by checksum */
- static std::error_condition open_disk_image(const emu_options &options, const device_t &device, const rom_entry *romp, chd_file &image_chd);
- static std::error_condition open_disk_image(const emu_options &options, software_list_device &swlist, const software_info &swinfo, const rom_entry *romp, chd_file &image_chd);
+ static std::error_condition open_disk_image(emu_options &options, const device_t &device, const rom_entry *romp, chd_file &image_chd);
+ static std::error_condition open_disk_image(emu_options &options, software_list_device &swlist, const software_info &swinfo, const rom_entry *romp, chd_file &image_chd);
private:
+ using search_paths = std::initializer_list<std::reference_wrapper<const std::vector<std::string> > >;
+
void determine_bios_rom(device_t &device, std::string_view specbios);
void count_roms();
void fill_random(u8 *base, u32 length);
@@ -441,15 +444,40 @@ private:
void display_loading_rom_message(const char *name, bool from_list);
void display_rom_load_results(bool from_list);
void region_post_process(memory_region *region, bool invert);
- std::unique_ptr<emu_file> open_rom_file(std::initializer_list<std::reference_wrapper<const std::vector<std::string> > > searchpath, const rom_entry *romp, std::vector<std::string> &tried_file_names, bool from_list);
- std::unique_ptr<emu_file> 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);
+ std::unique_ptr<emu_file> open_rom_file(
+ search_paths searchpath,
+ const rom_entry *romp,
+ std::vector<std::string> &tried_file_names,
+ bool from_list);
+ std::unique_ptr<emu_file> 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);
int rom_fread(emu_file *file, u8 *buffer, int length, const rom_entry *parent_region);
- int read_rom_data(emu_file *file, const rom_entry *parent_region, const rom_entry *romp);
- void fill_rom_data(const rom_entry *romp);
- void copy_rom_data(const rom_entry *romp);
- void process_rom_entries(std::initializer_list<std::reference_wrapper<const std::vector<std::string> > > searchpath, u8 bios, const rom_entry *parent_region, const rom_entry *romp, bool from_list);
- std::error_condition open_disk_diff(emu_options &options, const rom_entry *romp, chd_file &source, chd_file &diff_chd);
- void process_disk_entries(std::initializer_list<std::reference_wrapper<const std::vector<std::string> > > searchpath, std::string_view regiontag, const rom_entry *romp, std::function<const rom_entry * ()> next_parent);
+ int read_rom_data(emu_file *file, memory_region &region, const rom_entry *parent_region, const rom_entry *romp);
+ void fill_rom_data(memory_region &region, const rom_entry *romp);
+ void copy_rom_data(memory_region &region, const rom_entry *romp);
+ void process_rom_entries(
+ search_paths searchpath,
+ u8 bios,
+ memory_region &region,
+ const rom_entry *parent_region,
+ const rom_entry *romp,
+ bool from_list);
+ std::error_condition open_disk_diff(
+ emu_options &options,
+ const rom_entry *romp,
+ chd_file &source,
+ chd_file &diff_chd);
+ void process_disk_entries(
+ search_paths searchpath,
+ std::string_view regiontag,
+ const rom_entry *romp,
+ std::function<const rom_entry * ()> next_parent,
+ const chd_file::open_parent_func &open_parent);
void normalize_flags_for_device(std::string_view rgntag, u8 &width, endianness_t &endian);
void process_region_list();
@@ -467,8 +495,6 @@ private:
std::vector<std::unique_ptr<open_chd>> m_chd_list; /* disks */
- memory_region * m_region; // info about current region
-
std::string m_errorstring; // error string
std::string m_softwarningstring; // software warning string
};
diff --git a/src/frontend/mame/audit.cpp b/src/frontend/mame/audit.cpp
index 129126bb2ef..dbbb9ad8f3d 100644
--- a/src/frontend/mame/audit.cpp
+++ b/src/frontend/mame/audit.cpp
@@ -656,6 +656,9 @@ media_auditor::audit_record &media_auditor::audit_one_disk(const rom_entry *rom,
chd_file source;
const std::error_condition err = rom_load_manager::open_disk_image(m_enumerator.options(), std::forward<T>(args)..., rom, source);
+ // FIXME: A CHD with an invalid header or missing parent is treated as not found.
+ // We need a way to report more detailed errors for bad disk images.
+
// if we succeeded, get the hashes
if (!err)
{
diff --git a/src/lib/util/chd.cpp b/src/lib/util/chd.cpp
index 1766ba9898d..11f0b93eb86 100644
--- a/src/lib/util/chd.cpp
+++ b/src/lib/util/chd.cpp
@@ -318,6 +318,16 @@ util::random_read &chd_file::file()
return *m_file;
}
+bool chd_file::parent_missing() const noexcept
+{
+ if (m_parent_missing)
+ return true;
+ else if (!m_parent)
+ return false;
+ else
+ return m_parent->parent_missing();
+}
+
/**
* @fn util::sha1_t chd_file::sha1()
*
@@ -590,7 +600,12 @@ void chd_file::set_parent_sha1(util::sha1_t parent)
* @return A std::error_condition.
*/
-std::error_condition chd_file::create(util::random_read_write::ptr &&file, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t unitbytes, chd_codec_type compression[4])
+std::error_condition chd_file::create(
+ util::random_read_write::ptr &&file,
+ uint64_t logicalbytes,
+ uint32_t hunkbytes,
+ uint32_t unitbytes,
+ chd_codec_type compression[4])
{
// make sure we don't already have a file open
if (m_file)
@@ -603,7 +618,7 @@ std::error_condition chd_file::create(util::random_read_write::ptr &&file, uint6
m_hunkbytes = hunkbytes;
m_unitbytes = unitbytes;
memcpy(m_compression, compression, sizeof(m_compression));
- m_parent = nullptr;
+ m_parent.reset();
// take ownership of the file
m_file = std::move(file);
@@ -626,7 +641,12 @@ std::error_condition chd_file::create(util::random_read_write::ptr &&file, uint6
* @return A std::error_condition.
*/
-std::error_condition chd_file::create(util::random_read_write::ptr &&file, uint64_t logicalbytes, uint32_t hunkbytes, chd_codec_type compression[4], chd_file &parent)
+std::error_condition chd_file::create(
+ util::random_read_write::ptr &&file,
+ uint64_t logicalbytes,
+ uint32_t hunkbytes,
+ chd_codec_type compression[4],
+ chd_file &parent)
{
// make sure we don't already have a file open
if (m_file)
@@ -639,7 +659,7 @@ std::error_condition chd_file::create(util::random_read_write::ptr &&file, uint6
m_hunkbytes = hunkbytes;
m_unitbytes = parent.unit_bytes();
memcpy(m_compression, compression, sizeof(m_compression));
- m_parent = &parent;
+ m_parent = std::shared_ptr<chd_file>(std::shared_ptr<chd_file>(), &parent);
// take ownership of the file
m_file = std::move(file);
@@ -662,7 +682,12 @@ std::error_condition chd_file::create(util::random_read_write::ptr &&file, uint6
* @return A std::error_condition.
*/
-std::error_condition chd_file::create(std::string_view filename, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t unitbytes, chd_codec_type compression[4])
+std::error_condition chd_file::create(
+ std::string_view filename,
+ uint64_t logicalbytes,
+ uint32_t hunkbytes,
+ uint32_t unitbytes,
+ chd_codec_type compression[4])
{
// make sure we don't already have a file open
if (m_file)
@@ -702,7 +727,12 @@ std::error_condition chd_file::create(std::string_view filename, uint64_t logica
* @return A std::error_condition.
*/
-std::error_condition chd_file::create(std::string_view filename, uint64_t logicalbytes, uint32_t hunkbytes, chd_codec_type compression[4], chd_file &parent)
+std::error_condition chd_file::create(
+ std::string_view filename,
+ uint64_t logicalbytes,
+ uint32_t hunkbytes,
+ chd_codec_type compression[4],
+ chd_file &parent)
{
// make sure we don't already have a file open
if (m_file)
@@ -740,7 +770,11 @@ std::error_condition chd_file::create(std::string_view filename, uint64_t logica
* @return A std::error_condition.
*/
-std::error_condition chd_file::open(std::string_view filename, bool writeable, chd_file *parent)
+std::error_condition chd_file::open(
+ std::string_view filename,
+ bool writeable,
+ chd_file *parent,
+ const open_parent_func &open_parent)
{
// make sure we don't already have a file open
if (m_file)
@@ -754,12 +788,7 @@ std::error_condition chd_file::open(std::string_view filename, bool writeable, c
return filerr;
// now open the CHD
- std::error_condition err = open(std::move(file), writeable, parent);
- if (err)
- return err;
-
- // we now own this file
- return err;
+ return open(std::move(file), writeable, parent, open_parent);
}
/**
@@ -776,7 +805,11 @@ std::error_condition chd_file::open(std::string_view filename, bool writeable, c
* @return A std::error_condition.
*/
-std::error_condition chd_file::open(util::random_read_write::ptr &&file, bool writeable, chd_file *parent)
+std::error_condition chd_file::open(
+ util::random_read_write::ptr &&file,
+ bool writeable,
+ chd_file *parent,
+ const open_parent_func &open_parent)
{
// make sure we don't already have a file open
if (m_file)
@@ -786,9 +819,9 @@ std::error_condition chd_file::open(util::random_read_write::ptr &&file, bool wr
// open the file
m_file = std::move(file);
- m_parent = parent;
+ m_parent = std::shared_ptr<chd_file>(std::shared_ptr<chd_file>(), parent);
m_cachehunk = ~0;
- return open_common(writeable);
+ return open_common(writeable, open_parent);
}
/**
@@ -816,7 +849,7 @@ void chd_file::close()
m_unitbytes = 0;
m_unitcount = 0;
memset(m_compression, 0, sizeof(m_compression));
- m_parent = nullptr;
+ m_parent.reset();
m_parent_missing = false;
// reset key offsets within the header
@@ -936,7 +969,7 @@ std::error_condition chd_file::read_hunk(uint32_t hunknum, void *buffer)
file_read(blockoffs, dest, m_hunkbytes);
else if (m_parent_missing)
throw std::error_condition(error::REQUIRES_PARENT);
- else if (m_parent != nullptr)
+ else if (m_parent)
m_parent->read_hunk(hunknum, dest);
else
memset(dest, 0, m_hunkbytes);
@@ -2300,7 +2333,7 @@ std::error_condition chd_file::create_common()
put_u32be(&rawheader[60], m_unitbytes);
be_write_sha1(&rawheader[64], util::sha1_t::null);
be_write_sha1(&rawheader[84], util::sha1_t::null);
- be_write_sha1(&rawheader[104], (m_parent != nullptr) ? m_parent->sha1() : util::sha1_t::null);
+ be_write_sha1(&rawheader[104], m_parent ? m_parent->sha1() : util::sha1_t::null);
// write the resulting header
file_write(0, rawheader, sizeof(rawheader));
@@ -2368,7 +2401,7 @@ std::error_condition chd_file::create_common()
* @return A std::error_condition.
*/
-std::error_condition chd_file::open_common(bool writeable)
+std::error_condition chd_file::open_common(bool writeable, const open_parent_func &open_parent)
{
// wrap in try for proper error handling
try
@@ -2406,13 +2439,18 @@ std::error_condition chd_file::open_common(bool writeable)
// make sure we have a parent if we need one (and don't if we don't)
if (parentsha1 != util::sha1_t::null)
{
+ if (!m_parent && open_parent)
+ m_parent = open_parent(parentsha1);
+
if (!m_parent)
m_parent_missing = true;
else if (m_parent->sha1() != parentsha1)
throw std::error_condition(error::INVALID_PARENT);
}
else if (m_parent)
+ {
throw std::error_condition(std::errc::invalid_argument);
+ }
// finish opening the file
create_open_common();
@@ -2789,7 +2827,7 @@ chd_file_compressor::~chd_file_compressor()
void chd_file_compressor::compress_begin()
{
// reset state
- m_walking_parent = (m_parent != nullptr);
+ m_walking_parent = bool(m_parent);
m_total_in = 0;
m_total_out = 0;
m_compsha1.reset();
@@ -2922,7 +2960,7 @@ std::error_condition chd_file_compressor::compress_continue(double &progress, do
}
// if not, see if it's in the parent map
- if (m_parent != nullptr)
+ if (m_parent)
{
uint64_t parentunit = m_parent_map.find(item.m_hash[0].m_crc16, item.m_hash[0].m_sha1);
if (parentunit != hashmap::NOT_FOUND)
diff --git a/src/lib/util/chd.h b/src/lib/util/chd.h
index 3d9c54dedda..3e52cab4f9b 100644
--- a/src/lib/util/chd.h
+++ b/src/lib/util/chd.h
@@ -19,6 +19,8 @@
#include "osdcore.h"
#include <atomic>
+#include <functional>
+#include <memory>
#include <string>
#include <string_view>
#include <system_error>
@@ -292,22 +294,25 @@ public:
COMPRESSING
};
+ using open_parent_func = std::function<std::unique_ptr<chd_file> (util::sha1_t const &)>;
+
// construction/destruction
chd_file();
virtual ~chd_file();
// getters
util::random_read &file();
- bool opened() const { return bool(m_file); }
- uint32_t version() const { return m_version; }
- uint64_t logical_bytes() const { return m_logicalbytes; }
- uint32_t hunk_bytes() const { return m_hunkbytes; }
- uint32_t hunk_count() const { return m_hunkcount; }
- uint32_t unit_bytes() const { return m_unitbytes; }
- uint64_t unit_count() const { return m_unitcount; }
+ bool opened() const noexcept { return bool(m_file); }
+ uint32_t version() const noexcept { return m_version; }
+ uint64_t logical_bytes() const noexcept { return m_logicalbytes; }
+ uint32_t hunk_bytes() const noexcept { return m_hunkbytes; }
+ uint32_t hunk_count() const noexcept { return m_hunkcount; }
+ uint32_t unit_bytes() const noexcept { return m_unitbytes; }
+ uint64_t unit_count() const noexcept { return m_unitcount; }
bool compressed() const { return (m_compression[0] != CHD_CODEC_NONE); }
- chd_codec_type compression(int index) const { return m_compression[index]; }
- chd_file *parent() const { return m_parent; }
+ chd_codec_type compression(int index) const noexcept { return m_compression[index]; }
+ chd_file *parent() const noexcept { return m_parent.get(); }
+ bool parent_missing() const noexcept;
util::sha1_t sha1();
util::sha1_t raw_sha1();
util::sha1_t parent_sha1();
@@ -324,8 +329,8 @@ public:
std::error_condition create(util::random_read_write::ptr &&file, uint64_t logicalbytes, uint32_t hunkbytes, chd_codec_type compression[4], chd_file &parent);
// file open
- std::error_condition open(std::string_view filename, bool writeable = false, chd_file *parent = nullptr);
- std::error_condition open(util::random_read_write::ptr &&file, bool writeable = false, chd_file *parent = nullptr);
+ std::error_condition open(std::string_view filename, bool writeable = false, chd_file *parent = nullptr, const open_parent_func &open_parent = nullptr);
+ std::error_condition open(util::random_read_write::ptr &&file, bool writeable = false, chd_file *parent = nullptr, const open_parent_func &open_parent = nullptr);
// file close
void close();
@@ -382,7 +387,7 @@ private:
std::error_condition compress_v5_map();
void decompress_v5_map();
std::error_condition create_common();
- std::error_condition open_common(bool writeable);
+ std::error_condition open_common(bool writeable, const open_parent_func &open_parent);
void create_open_common();
void verify_proper_compression_append(uint32_t hunknum);
void hunk_write_compressed(uint32_t hunknum, int8_t compression, const uint8_t *compressed, uint32_t complength, util::crc16_t crc16);
@@ -408,7 +413,7 @@ private:
uint32_t m_unitbytes; // size of each unit in bytes
uint64_t m_unitcount; // number of units represented
chd_codec_type m_compression[4]; // array of compression types used
- chd_file * m_parent; // pointer to parent file, or nullptr if none
+ std::shared_ptr<chd_file> m_parent; // pointer to parent file, or nullptr if none
bool m_parent_missing; // are we missing our parent?
// key offsets within the header