summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/diimage.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/diimage.cpp')
-rw-r--r--src/emu/diimage.cpp1118
1 files changed, 455 insertions, 663 deletions
diff --git a/src/emu/diimage.cpp b/src/emu/diimage.cpp
index 953e89dc42c..59d1523a6b1 100644
--- a/src/emu/diimage.cpp
+++ b/src/emu/diimage.cpp
@@ -2,7 +2,7 @@
// copyright-holders:Miodrag Milanovic
/***************************************************************************
- diimage.c
+ diimage.cpp
Device image interfaces.
@@ -11,44 +11,20 @@
#include "emu.h"
#include "emuopts.h"
-#include "drivenum.h"
+#include "fileio.h"
#include "romload.h"
-#include "ui/uimain.h"
-#include "zippath.h"
#include "softlist.h"
#include "softlist_dev.h"
-#include "formats/ioprocs.h"
-
-#include <regex>
+#include "corestr.h"
+#include "opresolv.h"
+#include "path.h"
+#include "zippath.h"
-//**************************************************************************
-// DEVICE CONFIG IMAGE INTERFACE
-//**************************************************************************
-const image_device_type_info device_image_interface::m_device_info_array[] =
- {
- { IO_UNKNOWN, "unknown", "unkn" }, /* 0 */
- { IO_CARTSLOT, "cartridge", "cart" }, /* 1 */
- { IO_FLOPPY, "floppydisk", "flop" }, /* 2 */
- { IO_HARDDISK, "harddisk", "hard" }, /* 3 */
- { IO_CYLINDER, "cylinder", "cyln" }, /* 4 */
- { IO_CASSETTE, "cassette", "cass" }, /* 5 */
- { IO_PUNCHCARD, "punchcard", "pcrd" }, /* 6 */
- { IO_PUNCHTAPE, "punchtape", "ptap" }, /* 7 */
- { IO_PRINTER, "printout", "prin" }, /* 8 */
- { IO_SERIAL, "serial", "serl" }, /* 9 */
- { IO_PARALLEL, "parallel", "parl" }, /* 10 */
- { IO_SNAPSHOT, "snapshot", "dump" }, /* 11 */
- { IO_QUICKLOAD, "quickload", "quik" }, /* 12 */
- { IO_MEMCARD, "memcard", "memc" }, /* 13 */
- { IO_CDROM, "cdrom", "cdrm" }, /* 14 */
- { IO_MAGTAPE, "magtape", "magt" }, /* 15 */
- { IO_ROM, "romimage", "rom" }, /* 16 */
- { IO_MIDIIN, "midiin", "min" }, /* 17 */
- { IO_MIDIOUT, "midiout", "mout" }, /* 18 */
- { IO_PICTURE, "picture", "pic" }, /* 19 */
- { IO_VIDEO, "vidfile", "vid" } /* 20 */
- };
+#include <algorithm>
+#include <cstring>
+#include <regex>
+#include <sstream>
//**************************************************************************
@@ -89,16 +65,18 @@ image_device_format::~image_device_format()
device_image_interface::device_image_interface(const machine_config &mconfig, device_t &device)
: device_interface(device, "image")
- , m_err()
, m_file()
, m_mame_file()
+ , m_default_region(-1)
+ , m_current_region(-1)
, m_software_part_ptr(nullptr)
- , m_supported(0)
+ , m_sequence_counter(0)
, m_readonly(false)
, m_created(false)
, m_create_format(0)
, m_create_args(nullptr)
, m_user_loadable(true)
+ , m_must_be_loaded(false)
, m_is_loading(false)
, m_is_reset_and_loading(false)
{
@@ -113,6 +91,17 @@ device_image_interface::~device_image_interface()
{
}
+//-------------------------------------------------
+// add_region - register a region that may
+// have a chd image
+//-------------------------------------------------
+void device_image_interface::add_region(std::string name, bool is_default)
+{
+ if (is_default)
+ m_default_region = m_possible_preset_regions.size();
+ m_possible_preset_regions.push_back(name);
+}
+
//-------------------------------------------------
// interface_config_complete - perform any
@@ -126,75 +115,150 @@ void device_image_interface::interface_config_complete()
update_names();
}
-
//-------------------------------------------------
-// find_device_type - search trough list of
-// device types to extract data
+// check_preset_images - lookup the CHDs from the
+// region(s), if any
//-------------------------------------------------
-const image_device_type_info *device_image_interface::find_device_type(iodevice_t type)
+void device_image_interface::check_preset_images()
{
- int i;
- for (i = 0; i < ARRAY_LENGTH(device_image_interface::m_device_info_array); i++)
+ if (!m_possible_preset_regions.empty())
+ {
+ for(const auto &r : m_possible_preset_regions)
+ m_preset_images.push_back(device().machine().rom_load().get_disk_handle(":" + r));
+ if (m_default_region != -1 && m_preset_images[m_default_region])
+ m_current_region = m_default_region;
+ else
+ {
+ for (m_current_region = 0; m_current_region != int(m_preset_images.size()) && !m_preset_images[m_current_region]; m_current_region++);
+ if (m_current_region == int(m_preset_images.size()))
+ fatalerror("%s: No configured region has an image\n", device().tag());
+ }
+ set_image_tag();
+ set_user_loadable(false);
+ }
+ else
{
- if (m_device_info_array[i].m_type == type)
- return &m_device_info_array[i];
+ std::string tag = device().owner()->tag();
+ auto *const chd = device().machine().rom_load().get_disk_handle(tag);
+ if (chd)
+ {
+ m_possible_preset_regions.emplace_back(std::move(tag));
+ m_preset_images.push_back(chd);
+ m_current_region = 0;
+ set_image_tag();
+ set_user_loadable(false);
+ }
}
- return nullptr;
}
//-------------------------------------------------
-// device_typename - retrieves device type name
+// has_preset_images - does the device have an
+// image to retrieve through current_image_*
//-------------------------------------------------
-const char *device_image_interface::device_typename(iodevice_t type)
+bool device_image_interface::has_preset_images() const
{
- const image_device_type_info *info = find_device_type(type);
- return (info != nullptr) ? info->m_name : "unknown";
+ return !m_possible_preset_regions.empty();
}
//-------------------------------------------------
-// device_brieftypename - retrieves device
-// brief type name
+// has_preset_images - does the device have
+// multiple preset images with user selection
//-------------------------------------------------
-const char *device_image_interface::device_brieftypename(iodevice_t type)
+bool device_image_interface::has_preset_images_selection() const
{
- const image_device_type_info *info = find_device_type(type);
- return (info != nullptr) ? info->m_shortname : "unk";
+ int icount = 0;
+ for (const auto *f : m_preset_images)
+ if (f)
+ icount ++;
+ return icount > 1;
}
+
//-------------------------------------------------
-// device_typeid - retrieves device type id
+// preset_images_list -- generate the list of
+// available image names
//-------------------------------------------------
-iodevice_t device_image_interface::device_typeid(const char *name)
+std::vector<std::string> device_image_interface::preset_images_list() const
{
- int i;
- for (i = 0; i < ARRAY_LENGTH(device_image_interface::m_device_info_array); i++)
- {
- if (!core_stricmp(name, m_device_info_array[i].m_name) || !core_stricmp(name, m_device_info_array[i].m_shortname))
- return m_device_info_array[i].m_type;
- }
- return (iodevice_t)-1;
+ std::vector<std::string> result;
+ for (unsigned int i = 0; i != m_preset_images.size(); i++)
+ if (m_preset_images[i])
+ result.push_back(m_possible_preset_regions[i]);
+ return result;
+}
+
+//-------------------------------------------------
+// current_preset_image_id -- current image id,
+// recomputed to ignore non-present images.
+// returns -1 if not in preset mode
+//-------------------------------------------------
+
+int device_image_interface::current_preset_image_id() const
+{
+ if (m_current_region == -1)
+ return -1;
+ int id = 0;
+ for (int i = 0; i != m_current_region; i++)
+ if (m_preset_images[i])
+ id++;
+ return id;
+}
+
+//-------------------------------------------------
+// current_preset_image_chd -- return the chd of
+// the current active image, nullptr if non
+//-------------------------------------------------
+
+chd_file *device_image_interface::current_preset_image_chd() const
+{
+ if (m_current_region == -1)
+ return nullptr;
+ return m_preset_images[m_current_region];
+}
+
+//-------------------------------------------------
+// switch_preset_image -- change of preset image
+//-------------------------------------------------
+
+void device_image_interface::switch_preset_image(int id)
+{
+ for (unsigned int i = 0; i != m_preset_images.size(); i++)
+ if (m_preset_images[i])
+ {
+ if(!id)
+ {
+ call_unload();
+ m_current_region = i;
+ call_load();
+ break;
+ }
+ id--;
+ }
+
+ return;
}
+
//-------------------------------------------------
// set_image_filename - specifies the filename of
// an image
//-------------------------------------------------
-void device_image_interface::set_image_filename(const std::string &filename)
+void device_image_interface::set_image_filename(std::string_view filename)
{
m_image_name = filename;
- util::zippath_parent(m_working_directory, filename);
+ m_working_directory = util::zippath_parent(m_image_name);
m_basename.assign(m_image_name);
// find the last "path separator"
auto iter = std::find_if(
- m_image_name.rbegin(),
- m_image_name.rend(),
- [](char c) { return (c == '\\') || (c == '/') || (c == ':'); });
+ m_image_name.rbegin(),
+ m_image_name.rend(),
+ [] (char c) { return (c == '\\') || (c == '/') || (c == ':'); });
if (iter != m_image_name.rend())
m_basename.assign(iter.base(), m_image_name.end());
@@ -207,222 +271,119 @@ void device_image_interface::set_image_filename(const std::string &filename)
m_filetype = core_filename_extract_extension(m_basename, true);
}
-
-/****************************************************************************
- CREATION FORMATS
-****************************************************************************/
-
//-------------------------------------------------
-// device_get_named_creatable_format -
-// accesses a specific image format available for
-// image creation by name
-//-------------------------------------------------
-
-const image_device_format *device_image_interface::device_get_named_creatable_format(const std::string &format_name)
-{
- for (auto &format : m_formatlist)
- if (format->name() == format_name)
- return format.get();
- return nullptr;
-}
-
-
-//-------------------------------------------------
-// add_format
+// set_image_tag - specifies the filename of
+// an image as the device tag
//-------------------------------------------------
-void device_image_interface::add_format(std::unique_ptr<image_device_format> &&format)
+void device_image_interface::set_image_tag()
{
- m_formatlist.push_back(std::move(format));
+ m_image_name = device().owner()->tag();
+ m_working_directory = "";
+ m_basename = "";
+ m_basename_noext = "";
+ m_filetype = "";
}
//-------------------------------------------------
-// add_format
+// is_filetype - check if the filetype matches
//-------------------------------------------------
-void device_image_interface::add_format(std::string &&name, std::string &&description, std::string &&extensions, std::string &&optspec)
+bool device_image_interface::is_filetype(std::string_view candidate_filetype) const
{
- auto format = std::make_unique<image_device_format>(std::move(name), std::move(description), std::move(extensions), std::move(optspec));
- add_format(std::move(format));
+ return util::streqlower(m_filetype, candidate_filetype);
}
-/****************************************************************************
- ERROR HANDLING
-****************************************************************************/
-
//-------------------------------------------------
-// image_clear_error - clear out any specified
-// error
+// add_media_change_notifier - subscribe for
+// media change notifications
//-------------------------------------------------
-void device_image_interface::clear_error()
+util::notifier_subscription device_image_interface::add_media_change_notifier(delegate<void (media_change_event)> &&n)
{
- m_err = IMAGE_ERROR_SUCCESS;
- if (!m_err_message.empty())
- {
- m_err_message.clear();
- }
+ return m_media_change_notifier.subscribe(std::move(n));
}
+//***************************************************************************
+// CREATION FORMATS
+//***************************************************************************
//-------------------------------------------------
-// error - returns the error text for an image
-// error
+// device_get_named_creatable_format -
+// accesses a specific image format available for
+// image creation by name
//-------------------------------------------------
-static const char *const messages[] =
+const image_device_format *device_image_interface::device_get_named_creatable_format(std::string_view format_name) const noexcept
{
- "",
- "Internal error",
- "Unsupported operation",
- "Out of memory",
- "File not found",
- "Invalid image",
- "File already open",
- "Unspecified error"
-};
-
-const char *device_image_interface::error()
-{
- return (!m_err_message.empty()) ? m_err_message.c_str() : messages[m_err];
+ for (const auto &format : m_formatlist)
+ if (std::string_view(format->name()) == format_name)
+ return format.get();
+ return nullptr;
}
-
//-------------------------------------------------
-// seterror - specifies an error on an image
+// add_format
//-------------------------------------------------
-void device_image_interface::seterror(image_error_t err, const char *message)
+void device_image_interface::add_format(std::unique_ptr<image_device_format> &&format)
{
- clear_error();
- m_err = err;
- if (message != nullptr)
- {
- m_err_message = message;
- }
+ m_formatlist.push_back(std::move(format));
}
-
//-------------------------------------------------
-// message - used to display a message while
-// loading
+// add_format
//-------------------------------------------------
-void device_image_interface::message(const char *format, ...)
+void device_image_interface::add_format(std::string &&name, std::string &&description, std::string &&extensions, std::string &&optspec)
{
- va_list args;
- char buffer[256];
-
- /* format the message */
- va_start(args, format);
- vsnprintf(buffer, ARRAY_LENGTH(buffer), format, args);
- va_end(args);
-
- /* display the popup for a standard amount of time */
- device().machine().ui().popup_time(5, "%s: %s",
- basename(),
- buffer);
+ auto format = std::make_unique<image_device_format>(std::move(name), std::move(description), std::move(extensions), std::move(optspec));
+ add_format(std::move(format));
}
-/***************************************************************************
- WORKING DIRECTORIES
-***************************************************************************/
-
-//-------------------------------------------------
-// try_change_working_directory - tries to change
-// the working directory, but only if the directory
-// actually exists
-//-------------------------------------------------
-
-bool device_image_interface::try_change_working_directory(const std::string &subdir)
-{
- const osd::directory::entry *entry;
- bool success = false;
- bool done = false;
-
- auto directory = osd::directory::open(m_working_directory);
- if (directory)
- {
- while (!done && (entry = directory->read()) != nullptr)
- {
- if (!core_stricmp(subdir.c_str(), entry->name))
- {
- done = true;
- success = entry->type == osd::directory::entry::entry_type::DIR;
- }
- }
-
- directory.reset();
- }
-
- // did we successfully identify the directory?
- if (success)
- m_working_directory = util::zippath_combine(m_working_directory, subdir);
-
- return success;
-}
-
+//***************************************************************************
+// ERROR HANDLING
+//***************************************************************************
//-------------------------------------------------
-// setup_working_directory - sets up the working
-// directory according to a few defaults
+// error - returns the error text for an image
+// error
//-------------------------------------------------
-void device_image_interface::setup_working_directory()
+std::error_category const &image_category() noexcept
{
- bool success = false;
- // get user-specified directory and make sure it exists
- m_working_directory = device().mconfig().options().sw_path();
- // if multipath, get first
- size_t i = m_working_directory.find_first_of(";");
- if (i != std::string::npos)
- m_working_directory.resize(i);
- // validate directory
- if (!m_working_directory.empty())
- if (osd::directory::open(m_working_directory))
- success = true;
-
- // if not exist, use previous method
- if (!success)
+ class image_category_impl : public std::error_category
{
- // first set up the working directory to be the starting directory
- osd_get_full_path(m_working_directory, ".");
- // now try browsing down to "software"
- if (try_change_working_directory("software"))
- success = true;
- }
+ public:
+ virtual char const *name() const noexcept override { return "image"; }
- if (success)
- {
- // now down to a directory for this computer
- int gamedrv = driver_list::find(device().machine().system());
- while(gamedrv != -1 && !try_change_working_directory(driver_list::driver(gamedrv).name))
+ virtual std::string message(int condition) const override
{
- gamedrv = driver_list::compatible_with(gamedrv);
+ using namespace std::literals;
+ static std::string_view const s_messages[] = {
+ "No error"sv,
+ "Internal error"sv,
+ "Unsupported operation"sv,
+ "Invalid image"sv,
+ "Invalid image length"sv,
+ "File already open"sv,
+ "Unrecognized software item"sv,
+ "Invalid software item"sv,
+ "Unspecified error"sv };
+ if ((0 <= condition) && (std::size(s_messages) > condition))
+ return std::string(s_messages[condition]);
+ else
+ return "Unknown error"s;
}
- }
-}
-
-
-//-------------------------------------------------
-// working_directory - returns the working
-// directory to use for this image; this is
-// valid even if not mounted
-//-------------------------------------------------
-
-const std::string &device_image_interface::working_directory()
-{
- // check to see if we've never initialized the working directory
- if (m_working_directory.empty())
- setup_working_directory();
-
- return m_working_directory;
+ };
+ static image_category_impl const s_image_category_instance;
+ return s_image_category_instance;
}
@@ -431,7 +392,7 @@ const std::string &device_image_interface::working_directory()
// software_info structure from the softlist
//-------------------------------------------------
-const software_info *device_image_interface::software_entry() const
+const software_info *device_image_interface::software_entry() const noexcept
{
return !m_software_part_ptr ? nullptr : &m_software_part_ptr->info();
}
@@ -441,14 +402,13 @@ const software_info *device_image_interface::software_entry() const
// get_software_region
//-------------------------------------------------
-u8 *device_image_interface::get_software_region(const char *tag)
+u8 *device_image_interface::get_software_region(std::string_view tag)
{
if (!loaded_through_softlist())
return nullptr;
- std::string full_tag = util::string_format("%s:%s", device().tag(), tag);
- memory_region *region = device().machine().root_device().memregion(full_tag.c_str());
- return region != nullptr ? region->base() : nullptr;
+ memory_region *const region = device().memregion(tag);
+ return region ? region->base() : nullptr;
}
@@ -456,11 +416,13 @@ u8 *device_image_interface::get_software_region(const char *tag)
// image_get_software_region_length
//-------------------------------------------------
-u32 device_image_interface::get_software_region_length(const char *tag)
+u32 device_image_interface::get_software_region_length(std::string_view tag)
{
- std::string full_tag = util::string_format("%s:%s", device().tag(), tag);
- memory_region *region = device().machine().root_device().memregion(full_tag.c_str());
- return region != nullptr ? region->bytes() : 0;
+ if (!loaded_through_softlist())
+ return 0;
+
+ memory_region *const region = device().memregion(tag);
+ return region ? region->bytes() : 0;
}
@@ -468,7 +430,7 @@ u32 device_image_interface::get_software_region_length(const char *tag)
// image_get_feature
//-------------------------------------------------
-const char *device_image_interface::get_feature(const char *feature_name) const
+const char *device_image_interface::get_feature(std::string_view feature_name) const
{
return !m_software_part_ptr ? nullptr : m_software_part_ptr->feature(feature_name);
}
@@ -478,18 +440,18 @@ const char *device_image_interface::get_feature(const char *feature_name) const
// load_software_region -
//-------------------------------------------------
-bool device_image_interface::load_software_region(const char *tag, optional_shared_ptr<u8> &ptr)
+std::error_condition device_image_interface::load_software_region(std::string_view tag, std::unique_ptr<u8[]> &ptr)
{
size_t size = get_software_region_length(tag);
if (size)
{
- ptr.allocate(size);
-
- memcpy(ptr, get_software_region(tag), size);
+ ptr = std::make_unique<u8[]>(size);
+ memcpy(ptr.get(), get_software_region(tag), size);
+ return std::error_condition();
}
-
- return size > 0;
+ else
+ return image_error::UNSUPPORTED;
}
@@ -500,45 +462,30 @@ bool device_image_interface::load_software_region(const char *tag, optional_shar
// to be loaded
// ****************************************************************************
-bool device_image_interface::run_hash(util::core_file &file, u32 skip_bytes, util::hash_collection &hashes, const char *types)
+std::error_condition device_image_interface::run_hash(util::random_read &file, u32 skip_bytes, util::hash_collection &hashes, const char *types)
{
// reset the hash; we want to override existing data
hashes.reset();
// figure out the size, and "cap" the skip bytes
- u64 size = file.size();
- skip_bytes = (u32) std::min((u64) skip_bytes, size);
-
- // seek to the beginning
- file.seek(skip_bytes, SEEK_SET);
- u64 position = skip_bytes;
-
- // keep on reading hashes
- hashes.begin(types);
- while (position < size)
- {
- uint8_t buffer[8192];
-
- // read bytes
- const u32 count = (u32) std::min(size - position, (u64) sizeof(buffer));
- const u32 actual_count = file.read(buffer, count);
- if (actual_count == 0)
- return false;
- position += actual_count;
-
- // and compute the hashes
- hashes.buffer(buffer, actual_count);
- }
- hashes.end();
-
- // cleanup
- file.seek(0, SEEK_SET);
- return true;
+ u64 size;
+ std::error_condition filerr = file.length(size);
+ if (filerr)
+ return filerr;
+ skip_bytes = u32(std::min<u64>(skip_bytes, size));
+
+ // and compute the hashes
+ size_t actual_count;
+ filerr = hashes.compute(file, skip_bytes, size - skip_bytes, actual_count, types);
+ if (filerr)
+ return filerr;
+
+ return std::error_condition();
}
-bool device_image_interface::image_checkhash()
+std::error_condition device_image_interface::image_checkhash()
{
// only calculate CRC if it hasn't been calculated, and the open_mode is read only
u32 crcval;
@@ -546,26 +493,25 @@ bool device_image_interface::image_checkhash()
{
// do not cause a linear read of 600 megs please
// TODO: use SHA1 in the CHD header as the hash
- if (image_type() == IO_CDROM)
- return true;
+ if (image_is_chd_type())
+ return std::error_condition();
// Skip calculating the hash when we have an image mounted through a software list
if (loaded_through_softlist())
- return true;
+ return std::error_condition();
// run the hash
- if (!run_hash(*m_file, unhashed_header_length(), m_hash, util::hash_collection::HASH_TYPES_ALL))
- return false;
+ return run_hash(*m_file, unhashed_header_length(), m_hash, util::hash_collection::HASH_TYPES_ALL);
}
- return true;
+ return std::error_condition();
}
-util::hash_collection device_image_interface::calculate_hash_on_file(util::core_file &file) const
+util::hash_collection device_image_interface::calculate_hash_on_file(util::random_read &file) const
{
// calculate the hash
util::hash_collection hash;
- if (!run_hash(file, unhashed_header_length(), hash, util::hash_collection::HASH_TYPES_ALL))
+ if (run_hash(file, unhashed_header_length(), hash, util::hash_collection::HASH_TYPES_ALL))
hash.reset();
return hash;
}
@@ -576,39 +522,13 @@ u32 device_image_interface::crc()
u32 crc = 0;
image_checkhash();
- m_hash.crc(crc);
+ if (!m_hash.crc(crc))
+ crc = 0;
return crc;
}
-//-------------------------------------------------
-// support_command_line_image_creation - do we
-// want to support image creation from the front
-// end command line?
-//-------------------------------------------------
-
-bool device_image_interface::support_command_line_image_creation() const
-{
- bool result;
- switch (image_type())
- {
- case IO_PRINTER:
- case IO_SERIAL:
- case IO_PARALLEL:
- // going by the assumption that these device image types should support this
- // behavior; ideally we'd get rid of IO_* and just push this to the specific
- // devices
- result = true;
- break;
- default:
- result = false;
- break;
- }
- return result;
-}
-
-
// ****************************************************************************
// Battery functions
//
@@ -629,38 +549,36 @@ void device_image_interface::battery_load(void *buffer, int length, int fill)
if (!buffer || (length <= 0))
throw emu_fatalerror("device_image_interface::battery_load: Must specify sensical buffer/length");
- osd_file::error filerr;
- int bytes_read = 0;
- std::string fname = std::string(device().machine().system().name).append(PATH_SEPARATOR).append(m_basename_noext.c_str()).append(".nv");
+ std::string const fname = std::string(device().machine().system().name).append(PATH_SEPARATOR).append(m_basename_noext).append(".nv");
/* try to open the battery file and read it in, if possible */
emu_file file(device().machine().options().nvram_directory(), OPEN_FLAG_READ);
- filerr = file.open(fname);
- if (filerr == osd_file::error::NONE)
+ std::error_condition const filerr = file.open(fname);
+ int bytes_read = 0;
+ if (!filerr)
bytes_read = file.read(buffer, length);
// fill remaining bytes (if necessary)
memset(((char *)buffer) + bytes_read, fill, length - bytes_read);
}
-void device_image_interface::battery_load(void *buffer, int length, void *def_buffer)
+void device_image_interface::battery_load(void *buffer, int length, const void *def_buffer)
{
if (!buffer || (length <= 0))
throw emu_fatalerror("device_image_interface::battery_load: Must specify sensical buffer/length");
- osd_file::error filerr;
- int bytes_read = 0;
- std::string fname = std::string(device().machine().system().name).append(PATH_SEPARATOR).append(m_basename_noext.c_str()).append(".nv");
+ std::string const fname = std::string(device().machine().system().name).append(PATH_SEPARATOR).append(m_basename_noext).append(".nv");
// try to open the battery file and read it in, if possible
emu_file file(device().machine().options().nvram_directory(), OPEN_FLAG_READ);
- filerr = file.open(fname);
- if (filerr == osd_file::error::NONE)
+ std::error_condition const filerr = file.open(fname);
+ int bytes_read = 0;
+ if (!filerr)
bytes_read = file.read(buffer, length);
- // if no file was present, copy the default battery
- if (bytes_read == 0 && def_buffer)
- memcpy((char *)buffer, (char *)def_buffer, length);
+ // if no file was present, copy the default contents
+ if (!bytes_read && def_buffer)
+ std::memcpy(buffer, def_buffer, length);
}
@@ -679,111 +597,45 @@ void device_image_interface::battery_save(const void *buffer, int length)
if (!device().machine().options().nvram_save())
return;
- std::string fname = std::string(device().machine().system().name).append(PATH_SEPARATOR).append(m_basename_noext.c_str()).append(".nv");
+ std::string fname = std::string(device().machine().system().name).append(PATH_SEPARATOR).append(m_basename_noext).append(".nv");
// try to open the battery file and write it out, if possible
emu_file file(device().machine().options().nvram_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
- osd_file::error filerr = file.open(fname);
- if (filerr == osd_file::error::NONE)
+ std::error_condition const filerr = file.open(fname);
+ if (!filerr)
file.write(buffer, length);
}
-//-------------------------------------------------
-// uses_file_extension - update configuration
-// based on completed device setup
-//-------------------------------------------------
-
-bool device_image_interface::uses_file_extension(const char *file_extension) const
-{
- bool result = false;
-
- if (file_extension[0] == '.')
- file_extension++;
-
- /* find the extensions */
- std::string extensions(file_extensions());
- char *ext = strtok((char*)extensions.c_str(),",");
- while (ext != nullptr)
- {
- if (!core_stricmp(ext, file_extension))
- {
- result = true;
- break;
- }
- ext = strtok (nullptr, ",");
- }
- return result;
-}
-
-
// ***************************************************************************
// IMAGE LOADING
// ***************************************************************************
//-------------------------------------------------
-// is_loaded - quick check to determine whether an
-// image is loaded
-//-------------------------------------------------
-
-bool device_image_interface::is_loaded()
-{
- return (m_file != nullptr);
-}
-
-//-------------------------------------------------
-// image_error_from_file_error - converts an image
-// error to a file error
-//-------------------------------------------------
-
-image_error_t device_image_interface::image_error_from_file_error(osd_file::error filerr)
-{
- switch (filerr)
- {
- case osd_file::error::NONE:
- return IMAGE_ERROR_SUCCESS;
-
- case osd_file::error::NOT_FOUND:
- case osd_file::error::ACCESS_DENIED:
- // file not found (or otherwise cannot open)
- return IMAGE_ERROR_FILENOTFOUND;
-
- case osd_file::error::OUT_OF_MEMORY:
- // out of memory
- return IMAGE_ERROR_OUTOFMEMORY;
-
- case osd_file::error::ALREADY_OPEN:
- // this shouldn't happen
- return IMAGE_ERROR_ALREADYOPEN;
-
- case osd_file::error::FAILURE:
- case osd_file::error::TOO_MANY_FILES:
- case osd_file::error::INVALID_DATA:
- default:
- // other errors
- return IMAGE_ERROR_INTERNAL;
- }
-}
-
-
-//-------------------------------------------------
// load_image_by_path - loads an image with a
// specific path
//-------------------------------------------------
-image_error_t device_image_interface::load_image_by_path(u32 open_flags, const std::string &path)
+std::error_condition device_image_interface::load_image_by_path(u32 open_flags, std::string_view path)
{
std::string revised_path;
// attempt to read the file
- auto const filerr = util::zippath_fopen(path, open_flags, m_file, revised_path);
- if (filerr != osd_file::error::NONE)
- return image_error_from_file_error(filerr);
+ auto filerr = util::zippath_fopen(path, open_flags, m_file, revised_path);
+ if (filerr)
+ {
+ osd_printf_verbose("%s: error opening image file %s with flags=%08X (%s:%d %s)\n", device().tag(), path, open_flags, filerr.category().name(), filerr.value(), filerr.message());
+ return filerr;
+ }
+ else
+ {
+ osd_printf_verbose("%s: opened image file %s with flags=%08X\n", device().tag(), path, open_flags);
+ }
m_readonly = (open_flags & OPEN_FLAG_WRITE) ? 0 : 1;
m_created = (open_flags & OPEN_FLAG_CREATE) ? 1 : 0;
set_image_filename(revised_path);
- return IMAGE_ERROR_SUCCESS;
+ return std::error_condition();
}
@@ -791,7 +643,7 @@ image_error_t device_image_interface::load_image_by_path(u32 open_flags, const s
// reopen_for_write
//-------------------------------------------------
-int device_image_interface::reopen_for_write(const std::string &path)
+std::error_condition device_image_interface::reopen_for_write(std::string_view path)
{
m_file.reset();
@@ -799,15 +651,15 @@ int device_image_interface::reopen_for_write(const std::string &path)
// attempt to open the file for writing
auto const filerr = util::zippath_fopen(path, OPEN_FLAG_READ|OPEN_FLAG_WRITE|OPEN_FLAG_CREATE, m_file, revised_path);
- if (filerr != osd_file::error::NONE)
- return image_error_from_file_error(filerr);
+ if (filerr)
+ return filerr;
// success!
m_readonly = 0;
m_created = 1;
set_image_filename(revised_path);
- return IMAGE_ERROR_SUCCESS;
+ return std::error_condition();
}
@@ -820,71 +672,64 @@ std::vector<u32> device_image_interface::determine_open_plan(bool is_create)
{
std::vector<u32> open_plan;
- // emit flags into a vector
- if (!is_create && is_readable() && is_writeable())
- open_plan.push_back(OPEN_FLAG_READ | OPEN_FLAG_WRITE);
- if (!is_create && !is_readable() && is_writeable())
- open_plan.push_back(OPEN_FLAG_WRITE);
- if (!is_create && is_readable())
- open_plan.push_back(OPEN_FLAG_READ);
- if (is_create && is_writeable() && is_creatable())
- open_plan.push_back(OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE);
+ if (!is_create)
+ {
+ if (is_writeable())
+ open_plan.push_back(is_readable() ? (OPEN_FLAG_READ | OPEN_FLAG_WRITE) : OPEN_FLAG_WRITE);
+ if (is_readable())
+ open_plan.push_back(OPEN_FLAG_READ);
+ }
+ else if (is_writeable() && is_creatable())
+ {
+ if (is_readable())
+ open_plan.push_back(OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE);
+ else
+ open_plan.push_back(OPEN_FLAG_WRITE | OPEN_FLAG_CREATE);
+ }
return open_plan;
}
//-------------------------------------------------
-// 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().c_str());
- osd_printf_error(" FOUND: %s\n", acthashes.macro_string().c_str());
-}
-
-
-//-------------------------------------------------
// verify_length_and_hash - verify the length
// and hash signatures of a file
//-------------------------------------------------
-static int verify_length_and_hash(emu_file *file, const char *name, u32 explength, const util::hash_collection &hashes)
+static int verify_length_and_hash(emu_file *file, std::string_view 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());
+ util::hash_collection &acthashes = file->hashes(hashes.hash_types());
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;
}
@@ -892,104 +737,85 @@ static int verify_length_and_hash(emu_file *file, const char *name, u32 explengt
// load_software - software image loading
//-------------------------------------------------
-bool device_image_interface::load_software(software_list_device &swlist, const char *swname, const rom_entry *start)
+std::error_condition device_image_interface::load_software(software_list_device &swlist, std::string_view swname, const rom_entry *start)
{
- std::string locationtag, breakstr("%");
- const rom_entry *region;
- bool retVal = false;
+ std::error_condition retval;
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;
+ const software_info *const swinfo = swlist.find(std::string(swname));
+ if (!swinfo)
+ return image_error::NOSOFTWARE;
- u32 crc = 0;
- bool has_crc = util::hash_collection(ROM_GETHASHDATA(romp)).crc(crc);
+ if (swinfo->supported() == software_support::PARTIALLY_SUPPORTED)
+ osd_printf_error("WARNING: support for software %s (in list %s) is only partial\n", swname, swlist.list_name());
+ else if (swinfo->supported() == software_support::UNSUPPORTED)
+ osd_printf_error("WARNING: support for software %s (in list %s) is only preliminary\n", swname, swlist.list_name());
- const software_info *swinfo = swlist.find(swname);
- if (swinfo == nullptr)
- return false;
-
- 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().c_str());
- if (supported == SOFTWARE_SUPPORTED_NO)
- osd_printf_error("WARNING: support for software %s (in list %s) is only preliminary\n", swname, swlist.list_name().c_str());
-
- // 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(romp->hashdata()).crc(crc);
+ std::vector<const software_info *> parents;
+ std::vector<std::string> searchpath = rom_load_manager::get_software_searchpath(swlist, *swinfo);
- while (swinfo != nullptr)
+ // for historical reasons, add the search path for the software list device's owner
+ const device_t *const listowner = swlist.owner();
+ if (listowner)
{
- locationtag.append(swinfo->shortname()).append(breakstr);
- swinfo = !swinfo->parentname().empty() ? swlist.find(swinfo->parentname().c_str()) : nullptr;
+ std::vector<std::string> devsearch = listowner->searchpath();
+ for (std::string &path : devsearch)
+ searchpath.emplace_back(std::move(path));
}
- // 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)
+ // 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);
+ std::error_condition filerr;
+ if (has_crc)
+ filerr = m_mame_file->open(romp->name(), crc);
+ else
+ filerr = m_mame_file->open(romp->name());
+ if (filerr)
{
- // 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);
+ m_mame_file.reset();
+ std::ostringstream msg;
+ util::stream_format(msg,
+ "%s: error opening image file %s: %s (%s:%d)",
+ device().tag(), romp->name(),
+ filerr.message(),
+ filerr.category().name(),
+ filerr.value());
+ if (!searchpath.empty())
+ {
+ msg << " (tried in";
+ for (auto const &path : searchpath)
+ msg << ' ' << path;
+ msg << ')';
+ }
+ osd_printf_error("%s\n", std::move(msg).str());
}
- // 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));
-
- if (tag5.find_first_of('%') != -1)
- fatalerror("We do not support clones of clones!\n");
-
- // try to load from the available location(s):
- // - if we are not using lists, we have regiontag only;
- // - if we are using lists, we have: list/clonename, list/parentname, clonename, parentname
- // 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);
-
- 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)
+ warningcount += verify_length_and_hash(m_mame_file.get(), romp->name(), romp->get_length(), util::hash_collection(romp->hashdata()));
+
+ if (!filerr)
filerr = util::core_file::open_proxy(*m_mame_file, m_file);
- if (filerr == osd_file::error::NONE)
- retVal = true;
+ if (filerr)
+ retval = filerr;
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;
}
@@ -997,16 +823,16 @@ bool device_image_interface::load_software(software_list_device &swlist, const c
// load_internal - core image loading
//-------------------------------------------------
-image_init_result device_image_interface::load_internal(const std::string &path, bool is_create, int create_format, util::option_resolution *create_args)
+std::pair<std::error_condition, std::string> device_image_interface::load_internal(std::string_view path, bool is_create, int create_format, util::option_resolution *create_args)
{
+ std::pair<std::error_condition, std::string> err;
+
// first unload the image
unload();
- // clear any possible error messages
- clear_error();
-
// we are now loading
m_is_loading = true;
+ m_sequence_counter++;
// record the filename
set_image_filename(path);
@@ -1014,48 +840,47 @@ image_init_result device_image_interface::load_internal(const std::string &path,
if (core_opens_image_file())
{
// determine open plan
- std::vector<u32> open_plan = determine_open_plan(is_create);
+ std::vector<u32> const open_plan = determine_open_plan(is_create);
// attempt to open the file in various ways
for (auto iter = open_plan.cbegin(); !m_file && iter != open_plan.cend(); iter++)
{
// open the file
- m_err = load_image_by_path(*iter, path);
- if (m_err && (m_err != IMAGE_ERROR_FILENOTFOUND))
- goto done;
+ err.first = load_image_by_path(*iter, path);
+ if (err.first && (err.first != std::errc::no_such_file_or_directory) && (err.first != std::errc::permission_denied))
+ break;
}
// did we fail to find the file?
- if (!is_loaded())
- {
- m_err = IMAGE_ERROR_FILENOTFOUND;
- goto done;
- }
+ if (!err.first && !m_file)
+ err.first = std::errc::no_such_file_or_directory;
}
- // call device load or create
- m_create_format = create_format;
- m_create_args = create_args;
+ if (!err.first)
+ {
+ // call device load or create
+ m_create_format = create_format;
+ m_create_args = create_args;
- if (init_phase()==false) {
- m_err = (finish_load() == image_init_result::PASS) ? IMAGE_ERROR_SUCCESS : IMAGE_ERROR_INTERNAL;
- if (m_err)
- goto done;
+ if (!init_phase())
+ err = finish_load();
}
- // success!
-done:
- if (m_err!=0) {
- if (!init_phase())
- {
- if (device().machine().phase() == machine_phase::RUNNING)
- device().popmessage("Error: Unable to %s image '%s': %s", is_create ? "create" : "load", path, error());
- else
- osd_printf_error("Error: Unable to %s image '%s': %s\n", is_create ? "create" : "load", path.c_str(), error());
- }
+ if (err.first)
+ {
+ osd_printf_error(
+ !err.second.empty()
+ ? (is_create ? "Unable to create image '%1$s': %2$s (%3$s:%4$d %5$s)\n" : "Unable to load image '%1$s': %2$s (%3$s:%4$d %5$s)\n")
+ : (is_create ? "Unable to create image '%1$s': %5$s (%3$s:%4$d)\n" : "Unable to load image '%1$s': %5$s (%3$s:%4$d)\n"),
+ path,
+ err.second,
+ err.first.category().name(),
+ err.first.value(),
+ err.first.message());
clear();
}
- return m_err ? image_init_result::FAIL : image_init_result::PASS;
+
+ return err;
}
@@ -1063,13 +888,13 @@ done:
// load - load an image into MAME
//-------------------------------------------------
-image_init_result device_image_interface::load(const std::string &path)
+std::pair<std::error_condition, std::string> device_image_interface::load(std::string_view path)
{
// is this a reset on load item?
if (is_reset_on_load() && !init_phase())
{
reset_and_load(path);
- return image_init_result::PASS;
+ return std::make_pair(std::error_condition(), std::string());
}
return load_internal(path, false, 0, nullptr);
@@ -1080,26 +905,26 @@ image_init_result device_image_interface::load(const std::string &path)
// load_software - loads a softlist item by name
//-------------------------------------------------
-image_init_result device_image_interface::load_software(const std::string &software_identifier)
+std::pair<std::error_condition, std::string> device_image_interface::load_software(std::string_view software_identifier)
{
// Is this a software part that forces a reset and we're at runtime? If so, get this loaded through reset_and_load
if (is_reset_on_load() && !init_phase())
{
reset_and_load(software_identifier);
- return image_init_result::PASS;
+ return std::make_pair(std::error_condition(), std::string());
}
// Prepare to load
unload();
- clear_error();
m_is_loading = true;
// Check if there's a software list defined for this device and use that if we're not creating an image
- bool softload = load_software_part(software_identifier);
- if (!softload)
+ std::pair<std::error_condition, std::string> err;
+ err.first = load_software_part(software_identifier);
+ if (err.first)
{
m_is_loading = false;
- return image_init_result::FAIL;
+ return err;
}
// set up softlist stuff
@@ -1109,9 +934,10 @@ image_init_result device_image_interface::load_software(const std::string &softw
m_image_name = m_full_software_name;
m_basename = m_full_software_name;
m_basename_noext = m_full_software_name;
- m_filetype = use_software_list_file_extension_for_filetype() && m_mame_file != nullptr
- ? core_filename_extract_extension(m_mame_file->filename(), true)
- : "";
+ if (use_software_list_file_extension_for_filetype() && m_mame_file)
+ m_filetype = core_filename_extract_extension(m_mame_file->filename(), true);
+ else
+ m_filetype.clear();
// Copy some image information when we have been loaded through a software list
software_info &swinfo = m_software_part_ptr->info();
@@ -1120,22 +946,32 @@ image_init_result device_image_interface::load_software(const std::string &softw
if (swinfo.longname().empty() || swinfo.publisher().empty() || swinfo.year().empty())
fatalerror("Each entry in an XML list must have all of the following fields: description, publisher, year!\n");
- // store
- m_longname = swinfo.longname();
- m_manufacturer = swinfo.publisher();
- m_year = swinfo.year();
-
// set file type
- std::string filename = (m_mame_file != nullptr) && (m_mame_file->filename() != nullptr)
+ std::string filename = (m_mame_file && m_mame_file->filename())
? m_mame_file->filename()
: "";
m_filetype = core_filename_extract_extension(filename, true);
// call finish_load if necessary
- if (init_phase() == false && (finish_load() != image_init_result::PASS))
- return image_init_result::FAIL;
+ if (!init_phase())
+ {
+ err = finish_load();
+ if (err.first)
+ {
+ osd_printf_error(
+ !err.second.empty()
+ ? "Unable to load software item '%1$s': %2$s (%3$s:%4$d %5$s)\n"
+ : "Unable to load software item '%1$s': %5$s (%3$s:%4$d)\n",
+ software_identifier,
+ err.second,
+ err.first.category().name(),
+ err.first.value(),
+ err.first.message());
+ clear();
+ }
+ }
- return image_init_result::PASS;
+ return err;
}
@@ -1144,53 +980,38 @@ image_init_result device_image_interface::load_software(const std::string &softw
// from core
//-------------------------------------------------
-image_init_result device_image_interface::finish_load()
+std::pair<std::error_condition, std::string> device_image_interface::finish_load()
{
- image_init_result err = image_init_result::PASS;
+ std::pair<std::error_condition, std::string> err;
if (m_is_loading)
{
- if (!image_checkhash())
- {
- m_err = IMAGE_ERROR_INVALIDIMAGE;
- err = image_init_result::FAIL;
- }
+ err.first = image_checkhash();
- if (err == image_init_result::PASS)
+ if (!err.first)
{
if (m_created)
- {
err = call_create(m_create_format, m_create_args);
- if (err != image_init_result::PASS)
- {
- if (!m_err)
- m_err = IMAGE_ERROR_UNSPECIFIED;
- }
- }
else
- {
- // using device load
- err = call_load();
- if (err != image_init_result::PASS)
- {
- if (!m_err)
- m_err = IMAGE_ERROR_UNSPECIFIED;
- }
- }
+ err = call_load(); // using device load
}
}
+
m_is_loading = false;
m_create_format = 0;
m_create_args = nullptr;
+ if (!err.first)
+ m_media_change_notifier(media_change_event::LOADED);
+
return err;
}
//-------------------------------------------------
-// create - create a image
+// create - create an image
//-------------------------------------------------
-image_init_result device_image_interface::create(const std::string &path)
+std::pair<std::error_condition, std::string> device_image_interface::create(std::string_view path)
{
return create(path, nullptr, nullptr);
}
@@ -1200,13 +1021,14 @@ image_init_result device_image_interface::create(const std::string &path)
// create - create a image
//-------------------------------------------------
-image_init_result device_image_interface::create(const std::string &path, const image_device_format *create_format, util::option_resolution *create_args)
+std::pair<std::error_condition, std::string> device_image_interface::create(std::string_view path, const image_device_format *create_format, util::option_resolution *create_args)
{
int format_index = 0;
int cnt = 0;
for (auto &format : m_formatlist)
{
- if (create_format == format.get()) {
+ if (create_format == format.get())
+ {
format_index = cnt;
break;
}
@@ -1222,7 +1044,7 @@ image_init_result device_image_interface::create(const std::string &path, const
// the emulation and record this image to be loaded
//-------------------------------------------------
-void device_image_interface::reset_and_load(const std::string &path)
+void device_image_interface::reset_and_load(std::string_view path)
{
// first make sure the reset is scheduled
device().machine().schedule_hard_reset();
@@ -1240,7 +1062,7 @@ void device_image_interface::reset_and_load(const std::string &path)
// to an image
//-------------------------------------------------
-void device_image_interface::clear()
+void device_image_interface::clear() noexcept
{
m_mame_file.reset();
m_file.reset();
@@ -1251,9 +1073,6 @@ void device_image_interface::clear()
m_create_format = 0;
m_create_args = nullptr;
- m_longname.clear();
- m_manufacturer.clear();
- m_year.clear();
m_basename.clear();
m_basename_noext.clear();
m_filetype.clear();
@@ -1261,6 +1080,10 @@ void device_image_interface::clear()
m_full_software_name.clear();
m_software_part_ptr = nullptr;
m_software_list_name.clear();
+
+ m_hash.reset();
+
+ m_sequence_counter++;
}
@@ -1272,10 +1095,15 @@ void device_image_interface::unload()
{
if (is_loaded() || loaded_through_softlist())
{
+ m_sequence_counter++;
call_unload();
+ clear();
+ m_media_change_notifier(media_change_event::UNLOADED);
+ }
+ else
+ {
+ clear(); // just to make sure everything is reset
}
- clear();
- clear_error();
}
@@ -1297,33 +1125,33 @@ const util::option_guide &device_image_interface::create_option_guide() const
void device_image_interface::update_names()
{
- const char *inst_name = custom_instance_name();
- const char *brief_name = custom_brief_instance_name();
- if (inst_name == nullptr)
- inst_name = device_typename(image_type());
- if (brief_name == nullptr)
- brief_name = device_brieftypename(image_type());
+ const char *inst_name = image_type_name();
+ const char *brief_name = image_brief_type_name();
+ assert(inst_name != nullptr);
+ assert(brief_name != nullptr);
// count instances of the general image type, or device type if custom
int count = 0;
int index = -1;
- for (const device_image_interface &image : image_interface_iterator(device().mconfig().root_device()))
+ for (const device_image_interface &image : image_interface_enumerator(device().mconfig().root_device()))
{
if (this == &image)
index = count;
- const char *other_name = image.custom_instance_name();
- if (!other_name)
- other_name = device_typename(image.image_type());
+ const char *other_name = image.image_type_name();
+ const char *other_brief_name = image.image_brief_type_name();
+ assert(other_name != nullptr);
+ assert(other_brief_name != nullptr);
- if (other_name == inst_name || !strcmp(other_name, inst_name))
+ if (other_name == inst_name || !strcmp(other_name, inst_name) ||
+ other_brief_name == brief_name || !strcmp(other_brief_name, brief_name))
count++;
}
- m_canonical_instance_name = string_format("%s%d", inst_name, index + 1);
+ m_canonical_instance_name = util::string_format("%s%d", inst_name, index + 1);
if (count > 1)
{
m_instance_name = m_canonical_instance_name;
- m_brief_instance_name = string_format("%s%d", brief_name, index + 1);
+ m_brief_instance_name = util::string_format("%s%d", brief_name, index + 1);
}
else
{
@@ -1336,7 +1164,7 @@ void device_image_interface::update_names()
// find_software_item
//-------------------------------------------------
-const software_part *device_image_interface::find_software_item(const std::string &identifier, bool restrict_to_interface, software_list_device **dev) const
+const software_part *device_image_interface::find_software_item(std::string_view identifier, bool restrict_to_interface, software_list_device **dev) const
{
// split full software name into software list name and short software name
std::string list_name, software_name, part_name;
@@ -1349,7 +1177,7 @@ const software_part *device_image_interface::find_software_item(const std::strin
: nullptr;
// find the software list if explicitly specified
- for (software_list_device &swlistdev : software_list_device_iterator(device().mconfig().root_device()))
+ for (software_list_device &swlistdev : software_list_device_enumerator(device().mconfig().root_device()))
{
if (list_name.empty() || (list_name == swlistdev.list_name()))
{
@@ -1416,7 +1244,7 @@ const software_list_loader &device_image_interface::get_software_list_loader() c
// sw_info and sw_part are also set.
//-------------------------------------------------
-bool device_image_interface::load_software_part(const std::string &identifier)
+std::error_condition device_image_interface::load_software_part(std::string_view identifier)
{
// if no match has been found, we suggest similar shortnames
software_list_device *swlist;
@@ -1424,14 +1252,14 @@ bool device_image_interface::load_software_part(const std::string &identifier)
if (m_software_part_ptr == nullptr)
{
software_list_device::display_matches(device().machine().config(), image_interface(), identifier);
- return false;
+ return image_error::NOSOFTWARE;
}
// Load the software part
- const char *swname = m_software_part_ptr->info().shortname().c_str();
+ const std::string &swname = m_software_part_ptr->info().shortname();
const rom_entry *start_entry = m_software_part_ptr->romdata().data();
const software_list_loader &loader = get_software_list_loader();
- bool result = loader.load_software(*this, *swlist, swname, start_entry);
+ std::error_condition result = loader.load_software(*this, *swlist, swname, start_entry);
// check compatibility
switch (swlist->is_compatible(*m_software_part_ptr))
@@ -1441,10 +1269,12 @@ bool device_image_interface::load_software_part(const std::string &identifier)
case SOFTWARE_IS_INCOMPATIBLE:
swlist->popmessage("WARNING! the set %s might not work on this system due to incompatible filter(s) '%s'\n", m_software_part_ptr->info().shortname(), swlist->filter());
+ osd_printf_warning("WARNING: the set %s might not work on this system due to incompatible filter(s) '%s'\n", m_software_part_ptr->info().shortname(), swlist->filter());
break;
case SOFTWARE_NOT_COMPATIBLE:
swlist->popmessage("WARNING! the set %s might not work on this system due to missing filter(s) '%s'\n", m_software_part_ptr->info().shortname(), swlist->filter());
+ osd_printf_warning("WARNING! the set %s might not work on this system due to missing filter(s) '%s'\n", m_software_part_ptr->info().shortname(), swlist->filter());
break;
}
@@ -1469,7 +1299,7 @@ bool device_image_interface::load_software_part(const std::string &identifier)
// software_get_default_slot
//-------------------------------------------------
-std::string device_image_interface::software_get_default_slot(const char *default_card_slot) const
+std::string device_image_interface::software_get_default_slot(std::string_view default_card_slot) const
{
std::string result;
@@ -1501,41 +1331,3 @@ bool device_image_interface::init_phase() const
return !device().has_running_machine()
|| device().machine().phase() == machine_phase::INIT;
}
-
-
-//----------------------------------------------------------------------------
-
-static int image_fseek_thunk(void *file, s64 offset, int whence)
-{
- device_image_interface *image = (device_image_interface *) file;
- return image->fseek(offset, whence);
-}
-
-static size_t image_fread_thunk(void *file, void *buffer, size_t length)
-{
- device_image_interface *image = (device_image_interface *) file;
- return image->fread(buffer, length);
-}
-
-static size_t image_fwrite_thunk(void *file, const void *buffer, size_t length)
-{
- device_image_interface *image = (device_image_interface *) file;
- return image->fwrite(buffer, length);
-}
-
-static u64 image_fsize_thunk(void *file)
-{
- device_image_interface *image = (device_image_interface *) file;
- return image->length();
-}
-
-//----------------------------------------------------------------------------
-
-struct io_procs image_ioprocs =
-{
- nullptr,
- image_fseek_thunk,
- image_fread_thunk,
- image_fwrite_thunk,
- image_fsize_thunk
-};