mirror of
https://github.com/holub/mame
synced 2025-04-20 15:32:45 +03:00
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.
This commit is contained in:
parent
4dfc36ae47
commit
d1172bf710
@ -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 ®ion,
|
||||
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 ®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())
|
||||
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 ®ion, 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 ®ion,
|
||||
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(),
|
||||
[®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++)
|
||||
@ -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()
|
||||
{
|
||||
|
@ -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 &®ion) : 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 ®ion, const rom_entry *parent_region, const rom_entry *romp);
|
||||
void fill_rom_data(memory_region ®ion, const rom_entry *romp);
|
||||
void copy_rom_data(memory_region ®ion, const rom_entry *romp);
|
||||
void process_rom_entries(
|
||||
search_paths searchpath,
|
||||
u8 bios,
|
||||
memory_region ®ion,
|
||||
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
|
||||
};
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user