mirror of
https://github.com/holub/mame
synced 2025-04-20 15:32:45 +03:00
ROM loading cleanup:
* More flexible constructors for path_iterator and emu_file * More straightforward system/device ROM loading and software loading when using ROM loader * Proper parent walk when searching for identical CHDs with different names from software list * Fixed hangs if software item parents form a loop * Fixed layouts being loaded from bogus empty paths Note that there are changes in behaviour: * For software list ROMs/disks, MAME will now search the software path before searching the machine path * The search path for the owner of the software list device is used, which may not be the driver itself * MAME will no longer load loose CHDs from the media path - it's just too unwieldy with the number of supported systems * MAME will no longer search archives above the top level of the media path
This commit is contained in:
parent
9341daa9ed
commit
cf078d736a
@ -835,19 +835,6 @@ std::vector<u32> device_image_interface::determine_open_plan(bool is_create)
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// dump_wrong_and_correct_checksums - dump an
|
||||
// error message containing the wrong and the
|
||||
// correct checksums for a given software item
|
||||
//-------------------------------------------------
|
||||
|
||||
static void dump_wrong_and_correct_checksums(const util::hash_collection &hashes, const util::hash_collection &acthashes)
|
||||
{
|
||||
osd_printf_error(" EXPECTED: %s\n", hashes.macro_string());
|
||||
osd_printf_error(" FOUND: %s\n", acthashes.macro_string());
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// verify_length_and_hash - verify the length
|
||||
// and hash signatures of a file
|
||||
@ -855,37 +842,38 @@ static void dump_wrong_and_correct_checksums(const util::hash_collection &hashes
|
||||
|
||||
static int verify_length_and_hash(emu_file *file, const char *name, u32 explength, const util::hash_collection &hashes)
|
||||
{
|
||||
int retVal = 0;
|
||||
if (file==nullptr) return 0;
|
||||
int retval = 0;
|
||||
if (!file)
|
||||
return 0;
|
||||
|
||||
// verify length
|
||||
u32 actlength = file->size();
|
||||
if (explength != actlength)
|
||||
{
|
||||
osd_printf_error("%s WRONG LENGTH (expected: %d found: %d)\n", name, explength, actlength);
|
||||
retVal++;
|
||||
retval++;
|
||||
}
|
||||
|
||||
// If there is no good dump known, write it
|
||||
util::hash_collection &acthashes = 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
|
||||
osd_printf_error("%s NO GOOD DUMP KNOWN\n", name);
|
||||
}
|
||||
// verify checksums
|
||||
else if (hashes != acthashes)
|
||||
{
|
||||
// otherwise, it's just bad
|
||||
osd_printf_error("%s WRONG CHECKSUMS:\n", name);
|
||||
dump_wrong_and_correct_checksums(hashes, acthashes);
|
||||
retVal++;
|
||||
osd_printf_error(" EXPECTED: %s\n", hashes.macro_string());
|
||||
osd_printf_error(" FOUND: %s\n", acthashes.macro_string());
|
||||
retval++;
|
||||
}
|
||||
// If it matches, but it is actually a bad dump, write it
|
||||
else if (hashes.flag(util::hash_collection::FLAG_BAD_DUMP))
|
||||
{
|
||||
// If it matches, but it is actually a bad dump, write it
|
||||
osd_printf_error("%s NEEDS REDUMP\n",name);
|
||||
}
|
||||
return retVal;
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
@ -895,102 +883,91 @@ static int verify_length_and_hash(emu_file *file, const char *name, u32 explengt
|
||||
|
||||
bool device_image_interface::load_software(software_list_device &swlist, const char *swname, const rom_entry *start)
|
||||
{
|
||||
std::string locationtag, breakstr("%");
|
||||
const rom_entry *region;
|
||||
bool retVal = false;
|
||||
bool retval = false;
|
||||
int warningcount = 0;
|
||||
for (region = start; region != nullptr; region = rom_next_region(region))
|
||||
for (const rom_entry *region = start; region; region = rom_next_region(region))
|
||||
{
|
||||
// loop until we hit the end of this region
|
||||
const rom_entry *romp = region + 1;
|
||||
while (!ROMENTRY_ISREGIONEND(romp))
|
||||
for (const rom_entry *romp = region + 1; !ROMENTRY_ISREGIONEND(romp); romp++)
|
||||
{
|
||||
// handle files
|
||||
if (ROMENTRY_ISFILE(romp))
|
||||
{
|
||||
osd_file::error filerr = osd_file::error::NOT_FOUND;
|
||||
|
||||
u32 crc = 0;
|
||||
bool has_crc = util::hash_collection(ROM_GETHASHDATA(romp)).crc(crc);
|
||||
|
||||
const software_info *swinfo = swlist.find(swname);
|
||||
if (swinfo == nullptr)
|
||||
const software_info *const swinfo = swlist.find(swname);
|
||||
if (!swinfo)
|
||||
return false;
|
||||
|
||||
u32 supported = swinfo->supported();
|
||||
const u32 supported = swinfo->supported();
|
||||
if (supported == SOFTWARE_SUPPORTED_PARTIAL)
|
||||
osd_printf_error("WARNING: support for software %s (in list %s) is only partial\n", swname, swlist.list_name());
|
||||
if (supported == SOFTWARE_SUPPORTED_NO)
|
||||
osd_printf_error("WARNING: 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 "
|
||||
// below, we have the code to split the elements and to create paths to load from
|
||||
u32 crc = 0;
|
||||
const bool has_crc = util::hash_collection(ROM_GETHASHDATA(romp)).crc(crc);
|
||||
std::vector<const software_info *> parents;
|
||||
std::vector<std::string> searchpath;
|
||||
|
||||
while (swinfo != nullptr)
|
||||
// search <rompath>/<list>/<software> following parents
|
||||
searchpath.emplace_back(util::string_format("%s" PATH_SEPARATOR "%s", swlist.list_name(), swname));
|
||||
for (const software_info *i = swinfo; i && !i->parentname().empty(); i = swlist.find(i->parentname()))
|
||||
{
|
||||
locationtag.append(swinfo->shortname()).append(breakstr);
|
||||
swinfo = !swinfo->parentname().empty() ? swlist.find(swinfo->parentname()) : nullptr;
|
||||
}
|
||||
// strip the final '%'
|
||||
locationtag.erase(locationtag.length() - 1, 1);
|
||||
|
||||
|
||||
// check if locationtag actually contains two locations separated by '%'
|
||||
// (i.e. check if we are dealing with a clone in softwarelist)
|
||||
std::string tag2, tag3, tag4(locationtag), tag5;
|
||||
int separator = tag4.find_first_of('%');
|
||||
if (separator != -1)
|
||||
{
|
||||
// we are loading a clone through softlists, split the setname from the parentname
|
||||
tag5.assign(tag4.substr(separator + 1, tag4.length() - separator + 1));
|
||||
tag4.erase(separator, tag4.length() - separator);
|
||||
if (std::find(parents.begin(), parents.end(), i) != parents.end())
|
||||
{
|
||||
osd_printf_warning("WARNING: parent/clone relationships form a loop for software %s (in list %s)\n", swname, swlist.list_name());
|
||||
break;
|
||||
}
|
||||
parents.emplace_back(i);
|
||||
searchpath.emplace_back(util::string_format("%s" PATH_SEPARATOR "%s", swlist.list_name(), i->parentname()));
|
||||
}
|
||||
|
||||
// prepare locations where we have to load from: list/parentname & list/clonename
|
||||
std::string tag1(swlist.list_name());
|
||||
tag1.append(PATH_SEPARATOR);
|
||||
tag2.assign(tag1.append(tag4));
|
||||
tag1.assign(swlist.list_name());
|
||||
tag1.append(PATH_SEPARATOR);
|
||||
tag3.assign(tag1.append(tag5));
|
||||
// search <rompath>/<software> following parents
|
||||
searchpath.emplace_back(swname);
|
||||
parents.clear();
|
||||
for (software_info const *i = swinfo; i && !i->parentname().empty(); i = swlist.find(i->parentname()))
|
||||
{
|
||||
if (std::find(parents.begin(), parents.end(), i) != parents.end())
|
||||
break;
|
||||
parents.emplace_back(i);
|
||||
searchpath.emplace_back(i->parentname());
|
||||
}
|
||||
|
||||
if (tag5.find_first_of('%') != -1)
|
||||
fatalerror("We do not support clones of clones!\n");
|
||||
// for historical reasons, add the search path for the software list device's owner
|
||||
const device_t *const listowner = swlist.owner();
|
||||
if (listowner)
|
||||
{
|
||||
std::vector<std::string> devsearch = listowner->searchpath();
|
||||
for (std::string &path : devsearch)
|
||||
searchpath.emplace_back(std::move(path));
|
||||
}
|
||||
|
||||
// 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
|
||||
// try to load from list/setname
|
||||
if ((m_mame_file == nullptr) && (tag2.c_str() != nullptr))
|
||||
m_mame_file = common_process_file(device().machine().options(), tag2.c_str(), has_crc, crc, romp, filerr);
|
||||
// try to load from list/parentname
|
||||
if ((m_mame_file == nullptr) && (tag3.c_str() != nullptr))
|
||||
m_mame_file = common_process_file(device().machine().options(), tag3.c_str(), has_crc, crc, romp, filerr);
|
||||
// try to load from setname
|
||||
if ((m_mame_file == nullptr) && (tag4.c_str() != nullptr))
|
||||
m_mame_file = common_process_file(device().machine().options(), tag4.c_str(), has_crc, crc, romp, filerr);
|
||||
// try to load from parentname
|
||||
if ((m_mame_file == nullptr) && (tag5.c_str() != nullptr))
|
||||
m_mame_file = common_process_file(device().machine().options(), tag5.c_str(), has_crc, crc, romp, filerr);
|
||||
// try to load the file
|
||||
m_mame_file.reset(new emu_file(device().machine().options().media_path(), searchpath, OPEN_FLAG_READ));
|
||||
m_mame_file->set_restrict_to_mediapath(1);
|
||||
osd_file::error filerr;
|
||||
if (has_crc)
|
||||
filerr = m_mame_file->open(ROM_GETNAME(romp), crc);
|
||||
else
|
||||
filerr = m_mame_file->open(ROM_GETNAME(romp));
|
||||
if (filerr != osd_file::error::NONE)
|
||||
m_mame_file.reset();
|
||||
|
||||
warningcount += verify_length_and_hash(m_mame_file.get(),ROM_GETNAME(romp),ROM_GETLENGTH(romp), util::hash_collection(ROM_GETHASHDATA(romp)));
|
||||
warningcount += verify_length_and_hash(m_mame_file.get(), ROM_GETNAME(romp), ROM_GETLENGTH(romp), util::hash_collection(ROM_GETHASHDATA(romp)));
|
||||
|
||||
if (filerr == osd_file::error::NONE)
|
||||
filerr = util::core_file::open_proxy(*m_mame_file, m_file);
|
||||
if (filerr == osd_file::error::NONE)
|
||||
retVal = true;
|
||||
retval = true;
|
||||
|
||||
break; // load first item for start
|
||||
}
|
||||
romp++; /* something else; skip */
|
||||
}
|
||||
}
|
||||
|
||||
if (warningcount > 0)
|
||||
{
|
||||
osd_printf_error("WARNING: the software item might not run correctly.\n");
|
||||
}
|
||||
return retVal;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
|
@ -9,9 +9,31 @@
|
||||
***************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "unzip.h"
|
||||
#include "fileio.h"
|
||||
|
||||
#include "unzip.h"
|
||||
|
||||
//#define VERBOSE 1
|
||||
#define LOG_OUTPUT_FUNC osd_printf_verbose
|
||||
#include "logmacro.h"
|
||||
|
||||
|
||||
template path_iterator::path_iterator(char *&, int);
|
||||
template path_iterator::path_iterator(char * const &, int);
|
||||
template path_iterator::path_iterator(char const *&, int);
|
||||
template path_iterator::path_iterator(char const * const &, int);
|
||||
template path_iterator::path_iterator(std::vector<std::string> &, int);
|
||||
template path_iterator::path_iterator(const std::vector<std::string> &, int);
|
||||
|
||||
template emu_file::emu_file(std::string &, u32);
|
||||
template emu_file::emu_file(const std::string &, u32);
|
||||
template emu_file::emu_file(char *&, u32);
|
||||
template emu_file::emu_file(char * const &, u32);
|
||||
template emu_file::emu_file(char const *&, u32);
|
||||
template emu_file::emu_file(char const * const &, u32);
|
||||
template emu_file::emu_file(std::vector<std::string> &, u32);
|
||||
template emu_file::emu_file(const std::vector<std::string> &, u32);
|
||||
|
||||
|
||||
const u32 OPEN_FLAG_HAS_CRC = 0x10000;
|
||||
|
||||
@ -28,6 +50,7 @@ const u32 OPEN_FLAG_HAS_CRC = 0x10000;
|
||||
path_iterator::path_iterator(std::string &&searchpath)
|
||||
: m_searchpath(std::move(searchpath))
|
||||
, m_current(m_searchpath.cbegin())
|
||||
, m_separator(';') // FIXME this should be a macro - UNIX prefers :
|
||||
, m_is_first(true)
|
||||
{
|
||||
}
|
||||
@ -35,6 +58,7 @@ path_iterator::path_iterator(std::string &&searchpath)
|
||||
path_iterator::path_iterator(std::string const &searchpath)
|
||||
: m_searchpath(searchpath)
|
||||
, m_current(m_searchpath.cbegin())
|
||||
, m_separator(';') // FIXME this should be a macro - UNIX prefers :
|
||||
, m_is_first(true)
|
||||
{
|
||||
}
|
||||
@ -47,6 +71,7 @@ path_iterator::path_iterator(path_iterator &&that)
|
||||
path_iterator::path_iterator(path_iterator const &that)
|
||||
: m_searchpath(that.m_searchpath)
|
||||
, m_current(std::next(m_searchpath.cbegin(), std::distance(that.m_searchpath.cbegin(), that.m_current)))
|
||||
, m_separator(that.m_separator)
|
||||
, m_is_first(that.m_is_first)
|
||||
{
|
||||
}
|
||||
@ -61,6 +86,7 @@ path_iterator &path_iterator::operator=(path_iterator &&that)
|
||||
auto const current(std::distance(that.m_searchpath.cbegin(), that.m_current));
|
||||
m_searchpath = std::move(that.m_searchpath);
|
||||
m_current = std::next(m_searchpath.cbegin(), current);
|
||||
m_separator = that.m_separator;
|
||||
m_is_first = that.m_is_first;
|
||||
return *this;
|
||||
}
|
||||
@ -69,6 +95,7 @@ path_iterator &path_iterator::operator=(path_iterator const &that)
|
||||
{
|
||||
m_searchpath = that.m_searchpath;
|
||||
m_current = std::next(m_searchpath.cbegin(), std::distance(that.m_searchpath.cbegin(), that.m_current));
|
||||
m_separator = that.m_separator;
|
||||
m_is_first = that.m_is_first;
|
||||
return *this;
|
||||
}
|
||||
@ -86,7 +113,7 @@ bool path_iterator::next(std::string &buffer, const char *name)
|
||||
return false;
|
||||
|
||||
// copy up to the next separator
|
||||
auto const sep(std::find(m_current, m_searchpath.cend(), ';')); // FIXME this should be a macro - UNIX prefers :
|
||||
auto const sep(std::find(m_current, m_searchpath.cend(), m_separator));
|
||||
buffer.assign(m_current, sep);
|
||||
m_current = sep;
|
||||
if (m_searchpath.cend() != m_current)
|
||||
@ -165,31 +192,31 @@ const osd::directory::entry *file_enumerator::next()
|
||||
//-------------------------------------------------
|
||||
|
||||
emu_file::emu_file(u32 openflags)
|
||||
: m_file()
|
||||
, m_iterator(std::string())
|
||||
, m_mediapaths(std::string())
|
||||
, m_crc(0)
|
||||
, m_openflags(openflags)
|
||||
, m_zipfile(nullptr)
|
||||
, m_ziplength(0)
|
||||
, m_remove_on_close(false)
|
||||
, m_restrict_to_mediapath(false)
|
||||
: emu_file(path_iterator(std::string()), openflags)
|
||||
{
|
||||
// sanity check the open flags
|
||||
if ((m_openflags & OPEN_FLAG_HAS_CRC) && (m_openflags & OPEN_FLAG_WRITE))
|
||||
throw emu_fatalerror("Attempted to open a file for write with OPEN_FLAG_HAS_CRC");
|
||||
|
||||
}
|
||||
|
||||
emu_file::emu_file(std::string &&searchpath, u32 openflags)
|
||||
: m_file()
|
||||
, m_iterator(searchpath)
|
||||
, m_mediapaths(std::move(searchpath))
|
||||
emu_file::emu_file(path_iterator &&searchpath, u32 openflags)
|
||||
: emu_file(openflags, EMPTY)
|
||||
{
|
||||
m_iterator.emplace_back(searchpath, std::string());
|
||||
m_mediapaths.emplace_back(std::move(searchpath), std::string());
|
||||
}
|
||||
|
||||
emu_file::emu_file(u32 openflags, empty_t)
|
||||
: m_filename()
|
||||
, m_fullpath()
|
||||
, m_file()
|
||||
, m_iterator()
|
||||
, m_mediapaths()
|
||||
, m_first(true)
|
||||
, m_crc(0)
|
||||
, m_openflags(openflags)
|
||||
, m_zipfile(nullptr)
|
||||
, m_ziplength(0)
|
||||
, m_remove_on_close(false)
|
||||
, m_restrict_to_mediapath(false)
|
||||
, m_restrict_to_mediapath(0)
|
||||
{
|
||||
// sanity check the open flags
|
||||
if ((m_openflags & OPEN_FLAG_HAS_CRC) && (m_openflags & OPEN_FLAG_WRITE))
|
||||
@ -279,7 +306,7 @@ osd_file::error emu_file::open(const std::string &name)
|
||||
m_openflags &= ~OPEN_FLAG_HAS_CRC;
|
||||
|
||||
// reset the iterator and open_next
|
||||
m_iterator.reset();
|
||||
m_first = true;
|
||||
return open_next();
|
||||
}
|
||||
|
||||
@ -291,28 +318,10 @@ osd_file::error emu_file::open(const std::string &name, u32 crc)
|
||||
m_openflags |= OPEN_FLAG_HAS_CRC;
|
||||
|
||||
// reset the iterator and open_next
|
||||
m_iterator.reset();
|
||||
m_first = true;
|
||||
return open_next();
|
||||
}
|
||||
|
||||
osd_file::error emu_file::open(const std::string &name1, const std::string &name2, u32 crc)
|
||||
{
|
||||
// concatenate the strings and do a standard open
|
||||
return open(name1 + name2, crc);
|
||||
}
|
||||
|
||||
osd_file::error emu_file::open(const std::string &name1, const std::string &name2, const std::string &name3, u32 crc)
|
||||
{
|
||||
// concatenate the strings and do a standard open
|
||||
return open(name1 + name2 + name3, crc);
|
||||
}
|
||||
|
||||
osd_file::error emu_file::open(const std::string &name1, const std::string &name2, const std::string &name3, const std::string &name4, u32 crc)
|
||||
{
|
||||
// concatenate the strings and do a standard open
|
||||
return open(name1 + name2 + name3 + name4, crc);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// open_next - open the next file that matches
|
||||
@ -322,24 +331,64 @@ osd_file::error emu_file::open(const std::string &name1, const std::string &name
|
||||
osd_file::error emu_file::open_next()
|
||||
{
|
||||
// if we're open from a previous attempt, close up now
|
||||
if (m_file != nullptr)
|
||||
if (m_file)
|
||||
close();
|
||||
|
||||
// loop over paths
|
||||
LOG("emu_file: open next '%s'\n", m_filename);
|
||||
osd_file::error filerr = osd_file::error::NOT_FOUND;
|
||||
while (m_iterator.next(m_fullpath, m_filename.c_str()))
|
||||
while (osd_file::error::NONE != filerr)
|
||||
{
|
||||
if (m_first)
|
||||
{
|
||||
m_first = false;
|
||||
for (searchpath_vector::value_type &i : m_iterator)
|
||||
{
|
||||
i.first.reset();
|
||||
if (!i.first.next(i.second))
|
||||
return filerr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
searchpath_vector::iterator i(m_iterator.begin());
|
||||
while (i != m_iterator.end())
|
||||
{
|
||||
if (i->first.next(i->second))
|
||||
{
|
||||
LOG("emu_file: next path %d '%s'\n", std::distance(m_iterator.begin(), i), i->second);
|
||||
for (searchpath_vector::iterator j = m_iterator.begin(); i != j; ++j)
|
||||
{
|
||||
j->first.reset();
|
||||
j->first.next(j->second);
|
||||
}
|
||||
break;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
if (m_iterator.end() == i)
|
||||
return filerr;
|
||||
}
|
||||
|
||||
// build full path
|
||||
m_fullpath.clear();
|
||||
for (searchpath_vector::value_type const &path : m_iterator)
|
||||
{
|
||||
m_fullpath.append(path.second);
|
||||
if (!m_fullpath.empty() && !util::is_directory_separator(m_fullpath.back()))
|
||||
m_fullpath.append(PATH_SEPARATOR);
|
||||
}
|
||||
m_fullpath.append(m_filename);
|
||||
|
||||
// attempt to open the file directly
|
||||
LOG("emu_file: attempting to open '%s' directly\n", m_fullpath);
|
||||
filerr = util::core_file::open(m_fullpath, m_openflags, m_file);
|
||||
if (filerr == osd_file::error::NONE)
|
||||
break;
|
||||
|
||||
// if we're opening for read-only we have other options
|
||||
if ((m_openflags & (OPEN_FLAG_READ | OPEN_FLAG_WRITE)) == OPEN_FLAG_READ)
|
||||
if ((osd_file::error::NONE != filerr) && ((m_openflags & (OPEN_FLAG_READ | OPEN_FLAG_WRITE)) == OPEN_FLAG_READ))
|
||||
{
|
||||
LOG("emu_file: attempting to open '%s' from archives\n", m_fullpath);
|
||||
filerr = attempt_zipped();
|
||||
if (filerr == osd_file::error::NONE)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return filerr;
|
||||
@ -402,7 +451,7 @@ osd_file::error emu_file::compress(int level)
|
||||
// loading if needed
|
||||
//-------------------------------------------------
|
||||
|
||||
bool emu_file::compressed_file_ready(void)
|
||||
bool emu_file::compressed_file_ready()
|
||||
{
|
||||
// load the ZIP file now if we haven't yet
|
||||
if (m_zipfile && (load_zipped_file() != osd_file::error::NONE))
|
||||
@ -611,16 +660,55 @@ void emu_file::flush()
|
||||
// any media path
|
||||
//-------------------------------------------------
|
||||
|
||||
bool emu_file::part_of_mediapath(std::string path)
|
||||
bool emu_file::part_of_mediapath(const std::string &path)
|
||||
{
|
||||
bool result = false;
|
||||
std::string mediapath;
|
||||
m_mediapaths.reset();
|
||||
while (m_mediapaths.next(mediapath, nullptr) && !result) {
|
||||
if (path.compare(mediapath.substr(0, mediapath.length())))
|
||||
result = true;
|
||||
if (!m_restrict_to_mediapath)
|
||||
return true;
|
||||
|
||||
for (size_t i = 0U; (m_mediapaths.size() > i) && ((0 > m_restrict_to_mediapath) || (i < m_restrict_to_mediapath)); i++)
|
||||
{
|
||||
m_mediapaths[i].first.reset();
|
||||
if (!m_mediapaths[i].first.next(m_mediapaths[i].second))
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string mediapath;
|
||||
while (true)
|
||||
{
|
||||
mediapath.clear();
|
||||
for (size_t i = 0U; (m_mediapaths.size() > i) && ((0 > m_restrict_to_mediapath) || (i < m_restrict_to_mediapath)); i++)
|
||||
{
|
||||
mediapath.append(m_mediapaths[i].second);
|
||||
if (!mediapath.empty() && !util::is_directory_separator(mediapath.back()))
|
||||
mediapath.append(PATH_SEPARATOR);
|
||||
}
|
||||
|
||||
if (!path.compare(0, mediapath.size(), mediapath))
|
||||
{
|
||||
LOG("emu_file: path '%s' matches media path '%s'\n", path, mediapath);
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t i = 0U;
|
||||
while ((m_mediapaths.size() > i) && ((0 > m_restrict_to_mediapath) || (i < m_restrict_to_mediapath)))
|
||||
{
|
||||
if (m_mediapaths[i].first.next(m_mediapaths[i].second))
|
||||
{
|
||||
for (size_t j = 0U; i != j; j++)
|
||||
{
|
||||
m_mediapaths[j].first.reset();
|
||||
m_mediapaths[j].first.next(m_mediapaths[j].second);
|
||||
}
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if ((m_mediapaths.size() == i) || ((0 <= m_restrict_to_mediapath) && (i == m_restrict_to_mediapath)))
|
||||
{
|
||||
LOG("emu_file: path '%s' not in media path\n", path);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
@ -641,21 +729,24 @@ osd_file::error emu_file::attempt_zipped()
|
||||
// loop over directory parts up to the start of filename
|
||||
while (1)
|
||||
{
|
||||
// find the final path separator
|
||||
auto const dirsep = m_fullpath.find_last_of(PATH_SEPARATOR[0]);
|
||||
if (dirsep == std::string::npos)
|
||||
if (!part_of_mediapath(m_fullpath))
|
||||
break;
|
||||
|
||||
if (restrict_to_mediapath() && !part_of_mediapath(m_fullpath))
|
||||
// find the final path separator
|
||||
auto const dirsepiter(std::find_if(m_fullpath.rbegin(), m_fullpath.rend(), util::is_directory_separator));
|
||||
if (dirsepiter == m_fullpath.rend())
|
||||
break;
|
||||
std::string::size_type const dirsep(std::distance(m_fullpath.begin(), dirsepiter.base()) - 1);
|
||||
|
||||
// insert the part from the right of the separator into the head of the filename
|
||||
if (!filename.empty()) filename.insert(0, 1, '/');
|
||||
if (!filename.empty())
|
||||
filename.insert(0, 1, '/');
|
||||
filename.insert(0, m_fullpath.substr(dirsep + 1, std::string::npos));
|
||||
|
||||
// remove this part of the filename and append an archive extension
|
||||
m_fullpath.resize(dirsep);
|
||||
m_fullpath.append(suffixes[i]);
|
||||
LOG("emu_file: looking for '%s' in archive '%s'\n", filename, m_fullpath);
|
||||
|
||||
// attempt to open the archive file
|
||||
util::archive_file::ptr zip;
|
||||
|
113
src/emu/fileio.h
113
src/emu/fileio.h
@ -16,6 +16,13 @@
|
||||
#include "corefile.h"
|
||||
#include "hash.h"
|
||||
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
|
||||
// some systems use macros for getc/putc rather than functions
|
||||
#ifdef getc
|
||||
#undef getc
|
||||
@ -37,6 +44,17 @@ public:
|
||||
path_iterator(path_iterator &&that);
|
||||
path_iterator(path_iterator const &that);
|
||||
|
||||
template <typename T>
|
||||
path_iterator(T &&searchpath, std::enable_if_t<std::is_constructible<std::string, T>::value, int> = 0)
|
||||
: path_iterator(std::string(std::forward<T>(searchpath)))
|
||||
{ }
|
||||
|
||||
// TODO: this doesn't work with C arrays (only vector, std::array, etc.)
|
||||
template <typename T>
|
||||
path_iterator(T &&paths, std::enable_if_t<std::is_constructible<std::string, typename std::remove_reference_t<T>::value_type>::value, int> = 0)
|
||||
: path_iterator(concatenate_paths(std::forward<T>(paths)))
|
||||
{ m_separator = '\0'; }
|
||||
|
||||
// assignment operators
|
||||
path_iterator &operator=(path_iterator &&that);
|
||||
path_iterator &operator=(path_iterator const &that);
|
||||
@ -46,9 +64,30 @@ public:
|
||||
void reset();
|
||||
|
||||
private:
|
||||
// helpers
|
||||
template <typename T>
|
||||
static std::string concatenate_paths(T &&paths)
|
||||
{
|
||||
std::string result;
|
||||
auto it(std::begin(paths));
|
||||
if (std::end(paths) != it)
|
||||
{
|
||||
result.append(*it);
|
||||
++it;
|
||||
}
|
||||
while (std::end(paths) != it)
|
||||
{
|
||||
result.append(1, '\0');
|
||||
result.append(*it);
|
||||
++it;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// internal state
|
||||
std::string m_searchpath;
|
||||
std::string::const_iterator m_current;
|
||||
char m_separator;
|
||||
bool m_is_first;
|
||||
};
|
||||
|
||||
@ -83,10 +122,24 @@ private:
|
||||
|
||||
class emu_file
|
||||
{
|
||||
enum empty_t { EMPTY };
|
||||
using searchpath_vector = std::vector<std::pair<path_iterator, std::string> >;
|
||||
|
||||
public:
|
||||
// file open/creation
|
||||
emu_file(u32 openflags);
|
||||
emu_file(std::string &&searchpath, u32 openflags);
|
||||
template <typename T>
|
||||
emu_file(T &&searchpath, std::enable_if_t<std::is_constructible<path_iterator, T>::value, u32> openflags)
|
||||
: emu_file(path_iterator(std::forward<T>(searchpath)), openflags)
|
||||
{ }
|
||||
template <typename T, typename U, typename V, typename... W>
|
||||
emu_file(T &&searchpath, U &&x, V &&y, W &&... z)
|
||||
: emu_file(0U, EMPTY)
|
||||
{
|
||||
m_iterator.reserve(sizeof...(W) + 1);
|
||||
m_mediapaths.reserve(sizeof...(W) + 1);
|
||||
set_searchpaths(std::forward<T>(searchpath), std::forward<U>(x), std::forward<V>(y), std::forward<W>(z)...);
|
||||
}
|
||||
virtual ~emu_file();
|
||||
|
||||
// getters
|
||||
@ -96,20 +149,15 @@ public:
|
||||
const char *fullpath() const { return m_fullpath.c_str(); }
|
||||
u32 openflags() const { return m_openflags; }
|
||||
util::hash_collection &hashes(const char *types);
|
||||
bool restrict_to_mediapath() const { return m_restrict_to_mediapath; }
|
||||
bool part_of_mediapath(std::string path);
|
||||
|
||||
// setters
|
||||
void remove_on_close() { m_remove_on_close = true; }
|
||||
void set_openflags(u32 openflags) { assert(!m_file); m_openflags = openflags; }
|
||||
void set_restrict_to_mediapath(bool rtmp = true) { m_restrict_to_mediapath = rtmp; }
|
||||
void set_restrict_to_mediapath(int rtmp) { m_restrict_to_mediapath = rtmp; }
|
||||
|
||||
// open/close
|
||||
osd_file::error open(const std::string &name);
|
||||
osd_file::error open(const std::string &name, u32 crc);
|
||||
osd_file::error open(const std::string &name1, const std::string &name2, u32 crc);
|
||||
osd_file::error open(const std::string &name1, const std::string &name2, const std::string &name3, u32 crc);
|
||||
osd_file::error open(const std::string &name1, const std::string &name2, const std::string &name3, const std::string &name4, u32 crc);
|
||||
osd_file::error open_next();
|
||||
osd_file::error open_ram(const void *data, u32 length);
|
||||
void close();
|
||||
@ -142,7 +190,26 @@ public:
|
||||
void flush();
|
||||
|
||||
private:
|
||||
bool compressed_file_ready(void);
|
||||
emu_file(u32 openflags, empty_t);
|
||||
emu_file(path_iterator &&searchpath, u32 openflags);
|
||||
|
||||
template <typename T>
|
||||
void set_searchpaths(T &&searchpath, u32 openflags)
|
||||
{
|
||||
m_iterator.emplace_back(searchpath, "");
|
||||
m_mediapaths.emplace_back(std::forward<T>(searchpath), "");
|
||||
m_openflags = openflags;
|
||||
}
|
||||
template <typename T, typename U, typename V, typename... W>
|
||||
void set_searchpaths(T &&searchpath, U &&x, V &&y, W &&... z)
|
||||
{
|
||||
m_iterator.emplace_back(searchpath, "");
|
||||
m_mediapaths.emplace_back(std::forward<T>(searchpath), "");
|
||||
set_searchpaths(std::forward<U>(x), std::forward<V>(y), std::forward<W>(z)...);
|
||||
}
|
||||
|
||||
bool part_of_mediapath(const std::string &path);
|
||||
bool compressed_file_ready();
|
||||
|
||||
// internal helpers
|
||||
osd_file::error attempt_zipped();
|
||||
@ -152,18 +219,36 @@ private:
|
||||
std::string m_filename; // original filename provided
|
||||
std::string m_fullpath; // full filename
|
||||
util::core_file::ptr m_file; // core file pointer
|
||||
path_iterator m_iterator; // iterator for paths
|
||||
path_iterator m_mediapaths; // media-path iterator
|
||||
searchpath_vector m_iterator; // iterator for paths
|
||||
searchpath_vector m_mediapaths; // media-path iterator
|
||||
bool m_first; // true if this is the start of iteration
|
||||
u32 m_crc; // file's CRC
|
||||
u32 m_openflags; // flags we used for the open
|
||||
util::hash_collection m_hashes; // collection of hashes
|
||||
|
||||
std::unique_ptr<util::archive_file> m_zipfile; // ZIP file pointer
|
||||
std::vector<u8> m_zipdata; // ZIP file data
|
||||
u64 m_ziplength; // ZIP file length
|
||||
std::vector<u8> m_zipdata; // ZIP file data
|
||||
u64 m_ziplength; // ZIP file length
|
||||
|
||||
bool m_remove_on_close; // flag: remove the file when closing
|
||||
bool m_restrict_to_mediapath; // flag: restrict to paths inside the media-path
|
||||
bool m_remove_on_close; // flag: remove the file when closing
|
||||
int m_restrict_to_mediapath; // flag: restrict to paths inside the media-path
|
||||
};
|
||||
|
||||
|
||||
extern template path_iterator::path_iterator(char *&, int);
|
||||
extern template path_iterator::path_iterator(char * const &, int);
|
||||
extern template path_iterator::path_iterator(char const *&, int);
|
||||
extern template path_iterator::path_iterator(char const * const &, int);
|
||||
extern template path_iterator::path_iterator(std::vector<std::string> &, int);
|
||||
extern template path_iterator::path_iterator(const std::vector<std::string> &, int);
|
||||
|
||||
extern template emu_file::emu_file(std::string &, u32);
|
||||
extern template emu_file::emu_file(const std::string &, u32);
|
||||
extern template emu_file::emu_file(char *&, u32);
|
||||
extern template emu_file::emu_file(char * const &, u32);
|
||||
extern template emu_file::emu_file(char const *&, u32);
|
||||
extern template emu_file::emu_file(char const * const &, u32);
|
||||
extern template emu_file::emu_file(std::vector<std::string> &, u32);
|
||||
extern template emu_file::emu_file(const std::vector<std::string> &, u32);
|
||||
|
||||
#endif // MAME_EMU_FILEIO_H
|
||||
|
@ -1561,11 +1561,12 @@ void render_target::load_additional_layout_files(const char *basename, bool have
|
||||
bool have_override = false;
|
||||
|
||||
// if override_artwork defined, load that and skip artwork other than default
|
||||
if (m_manager.machine().options().override_artwork())
|
||||
const char *const override_art = m_manager.machine().options().override_artwork();
|
||||
if (override_art && *override_art)
|
||||
{
|
||||
if (load_layout_file(m_manager.machine().options().override_artwork(), m_manager.machine().options().override_artwork()))
|
||||
if (load_layout_file(override_art, override_art))
|
||||
have_override = true;
|
||||
else if (load_layout_file(m_manager.machine().options().override_artwork(), "default"))
|
||||
else if (load_layout_file(override_art, "default"))
|
||||
have_override = true;
|
||||
}
|
||||
|
||||
@ -1582,7 +1583,7 @@ void render_target::load_additional_layout_files(const char *basename, bool have
|
||||
have_artwork = true;
|
||||
|
||||
// if a default view has been specified, use that as a fallback
|
||||
if (system.default_layout != nullptr)
|
||||
if (system.default_layout)
|
||||
have_default |= load_layout_file(nullptr, *system.default_layout);
|
||||
m_manager.machine().config().apply_default_layouts(
|
||||
[this, &have_default] (device_t &dev, internal_layout const &layout)
|
||||
@ -1590,36 +1591,30 @@ void render_target::load_additional_layout_files(const char *basename, bool have
|
||||
|
||||
// try to load another file based on the parent driver name
|
||||
int cloneof = driver_list::clone(system);
|
||||
if (cloneof != -1)
|
||||
while (0 <= cloneof)
|
||||
{
|
||||
if (!load_layout_file(driver_list::driver(cloneof).name, driver_list::driver(cloneof).name))
|
||||
have_artwork |= load_layout_file(driver_list::driver(cloneof).name, "default");
|
||||
else
|
||||
have_artwork = true;
|
||||
|
||||
// Check the parent of the parent to cover bios based artwork
|
||||
const game_driver &parent(driver_list::driver(cloneof));
|
||||
cloneof = driver_list::clone(parent);
|
||||
}
|
||||
|
||||
// Check the parent of the parent to cover bios based artwork
|
||||
if (cloneof != -1) {
|
||||
const game_driver &clone(driver_list::driver(cloneof));
|
||||
int cloneofclone = driver_list::clone(clone);
|
||||
if (cloneofclone != -1 && cloneofclone != cloneof)
|
||||
// Use fallback artwork if defined and no artwork has been found yet
|
||||
if (!have_artwork)
|
||||
{
|
||||
const char *const fallback_art = m_manager.machine().options().fallback_artwork();
|
||||
if (fallback_art && *fallback_art)
|
||||
{
|
||||
if (!load_layout_file(driver_list::driver(cloneofclone).name, driver_list::driver(cloneofclone).name))
|
||||
have_artwork |= load_layout_file(driver_list::driver(cloneofclone).name, "default");
|
||||
if (!load_layout_file(fallback_art, fallback_art))
|
||||
have_artwork |= load_layout_file(fallback_art, "default");
|
||||
else
|
||||
have_artwork = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Use fallback artwork if defined and no artwork has been found yet
|
||||
if (!have_artwork && m_manager.machine().options().fallback_artwork())
|
||||
{
|
||||
if (!load_layout_file(m_manager.machine().options().fallback_artwork(), m_manager.machine().options().fallback_artwork()))
|
||||
have_artwork |= load_layout_file(m_manager.machine().options().fallback_artwork(), "default");
|
||||
else
|
||||
have_artwork = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// local screen info to avoid repeated code
|
||||
@ -2041,6 +2036,7 @@ bool render_target::load_layout_file(const char *dirname, const char *filename)
|
||||
|
||||
// attempt to open the file; bail if we can't
|
||||
emu_file layoutfile(m_manager.machine().options().art_path(), OPEN_FLAG_READ);
|
||||
layoutfile.set_restrict_to_mediapath(1);
|
||||
osd_file::error const filerr(layoutfile.open(fname));
|
||||
if (filerr != osd_file::error::NONE)
|
||||
return false;
|
||||
|
@ -15,6 +15,9 @@
|
||||
#include "softlist_dev.h"
|
||||
#include "ui/uimain.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
|
||||
|
||||
#define LOG_LOAD 0
|
||||
#define LOG(...) do { if (LOG_LOAD) debugload(__VA_ARGS__); } while(0)
|
||||
@ -30,28 +33,108 @@
|
||||
HELPERS (also used by diimage.cpp)
|
||||
***************************************************************************/
|
||||
|
||||
static osd_file::error common_process_file(emu_options &options, const char *location, const char *ext, const rom_entry *romp, emu_file &image_file)
|
||||
{
|
||||
return (location && *location)
|
||||
? image_file.open(util::string_format("%s" PATH_SEPARATOR "%s%s", location, ROM_GETNAME(romp), ext))
|
||||
: image_file.open(std::string(ROM_GETNAME(romp)) + ext);
|
||||
}
|
||||
namespace {
|
||||
|
||||
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)
|
||||
rom_entry const *next_parent_system(game_driver const *&system, std::vector<rom_entry> &rom_entries)
|
||||
{
|
||||
auto image_file = std::make_unique<emu_file>(options.media_path(), OPEN_FLAG_READ);
|
||||
|
||||
if (has_crc)
|
||||
filerr = image_file->open(location, PATH_SEPARATOR, ROM_GETNAME(romp), crc);
|
||||
if (!system)
|
||||
return nullptr;
|
||||
int const parent(driver_list::find(system->parent));
|
||||
if (0 > parent)
|
||||
{
|
||||
system = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
filerr = image_file->open(util::string_format("%s" PATH_SEPARATOR "%s", location, ROM_GETNAME(romp)));
|
||||
|
||||
if (filerr != osd_file::error::NONE)
|
||||
image_file = nullptr;
|
||||
|
||||
return image_file;
|
||||
{
|
||||
system = &driver_list::driver(parent);
|
||||
rom_entries = rom_build_entries(system->rom);
|
||||
return &rom_entries[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
chd_error 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)
|
||||
{
|
||||
// hashes are fixed, but we might need to try multiple filenames
|
||||
std::set<std::string> tried;
|
||||
const util::hash_collection hashes(ROM_GETHASHDATA(romp));
|
||||
std::string filename, fullpath;
|
||||
const rom_entry *parent(nullptr);
|
||||
chd_error result(CHDERR_FILE_NOT_FOUND);
|
||||
while (romp && (CHDERR_NONE != result))
|
||||
{
|
||||
filename = ROM_GETNAME(romp);
|
||||
filename.append(".chd");
|
||||
if (tried.insert(filename).second)
|
||||
{
|
||||
// piggyback on emu_file to find the disk image file
|
||||
std::unique_ptr<emu_file> imgfile;
|
||||
for (const std::vector<std::string> &paths : searchpath)
|
||||
{
|
||||
imgfile.reset(new emu_file(options.media_path(), paths, OPEN_FLAG_READ));
|
||||
imgfile->set_restrict_to_mediapath(1);
|
||||
const osd_file::error filerr(imgfile->open(filename, OPEN_FLAG_READ));
|
||||
if (osd_file::error::NONE == 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.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// walk the parents looking for a CHD with the same hashes but a different name
|
||||
if (CHDERR_NONE != 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;
|
||||
}
|
||||
while (ROMENTRY_ISPARAMETER(parent) || ROMENTRY_ISSYSTEM_BIOS(parent) || ROMENTRY_ISDEFAULT_BIOS(parent))
|
||||
++parent;
|
||||
if (ROMENTRY_ISEND(parent))
|
||||
parent = nullptr;
|
||||
}
|
||||
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(ROM_GETHASHDATA(romp)) == hashes))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
ROM LOADING
|
||||
***************************************************************************/
|
||||
@ -506,7 +589,7 @@ 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(const char *regiontag, 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(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)
|
||||
{
|
||||
osd_file::error filerr = osd_file::error::NOT_FOUND;
|
||||
u32 const romsize = rom_file_size(romp);
|
||||
@ -520,93 +603,13 @@ std::unique_ptr<emu_file> rom_load_manager::open_rom_file(const char *regiontag,
|
||||
bool const has_crc = util::hash_collection(ROM_GETHASHDATA(romp)).crc(crc);
|
||||
|
||||
// attempt reading up the chain through the parents
|
||||
// It also automatically attempts any kind of load by checksum supported by the archives.
|
||||
// it also automatically attempts any kind of load by checksum supported by the archives.
|
||||
std::unique_ptr<emu_file> result;
|
||||
for (int drv = driver_list::find(machine().system()); !result && (0 <= drv); drv = driver_list::clone(drv))
|
||||
for (const std::vector<std::string> &paths : searchpath)
|
||||
{
|
||||
tried_file_names.emplace_back(driver_list::driver(drv).name);
|
||||
result = 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 (!result && regiontag)
|
||||
{
|
||||
// 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);
|
||||
|
||||
// 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 & 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)
|
||||
throw emu_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.emplace_back(tag1);
|
||||
result = common_process_file(machine().options(), tag1.c_str(), has_crc, crc, romp, filerr);
|
||||
}
|
||||
else
|
||||
{
|
||||
// try to load from list/setname
|
||||
if (!result && (tag2.c_str() != nullptr)) // FIXME: std::string::c_str will never return nullptr
|
||||
{
|
||||
tried_file_names.emplace_back(tag2);
|
||||
result = common_process_file(machine().options(), tag2.c_str(), has_crc, crc, romp, filerr);
|
||||
}
|
||||
// try to load from list/parentname
|
||||
if (!result && has_parent && (tag3.c_str() != nullptr)) // FIXME: std::string::c_str will never return nullptr
|
||||
{
|
||||
tried_file_names.emplace_back(tag3);
|
||||
result = common_process_file(machine().options(), tag3.c_str(), has_crc, crc, romp, filerr);
|
||||
}
|
||||
// try to load from setname
|
||||
if (!result && (tag4.c_str() != nullptr)) // FIXME: std::string::c_str will never return nullptr
|
||||
{
|
||||
tried_file_names.emplace_back(tag4);
|
||||
result = common_process_file(machine().options(), tag4.c_str(), has_crc, crc, romp, filerr);
|
||||
}
|
||||
// try to load from parentname
|
||||
if (!result && has_parent && (tag5.c_str() != nullptr)) // FIXME: std::string::c_str will never return nullptr
|
||||
{
|
||||
tried_file_names.emplace_back(tag5);
|
||||
result = common_process_file(machine().options(), tag5.c_str(), has_crc, crc, romp, filerr);
|
||||
}
|
||||
}
|
||||
result = open_rom_file(paths, tried_file_names, has_crc, crc, ROM_GETNAME(romp), filerr);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
|
||||
// update counters
|
||||
@ -621,6 +624,27 @@ std::unique_ptr<emu_file> rom_load_manager::open_rom_file(const char *regiontag,
|
||||
}
|
||||
|
||||
|
||||
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, const std::string &name, osd_file::error &filerr)
|
||||
{
|
||||
// record the set names we search
|
||||
tried.insert(tried.end(), paths.begin(), paths.end());
|
||||
|
||||
// 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);
|
||||
|
||||
// don't return anything if unsuccessful
|
||||
if (osd_file::error::NONE != filerr)
|
||||
return nullptr;
|
||||
else
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
rom_fread - cheesy fread that fills with
|
||||
random data for a nullptr file
|
||||
@ -824,7 +848,7 @@ void rom_load_manager::copy_rom_data(const rom_entry *romp)
|
||||
for a region
|
||||
-------------------------------------------------*/
|
||||
|
||||
void rom_load_manager::process_rom_entries(const device_t &device, const char *regiontag, const rom_entry *parent_region, const rom_entry *romp, bool from_list)
|
||||
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)
|
||||
{
|
||||
u32 lastflags = 0;
|
||||
std::vector<std::string> tried_file_names;
|
||||
@ -845,7 +869,7 @@ void rom_load_manager::process_rom_entries(const device_t &device, const char *r
|
||||
|
||||
if (ROMENTRY_ISFILL(romp))
|
||||
{
|
||||
if (!ROM_GETBIOSFLAGS(romp) || ROM_GETBIOSFLAGS(romp) == device.system_bios())
|
||||
if (!ROM_GETBIOSFLAGS(romp) || (ROM_GETBIOSFLAGS(romp) == bios))
|
||||
fill_rom_data(romp);
|
||||
|
||||
romp++;
|
||||
@ -857,7 +881,7 @@ void rom_load_manager::process_rom_entries(const device_t &device, const char *r
|
||||
else if (ROMENTRY_ISFILE(romp))
|
||||
{
|
||||
// handle files
|
||||
bool const irrelevantbios = (ROM_GETBIOSFLAGS(romp) != 0) && (ROM_GETBIOSFLAGS(romp) != device.system_bios());
|
||||
bool const irrelevantbios = (ROM_GETBIOSFLAGS(romp) != 0) && (ROM_GETBIOSFLAGS(romp) != bios);
|
||||
rom_entry const *baserom = romp;
|
||||
int explength = 0;
|
||||
|
||||
@ -866,7 +890,7 @@ void rom_load_manager::process_rom_entries(const device_t &device, const char *r
|
||||
std::unique_ptr<emu_file> file;
|
||||
if (!irrelevantbios)
|
||||
{
|
||||
file = open_rom_file(regiontag, romp, tried_file_names, from_list);
|
||||
file = open_rom_file(searchpath, romp, tried_file_names, from_list);
|
||||
if (!file)
|
||||
handle_missing_file(romp, tried_file_names, CHDERR_NONE);
|
||||
}
|
||||
@ -925,187 +949,13 @@ void rom_load_manager::process_rom_entries(const device_t &device, const char *r
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
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)
|
||||
throw emu_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)
|
||||
{
|
||||
// TODO: use system name and/or software list name in the path - the current setup doesn't scale
|
||||
std::string fname = std::string(ROM_GETNAME(romp)).append(".dif");
|
||||
|
||||
/* try to open the diff */
|
||||
@ -1149,11 +999,11 @@ 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(std::initializer_list<std::reference_wrapper<const std::vector<std::string> > > searchpath, const char *regiontag, const rom_entry *romp, std::function<const rom_entry * ()> next_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());
|
||||
[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 */
|
||||
for ( ; !ROMENTRY_ISREGIONEND(romp); romp++)
|
||||
@ -1162,16 +1012,15 @@ void rom_load_manager::process_disk_entries(const char *regiontag, const rom_ent
|
||||
if (ROMENTRY_ISFILE(romp))
|
||||
{
|
||||
auto chd = std::make_unique<open_chd>(regiontag);
|
||||
|
||||
util::hash_collection hashes(ROM_GETHASHDATA(romp));
|
||||
chd_error err;
|
||||
|
||||
/* make the filename of the source */
|
||||
std::string filename = std::string(ROM_GETNAME(romp)).append(".chd");
|
||||
const std::string filename = std::string(ROM_GETNAME(romp)).append(".chd");
|
||||
|
||||
/* 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 = chd_error(open_disk_image(machine().options(), &machine().system(), romp, chd->orig_chd(), locationtag));
|
||||
err = do_open_disk(machine().options(), searchpath, romp, chd->orig_chd(), next_parent);
|
||||
if (err != CHDERR_NONE)
|
||||
{
|
||||
handle_missing_file(romp, std::vector<std::string>(), err);
|
||||
@ -1184,6 +1033,7 @@ void rom_load_manager::process_disk_entries(const char *regiontag, const rom_ent
|
||||
acthashes.add_sha1(chd->orig_chd().sha1());
|
||||
|
||||
/* verify the hash */
|
||||
const util::hash_collection hashes(ROM_GETHASHDATA(romp));
|
||||
if (hashes != acthashes)
|
||||
{
|
||||
m_errorstring.append(string_format("%s WRONG CHECKSUMS:\n", filename));
|
||||
@ -1218,6 +1068,57 @@ void rom_load_manager::process_disk_entries(const char *regiontag, const rom_ent
|
||||
}
|
||||
|
||||
|
||||
chd_error rom_load_manager::open_disk_image(const 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 = [sys = &driver->system(), roms = std::vector<rom_entry>()] () mutable { return next_parent_system(sys, roms); };
|
||||
else
|
||||
next_parent = [] () { return nullptr; };
|
||||
return do_open_disk(options, { searchpath }, romp, image_chd, std::move(next_parent));
|
||||
}
|
||||
|
||||
|
||||
chd_error 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::vector<software_info const *> parents;
|
||||
std::vector<std::string> listsearch, freesearch, disksearch;
|
||||
disksearch.emplace_back(swlist.list_name());
|
||||
|
||||
for (software_info const *i = &swinfo; i; )
|
||||
{
|
||||
if (std::find(parents.begin(), parents.end(), i) != parents.end())
|
||||
break;
|
||||
parents.emplace_back(i);
|
||||
listsearch.emplace_back(util::string_format("%s" PATH_SEPARATOR "%s", swlist.list_name(), i->shortname()));
|
||||
freesearch.emplace_back(i->shortname());
|
||||
i = i->parentname().empty() ? nullptr : swlist.find(i->parentname());
|
||||
}
|
||||
|
||||
auto part(parents.front()->parts().end());
|
||||
return do_open_disk(
|
||||
options,
|
||||
{ listsearch, freesearch, disksearch },
|
||||
romp,
|
||||
image_chd,
|
||||
[&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];
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
normalize_flags_for_device - modify the region
|
||||
flags for the given device
|
||||
@ -1266,9 +1167,6 @@ void rom_load_manager::normalize_flags_for_device(const char *rgntag, u8 &width,
|
||||
|
||||
void rom_load_manager::load_software_part_region(device_t &device, software_list_device &swlist, const char *swname, const rom_entry *start_region)
|
||||
{
|
||||
std::string locationtag(swlist.list_name()), breakstr("%");
|
||||
const rom_entry *region;
|
||||
|
||||
m_errorstring.clear();
|
||||
m_softwarningstring.clear();
|
||||
|
||||
@ -1276,10 +1174,16 @@ void rom_load_manager::load_software_part_region(device_t &device, software_list
|
||||
m_romstotalsize = 0;
|
||||
m_romsloadedsize = 0;
|
||||
|
||||
std::vector<const software_info *> parents;
|
||||
std::vector<std::string> listsearch, freesearch, disksearch, devsearch;
|
||||
listsearch.emplace_back(util::string_format("%s" PATH_SEPARATOR "%s", swlist.list_name(), swname));
|
||||
freesearch.emplace_back(swname);
|
||||
const software_info *swinfo = swlist.find(swname);
|
||||
if (swinfo != nullptr)
|
||||
if (swinfo)
|
||||
{
|
||||
u32 supported = swinfo->supported();
|
||||
// dispay a warning for unsupported software
|
||||
// TODO: list supported clones like we do for machines?
|
||||
const u32 supported(swinfo->supported());
|
||||
if (supported == SOFTWARE_SUPPORTED_PARTIAL)
|
||||
{
|
||||
m_errorstring.append(string_format("WARNING: support for software %s (in list %s) is only partial\n", swname, swlist.list_name()));
|
||||
@ -1291,34 +1195,45 @@ void rom_load_manager::load_software_part_region(device_t &device, software_list
|
||||
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)
|
||||
// walk the chain of parents and add them to the search path
|
||||
parents.emplace_back(swinfo);
|
||||
swinfo = !swinfo->parentname().empty() ? swlist.find(swinfo->parentname()) : nullptr;
|
||||
while (swinfo)
|
||||
{
|
||||
locationtag.append(swinfo->shortname()).append(breakstr);
|
||||
if (std::find(parents.begin(), parents.end(), swinfo) != parents.end())
|
||||
{
|
||||
m_errorstring.append(util::string_format("WARNING: parent/clone relationships form a loop for software %s (in list %s)\n", swname, swlist.list_name()));
|
||||
m_softwarningstring.append(util::string_format("Parent/clone relationships from a loop for software %s (in list %s)\n", swname, swlist.list_name()));
|
||||
break;
|
||||
}
|
||||
parents.emplace_back(swinfo);
|
||||
listsearch.emplace_back(util::string_format("%s" PATH_SEPARATOR "%s", swlist.list_name(), swinfo->shortname()));
|
||||
freesearch.emplace_back(swinfo->shortname());
|
||||
swinfo = !swinfo->parentname().empty() ? swlist.find(swinfo->parentname()) : nullptr;
|
||||
}
|
||||
// strip the final '%'
|
||||
locationtag.erase(locationtag.length() - 1, 1);
|
||||
}
|
||||
|
||||
// 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))
|
||||
// for historical reasons, add the search path for the software list device's owner
|
||||
const device_t *const listowner = swlist.owner();
|
||||
if (listowner)
|
||||
devsearch = listowner->searchpath();
|
||||
|
||||
// loop until we hit the end
|
||||
std::function<const rom_entry * ()> next_parent;
|
||||
for (const rom_entry *region = start_region; region != nullptr; region = rom_next_region(region))
|
||||
{
|
||||
u32 regionlength = ROMREGION_GETLENGTH(region);
|
||||
|
||||
std::string regiontag = device.subtag(ROMREGION_GETTAG(region));
|
||||
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);
|
||||
@ -1326,47 +1241,76 @@ void rom_load_manager::load_software_part_region(device_t &device, software_list
|
||||
{
|
||||
normalize_flags_for_device(regiontag.c_str(), 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 */
|
||||
// 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))
|
||||
if (ROMREGION_ISERASE(region)) // clear the region if it's requested
|
||||
memset(m_region->base(), ROMREGION_GETERASEVAL(region), m_region->bytes());
|
||||
|
||||
/* or if it's sufficiently small (<= 4MB) */
|
||||
else if (m_region->bytes() <= 0x400000)
|
||||
else if (m_region->bytes() <= 0x400000) // or if it's sufficiently small (<= 4MB)
|
||||
memset(m_region->base(), 0, m_region->bytes());
|
||||
|
||||
#ifdef MAME_DEBUG
|
||||
/* if we're debugging, fill region with random data to catch errors */
|
||||
else
|
||||
else // if we're debugging, fill region with random data to catch errors
|
||||
fill_random(m_region->base(), m_region->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(device, locationtag.c_str(), region, region + 1, true);
|
||||
{
|
||||
if (devsearch.empty())
|
||||
process_rom_entries({ listsearch, freesearch }, 0U, region, region + 1, true);
|
||||
else
|
||||
process_rom_entries({ listsearch, freesearch, devsearch }, 0U, 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())
|
||||
{
|
||||
auto part(parents.front()->parts().end());
|
||||
next_parent =
|
||||
[&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];
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
next_parent = [] () { return nullptr; };
|
||||
}
|
||||
}
|
||||
if (devsearch.empty())
|
||||
process_disk_entries({ listsearch, freesearch, disksearch }, regiontag.c_str(), region + 1, next_parent);
|
||||
else
|
||||
process_disk_entries({ listsearch, freesearch, disksearch, devsearch }, regiontag.c_str(), region + 1, next_parent);
|
||||
}
|
||||
}
|
||||
|
||||
/* now go back and post-process all the regions */
|
||||
for (region = start_region; region != nullptr; region = rom_next_region(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(ROMREGION_GETTAG(region)), ROMREGION_ISINVERTED(region));
|
||||
|
||||
/* display the results and exit */
|
||||
// display the results and exit
|
||||
display_rom_load_results(true);
|
||||
}
|
||||
|
||||
@ -1377,10 +1321,13 @@ void rom_load_manager::load_software_part_region(device_t &device, software_list
|
||||
|
||||
void rom_load_manager::process_region_list()
|
||||
{
|
||||
/* loop until we hit the end */
|
||||
// loop until we hit the end
|
||||
device_iterator deviter(machine().root_device());
|
||||
std::vector<std::string> searchpath;
|
||||
for (device_t &device : deviter)
|
||||
{
|
||||
searchpath.clear();
|
||||
std::function<const rom_entry * ()> next_parent;
|
||||
for (const rom_entry *region = rom_first_region(device); region != nullptr; region = rom_next_region(region))
|
||||
{
|
||||
u32 regionlength = ROMREGION_GETLENGTH(region);
|
||||
@ -1388,17 +1335,17 @@ void rom_load_manager::process_region_list()
|
||||
std::string regiontag = device.subtag(ROM_GETNAME(region));
|
||||
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 */
|
||||
// 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());
|
||||
|
||||
@ -1412,11 +1359,25 @@ void rom_load_manager::process_region_list()
|
||||
#endif
|
||||
|
||||
// now process the entries in the region
|
||||
process_rom_entries(device, device.shortname(), region, region + 1, false);
|
||||
if (searchpath.empty())
|
||||
searchpath = device.searchpath();
|
||||
assert(!searchpath.empty());
|
||||
process_rom_entries({ searchpath }, device.system_bios(), 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 = [sys = &driver->system(), roms = std::vector<rom_entry>()] () mutable { return next_parent_system(sys, roms); };
|
||||
else
|
||||
next_parent = [] () { return nullptr; };
|
||||
}
|
||||
process_disk_entries({ searchpath }, regiontag.c_str(), region + 1, next_parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,15 +6,18 @@
|
||||
|
||||
ROM loading functions.
|
||||
*********************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef MAME_EMU_ROMLOAD_H
|
||||
#define MAME_EMU_ROMLOAD_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "chd.h"
|
||||
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
@ -420,6 +423,10 @@ public:
|
||||
|
||||
void load_software_part_region(device_t &device, software_list_device &swlist, const char *swname, const rom_entry *start_region);
|
||||
|
||||
/* open a disk image, searching up the parent and loading by checksum */
|
||||
static chd_error open_disk_image(const emu_options &options, const device_t &device, const rom_entry *romp, chd_file &image_chd);
|
||||
static chd_error open_disk_image(const emu_options &options, software_list_device &swlist, const software_info &swinfo, const rom_entry *romp, chd_file &image_chd);
|
||||
|
||||
private:
|
||||
void determine_bios_rom(device_t &device, const char *specbios);
|
||||
void count_roms();
|
||||
@ -430,18 +437,18 @@ 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(const char *regiontag, const rom_entry *romp, std::vector<std::string> &tried_file_names, bool from_list);
|
||||
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, const std::string &name, osd_file::error &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(const device_t &device, const char *regiontag, const rom_entry *parent_region, const rom_entry *romp, bool from_list);
|
||||
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);
|
||||
chd_error open_disk_diff(emu_options &options, const rom_entry *romp, chd_file &source, chd_file &diff_chd);
|
||||
void process_disk_entries(const char *regiontag, const rom_entry *parent_region, const rom_entry *romp, const char *locationtag);
|
||||
void process_disk_entries(std::initializer_list<std::reference_wrapper<const std::vector<std::string> > > searchpath, const char *regiontag, const rom_entry *romp, std::function<const rom_entry * ()> next_parent);
|
||||
void normalize_flags_for_device(const char *rgntag, u8 &width, endianness_t &endian);
|
||||
void process_region_list();
|
||||
|
||||
|
||||
// internal state
|
||||
running_machine & m_machine; // reference to our machine
|
||||
|
||||
@ -465,8 +472,6 @@ private:
|
||||
|
||||
/* ----- Helpers ----- */
|
||||
|
||||
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);
|
||||
|
||||
/* return pointer to the first ROM region within a source */
|
||||
const rom_entry *rom_first_region(const device_t &device);
|
||||
|
||||
@ -491,8 +496,4 @@ const rom_entry *rom_next_parameter(const rom_entry *romp);
|
||||
// builds a rom_entry vector from a tiny_rom_entry array
|
||||
std::vector<rom_entry> rom_build_entries(const tiny_rom_entry *tinyentries);
|
||||
|
||||
|
||||
/* 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);
|
||||
|
||||
#endif // MAME_EMU_ROMLOAD_H
|
||||
|
@ -9,10 +9,11 @@
|
||||
***************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "emuopts.h"
|
||||
#include "diimage.h"
|
||||
#include "romload.h"
|
||||
#include "softlist_dev.h"
|
||||
|
||||
#include "diimage.h"
|
||||
#include "emuopts.h"
|
||||
#include "romload.h"
|
||||
#include "validity.h"
|
||||
|
||||
#include <cctype>
|
||||
|
@ -9,14 +9,19 @@
|
||||
***************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "emuopts.h"
|
||||
#include "audit.h"
|
||||
#include "chd.h"
|
||||
|
||||
#include "sound/samples.h"
|
||||
|
||||
#include "emuopts.h"
|
||||
#include "drivenum.h"
|
||||
#include "romload.h"
|
||||
#include "sound/samples.h"
|
||||
#include "softlist_dev.h"
|
||||
|
||||
#include "chd.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// CORE FUNCTIONS
|
||||
@ -29,7 +34,6 @@
|
||||
media_auditor::media_auditor(const driver_enumerator &enumerator)
|
||||
: m_enumerator(enumerator)
|
||||
, m_validation(AUDIT_VALIDATE_FULL)
|
||||
, m_searchpath()
|
||||
{
|
||||
}
|
||||
|
||||
@ -53,22 +57,19 @@ media_auditor::summary media_auditor::audit_media(const char *validation)
|
||||
std::size_t shared_required = 0;
|
||||
|
||||
// iterate over devices and regions
|
||||
std::vector<std::string> searchpath;
|
||||
for (device_t &device : device_iterator(m_enumerator.config()->root_device()))
|
||||
{
|
||||
// determine the search path for this source and iterate through the regions
|
||||
m_searchpath.clear();
|
||||
for (const std::string &path : device.searchpath())
|
||||
{
|
||||
if (!m_searchpath.empty())
|
||||
m_searchpath += ';';
|
||||
m_searchpath += path;
|
||||
}
|
||||
searchpath.clear();
|
||||
|
||||
// now iterate over regions and ROMs within
|
||||
for (const rom_entry *region = rom_first_region(device); region; region = rom_next_region(region))
|
||||
{
|
||||
for (const rom_entry *rom = rom_first_file(region); rom; rom = rom_next_file(rom))
|
||||
{
|
||||
if (searchpath.empty())
|
||||
searchpath = device.searchpath();
|
||||
|
||||
char const *const name(ROM_GETNAME(rom));
|
||||
util::hash_collection const hashes(ROM_GETHASHDATA(rom));
|
||||
device_t *const shared_device(find_shared_device(device, name, hashes, ROM_GETLENGTH(rom)));
|
||||
@ -83,9 +84,9 @@ media_auditor::summary media_auditor::audit_media(const char *validation)
|
||||
|
||||
audit_record *record = nullptr;
|
||||
if (ROMREGION_ISROMDATA(region))
|
||||
record = &audit_one_rom(rom);
|
||||
record = &audit_one_rom(searchpath, rom);
|
||||
else if (ROMREGION_ISDISKDATA(region))
|
||||
record = &audit_one_disk(rom, nullptr);
|
||||
record = &audit_one_disk(rom, device);
|
||||
|
||||
if (record)
|
||||
{
|
||||
@ -126,12 +127,32 @@ media_auditor::summary media_auditor::audit_device(device_t &device, const char
|
||||
|
||||
// store validation for later
|
||||
m_validation = validation;
|
||||
m_searchpath = device.shortname();
|
||||
|
||||
std::size_t found = 0;
|
||||
std::size_t required = 0;
|
||||
|
||||
audit_regions(rom_first_region(device), nullptr, found, required);
|
||||
std::vector<std::string> searchpath;
|
||||
audit_regions(
|
||||
[this, &device, &searchpath] (rom_entry const *region, rom_entry const *rom) -> audit_record const *
|
||||
{
|
||||
if (ROMREGION_ISROMDATA(region))
|
||||
{
|
||||
if (searchpath.empty())
|
||||
searchpath = device.searchpath();
|
||||
return &audit_one_rom(searchpath, rom);
|
||||
}
|
||||
else if (ROMREGION_ISDISKDATA(region))
|
||||
{
|
||||
return &audit_one_disk(rom, device);
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
},
|
||||
rom_first_region(device),
|
||||
found,
|
||||
required);
|
||||
|
||||
if ((found == 0) && (required > 0))
|
||||
{
|
||||
@ -147,7 +168,7 @@ media_auditor::summary media_auditor::audit_device(device_t &device, const char
|
||||
//-------------------------------------------------
|
||||
// audit_software
|
||||
//-------------------------------------------------
|
||||
media_auditor::summary media_auditor::audit_software(const std::string &list_name, const software_info *swinfo, const char *validation)
|
||||
media_auditor::summary media_auditor::audit_software(software_list_device &swlist, const software_info &swinfo, const char *validation)
|
||||
{
|
||||
// start fresh
|
||||
m_record_list.clear();
|
||||
@ -155,21 +176,57 @@ media_auditor::summary media_auditor::audit_software(const std::string &list_nam
|
||||
// store validation for later
|
||||
m_validation = validation;
|
||||
|
||||
std::string combinedpath(util::string_format("%s;%s%s%s", swinfo->shortname(), list_name, PATH_SEPARATOR, swinfo->shortname()));
|
||||
std::string locationtag(util::string_format("%s%%%s%%", list_name, swinfo->shortname()));
|
||||
if (!swinfo->parentname().empty())
|
||||
{
|
||||
locationtag.append(swinfo->parentname());
|
||||
combinedpath.append(util::string_format(";%s;%s%s%s", swinfo->parentname(), list_name, PATH_SEPARATOR, swinfo->parentname()));
|
||||
}
|
||||
m_searchpath = combinedpath;
|
||||
|
||||
std::size_t found = 0;
|
||||
std::size_t required = 0;
|
||||
|
||||
// now iterate over software parts
|
||||
for (const software_part &part : swinfo->parts())
|
||||
audit_regions(part.romdata().data(), locationtag.c_str(), found, required);
|
||||
std::vector<std::string> searchpath;
|
||||
auto const do_audit =
|
||||
[this, &swlist, &swinfo, &searchpath] (rom_entry const *region, rom_entry const *rom) -> audit_record const *
|
||||
{
|
||||
if (ROMREGION_ISROMDATA(region))
|
||||
{
|
||||
if (searchpath.empty())
|
||||
{
|
||||
std::vector<software_info const *> parents;
|
||||
|
||||
// search <rompath>/<list>/<software> following parents
|
||||
searchpath.emplace_back(util::string_format("%s" PATH_SEPARATOR "%s", swlist.list_name(), swinfo.shortname()));
|
||||
for (software_info const *i = &swinfo; i && !i->parentname().empty(); i = swlist.find(i->parentname()))
|
||||
{
|
||||
if (std::find(parents.begin(), parents.end(), i) != parents.end())
|
||||
{
|
||||
osd_printf_warning("WARNING: software parent/clone relationships form a loop (%s:%s)\n", swlist.list_name(), swinfo.shortname());
|
||||
break;
|
||||
}
|
||||
parents.emplace_back(i);
|
||||
searchpath.emplace_back(util::string_format("%s" PATH_SEPARATOR "%s", swlist.list_name(), i->parentname()));
|
||||
}
|
||||
|
||||
// search <rompath>/<software> following parents
|
||||
searchpath.emplace_back(swinfo.shortname());
|
||||
parents.clear();
|
||||
for (software_info const *i = &swinfo; i && !i->parentname().empty(); i = swlist.find(i->parentname()))
|
||||
{
|
||||
if (std::find(parents.begin(), parents.end(), i) != parents.end())
|
||||
break;
|
||||
parents.emplace_back(i);
|
||||
searchpath.emplace_back(i->parentname());
|
||||
}
|
||||
}
|
||||
return &audit_one_rom(searchpath, rom);
|
||||
}
|
||||
else if (ROMREGION_ISDISKDATA(region))
|
||||
{
|
||||
return &audit_one_disk(rom, swlist, swinfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
for (const software_part &part : swinfo.parts())
|
||||
audit_regions(do_audit, part.romdata().data(), found, required);
|
||||
|
||||
if ((found == 0) && (required > 0))
|
||||
{
|
||||
@ -178,7 +235,7 @@ media_auditor::summary media_auditor::audit_software(const std::string &list_nam
|
||||
}
|
||||
|
||||
// return a summary
|
||||
return summarize(list_name.c_str());
|
||||
return summarize(swlist.list_name().c_str());
|
||||
}
|
||||
|
||||
|
||||
@ -342,25 +399,22 @@ media_auditor::summary media_auditor::summarize(const char *name, std::ostream *
|
||||
// audit_regions - validate/count for regions
|
||||
//-------------------------------------------------
|
||||
|
||||
void media_auditor::audit_regions(const rom_entry *region, const char *locationtag, std::size_t &found, std::size_t &required)
|
||||
template <typename T>
|
||||
void media_auditor::audit_regions(T do_audit, const rom_entry *region, std::size_t &found, std::size_t &required)
|
||||
{
|
||||
// now iterate over regions
|
||||
std::vector<std::string> searchpath;
|
||||
for ( ; region; region = rom_next_region(region))
|
||||
{
|
||||
// now iterate over rom definitions
|
||||
for (const rom_entry *rom = rom_first_file(region); rom; rom = rom_next_file(rom))
|
||||
for (rom_entry const *rom = rom_first_file(region); rom; rom = rom_next_file(rom))
|
||||
{
|
||||
util::hash_collection const hashes(ROM_GETHASHDATA(rom));
|
||||
|
||||
// count the number of files with hashes
|
||||
util::hash_collection const hashes(ROM_GETHASHDATA(rom));
|
||||
if (!hashes.flag(util::hash_collection::FLAG_NO_DUMP) && !ROM_ISOPTIONAL(rom))
|
||||
required++;
|
||||
|
||||
audit_record const *record = nullptr;
|
||||
if (ROMREGION_ISROMDATA(region))
|
||||
record = &audit_one_rom(rom);
|
||||
else if (ROMREGION_ISDISKDATA(region))
|
||||
record = &audit_one_disk(rom, locationtag);
|
||||
audit_record const *const record = do_audit(region, rom);
|
||||
|
||||
// count the number of files that are found.
|
||||
if (record && ((record->status() == audit_status::GOOD) || (record->status() == audit_status::FOUND_INVALID)))
|
||||
@ -374,7 +428,7 @@ void media_auditor::audit_regions(const rom_entry *region, const char *locationt
|
||||
// audit_one_rom - validate a single ROM entry
|
||||
//-------------------------------------------------
|
||||
|
||||
media_auditor::audit_record &media_auditor::audit_one_rom(const rom_entry *rom)
|
||||
media_auditor::audit_record &media_auditor::audit_one_rom(const std::vector<std::string> &searchpath, const rom_entry *rom)
|
||||
{
|
||||
// allocate and append a new record
|
||||
audit_record &record = *m_record_list.emplace(m_record_list.end(), *rom, media_type::ROM);
|
||||
@ -384,27 +438,19 @@ media_auditor::audit_record &media_auditor::audit_one_rom(const rom_entry *rom)
|
||||
bool const has_crc = record.expected_hashes().crc(crc);
|
||||
|
||||
// find the file and checksum it, getting the file length along the way
|
||||
emu_file file(m_enumerator.options().media_path(), OPEN_FLAG_READ | OPEN_FLAG_NO_PRELOAD);
|
||||
file.set_restrict_to_mediapath(true);
|
||||
path_iterator path(m_searchpath);
|
||||
std::string curpath;
|
||||
// FIXME: needs to be adjusted to match ROM loading behaviour
|
||||
while (path.next(curpath, record.name()))
|
||||
{
|
||||
// open the file if we can
|
||||
osd_file::error filerr;
|
||||
if (has_crc)
|
||||
filerr = file.open(curpath, crc);
|
||||
else
|
||||
filerr = file.open(curpath);
|
||||
emu_file file(m_enumerator.options().media_path(), searchpath, OPEN_FLAG_READ | OPEN_FLAG_NO_PRELOAD);
|
||||
file.set_restrict_to_mediapath(1);
|
||||
|
||||
// if it worked, get the actual length and hashes, then stop
|
||||
if (filerr == osd_file::error::NONE)
|
||||
{
|
||||
record.set_actual(file.hashes(m_validation), file.size());
|
||||
break;
|
||||
}
|
||||
}
|
||||
// open the file if we can
|
||||
osd_file::error filerr;
|
||||
if (has_crc)
|
||||
filerr = file.open(record.name(), crc);
|
||||
else
|
||||
filerr = file.open(record.name());
|
||||
|
||||
// if it worked, get the actual length and hashes, then stop
|
||||
if (filerr == osd_file::error::NONE)
|
||||
record.set_actual(file.hashes(m_validation), file.size());
|
||||
|
||||
// compute the final status
|
||||
compute_status(record, rom, record.actual_length() != 0);
|
||||
@ -416,14 +462,15 @@ media_auditor::audit_record &media_auditor::audit_one_rom(const rom_entry *rom)
|
||||
// audit_one_disk - validate a single disk entry
|
||||
//-------------------------------------------------
|
||||
|
||||
media_auditor::audit_record &media_auditor::audit_one_disk(const rom_entry *rom, const char *locationtag)
|
||||
template <typename... T>
|
||||
media_auditor::audit_record &media_auditor::audit_one_disk(const rom_entry *rom, T &&... args)
|
||||
{
|
||||
// allocate and append a new record
|
||||
audit_record &record = *m_record_list.emplace(m_record_list.end(), *rom, media_type::DISK);
|
||||
|
||||
// open the disk
|
||||
chd_file source;
|
||||
chd_error err = chd_error(open_disk_image(m_enumerator.options(), &m_enumerator.driver(), rom, source, locationtag));
|
||||
const chd_error err = rom_load_manager::open_disk_image(m_enumerator.options(), std::forward<T>(args)..., rom, source);
|
||||
|
||||
// if we succeeded, get the hashes
|
||||
if (err == CHDERR_NONE)
|
||||
|
@ -7,12 +7,11 @@
|
||||
ROM, disk, and sample auditing functions.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef MAME_FRONTEND_AUDIT_H
|
||||
#define MAME_FRONTEND_AUDIT_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "hash.h"
|
||||
|
||||
#include <iosfwd>
|
||||
@ -38,6 +37,7 @@
|
||||
|
||||
// forward declarations
|
||||
class driver_enumerator;
|
||||
class software_list_device;
|
||||
|
||||
|
||||
|
||||
@ -137,15 +137,15 @@ public:
|
||||
|
||||
private:
|
||||
// internal state
|
||||
media_type m_type; // type of item that was audited
|
||||
audit_status m_status; // status of audit on this item
|
||||
audit_substatus m_substatus; // finer-detail status
|
||||
const char * m_name; // name of item
|
||||
uint64_t m_explength; // expected length of item
|
||||
uint64_t m_length; // actual length of item
|
||||
util::hash_collection m_exphashes; // expected hash data
|
||||
util::hash_collection m_hashes; // actual hash information
|
||||
device_t * m_shared_device; // device that shares the rom
|
||||
media_type m_type; // type of item that was audited
|
||||
audit_status m_status; // status of audit on this item
|
||||
audit_substatus m_substatus; // finer-detail status
|
||||
const char * m_name; // name of item
|
||||
uint64_t m_explength; // expected length of item
|
||||
uint64_t m_length; // actual length of item
|
||||
util::hash_collection m_exphashes; // expected hash data
|
||||
util::hash_collection m_hashes; // actual hash information
|
||||
device_t * m_shared_device; // device that shares the rom
|
||||
};
|
||||
using record_list = std::list<audit_record>;
|
||||
|
||||
@ -158,15 +158,15 @@ public:
|
||||
// audit operations
|
||||
summary audit_media(const char *validation = AUDIT_VALIDATE_FULL);
|
||||
summary audit_device(device_t &device, const char *validation = AUDIT_VALIDATE_FULL);
|
||||
summary audit_software(const std::string &list_name, const software_info *swinfo, const char *validation = AUDIT_VALIDATE_FULL);
|
||||
summary audit_software(software_list_device &swlist, const software_info &swinfo, const char *validation = AUDIT_VALIDATE_FULL);
|
||||
summary audit_samples();
|
||||
summary summarize(const char *name, std::ostream *output = nullptr) const;
|
||||
|
||||
private:
|
||||
// internal helpers
|
||||
void audit_regions(const rom_entry *region, const char *locationtag, std::size_t &found, std::size_t &required);
|
||||
audit_record &audit_one_rom(const rom_entry *rom);
|
||||
audit_record &audit_one_disk(const rom_entry *rom, const char *locationtag);
|
||||
template <typename T> void audit_regions(T do_audit, const rom_entry *region, std::size_t &found, std::size_t &required);
|
||||
audit_record &audit_one_rom(const std::vector<std::string> &searchpath, const rom_entry *rom);
|
||||
template <typename... T> audit_record &audit_one_disk(const rom_entry *rom, T &&... args);
|
||||
void compute_status(audit_record &record, const rom_entry *rom, bool found);
|
||||
device_t *find_shared_device(device_t &device, const char *name, const util::hash_collection &romhashes, uint64_t romlength);
|
||||
|
||||
@ -174,7 +174,6 @@ private:
|
||||
record_list m_record_list;
|
||||
const driver_enumerator & m_enumerator;
|
||||
const char * m_validation;
|
||||
std::string m_searchpath;
|
||||
};
|
||||
|
||||
|
||||
|
@ -1279,7 +1279,7 @@ void cli_frontend::verifysoftware(const std::vector<std::string> &args)
|
||||
nrlists++;
|
||||
for (const software_info &swinfo : swlistdev.get_info())
|
||||
{
|
||||
media_auditor::summary summary = auditor.audit_software(swlistdev.list_name(), &swinfo, AUDIT_VALIDATE_FAST);
|
||||
media_auditor::summary summary = auditor.audit_software(swlistdev, swinfo, AUDIT_VALIDATE_FAST);
|
||||
|
||||
print_summary(
|
||||
auditor, summary, false,
|
||||
@ -1386,7 +1386,7 @@ void cli_frontend::verifysoftlist(const std::vector<std::string> &args)
|
||||
// Get the actual software list contents
|
||||
for (const software_info &swinfo : swlistdev.get_info())
|
||||
{
|
||||
media_auditor::summary summary = auditor.audit_software(swlistdev.list_name(), &swinfo, AUDIT_VALIDATE_FAST);
|
||||
media_auditor::summary summary = auditor.audit_software(swlistdev, swinfo, AUDIT_VALIDATE_FAST);
|
||||
|
||||
print_summary(
|
||||
auditor, summary, false,
|
||||
|
@ -138,7 +138,7 @@ void menu_control_device_image::load_software_part()
|
||||
driver_enumerator drivlist(machine().options(), machine().options().system_name());
|
||||
drivlist.next();
|
||||
media_auditor auditor(drivlist);
|
||||
media_auditor::summary summary = auditor.audit_software(m_sld->list_name(), (software_info *)m_swi, AUDIT_VALIDATE_FAST);
|
||||
media_auditor::summary summary = auditor.audit_software(*m_sld, *m_swi, AUDIT_VALIDATE_FAST);
|
||||
// if everything looks good, load software
|
||||
if (summary == media_auditor::CORRECT || summary == media_auditor::BEST_AVAILABLE || summary == media_auditor::NONE_NEEDED)
|
||||
{
|
||||
|
@ -897,7 +897,7 @@ void menu_select_game::inkey_select_favorite(const event *menu_event)
|
||||
software_list_device *swlist = software_list_device::find_by_name(*drv.config(), ui_swinfo->listname);
|
||||
const software_info *swinfo = swlist->find(ui_swinfo->shortname);
|
||||
|
||||
media_auditor::summary const summary = auditor.audit_software(swlist->list_name(), swinfo, AUDIT_VALIDATE_FAST);
|
||||
media_auditor::summary const summary = auditor.audit_software(*swlist, *swinfo, AUDIT_VALIDATE_FAST);
|
||||
|
||||
if (summary == media_auditor::CORRECT || summary == media_auditor::BEST_AVAILABLE || summary == media_auditor::NONE_NEEDED)
|
||||
{
|
||||
|
@ -2282,8 +2282,7 @@ void menu_select_launch::arts_render(float origx1, float origy1, float origx2, f
|
||||
// loads the image if necessary
|
||||
if (!m_cache->snapx_driver_is(driver) || !snapx_valid() || m_switch_image)
|
||||
{
|
||||
emu_file snapfile(searchstr.c_str(), OPEN_FLAG_READ);
|
||||
snapfile.set_restrict_to_mediapath(true);
|
||||
emu_file snapfile(searchstr, OPEN_FLAG_READ);
|
||||
bitmap_argb32 tmp_bitmap;
|
||||
|
||||
// try to load snapshot first from saved "0000.png" file
|
||||
|
@ -486,7 +486,7 @@ void menu_select_software::inkey_select(const event *menu_event)
|
||||
software_list_device *swlist = software_list_device::find_by_name(*drivlist.config(), ui_swinfo->listname);
|
||||
const software_info *swinfo = swlist->find(ui_swinfo->shortname);
|
||||
|
||||
media_auditor::summary const summary = auditor.audit_software(swlist->list_name(), swinfo, AUDIT_VALIDATE_FAST);
|
||||
media_auditor::summary const summary = auditor.audit_software(*swlist, *swinfo, AUDIT_VALIDATE_FAST);
|
||||
|
||||
if (summary == media_auditor::CORRECT || summary == media_auditor::BEST_AVAILABLE || summary == media_auditor::NONE_NEEDED)
|
||||
{
|
||||
|
@ -39926,7 +39926,7 @@ tvcapcom //
|
||||
theboat //
|
||||
|
||||
@source:tvgame.cpp
|
||||
tvgame //
|
||||
tvgame // 2011
|
||||
|
||||
@source:twin16.cpp
|
||||
cuebrickj // GX903 (c) 1989 (Japan)
|
||||
|
Loading…
Reference in New Issue
Block a user