diff --git a/src/emu/devimage.c b/src/emu/devimage.c index bbafeab224f..44783df9604 100644 --- a/src/emu/devimage.c +++ b/src/emu/devimage.c @@ -199,7 +199,7 @@ legacy_image_device_config_base::~legacy_image_device_config_base() legacy_image_device_base::legacy_image_device_base(running_machine &machine, const device_config &config) : legacy_device_base(machine, config), device_image_interface(machine, config, *this), - m_file(NULL) + m_is_loading(FALSE) { } @@ -220,6 +220,15 @@ image_error_t legacy_image_device_base::set_image_filename(const char *filename) return IMAGE_ERROR_SUCCESS; } +/*------------------------------------------------- + is_loaded - quick check to determine whether an + image is loaded +-------------------------------------------------*/ + +bool legacy_image_device_base::is_loaded() +{ + return (m_file != NULL); // (image->software_info_ptr != NULL); +} /*------------------------------------------------- load_image_by_path - loads an image with a @@ -312,9 +321,11 @@ bool legacy_image_device_base::load_internal(const char *path, bool is_create, i unload(); /* clear any possible error messages */ + clear_error(); /* we are now loading */ - + m_is_loading = TRUE; + /* record the filename */ err = set_image_filename(path); if (err) @@ -332,16 +343,50 @@ bool legacy_image_device_base::load_internal(const char *path, bool is_create, i if (err && (err != IMAGE_ERROR_FILENOTFOUND)) goto done; } + + /* did we fail to find the file? */ + if (!is_loaded()) + { + err = IMAGE_ERROR_FILENOTFOUND; + goto done; + } + + /* call device load or create */ + m_create_format = create_format; + m_create_args = create_args; + + if (m_init_phase==FALSE) { + err = (image_error_t)finish_load(); + if (err) + goto done; + } /* success! */ done: - if (err) { + if (m_err) { + if (!m_init_phase) + { + if (mame_get_phase(machine) == MAME_PHASE_RUNNING) + popmessage("Error: Unable to %s image '%s': %s\n", is_create ? "create" : "load", path, error()); + else + mame_printf_error("Error: Unable to %s image '%s': %s", is_create ? "create" : "load", path, error()); + } clear(); } else { /* do we need to reset the CPU? only schedule it if load/create is successful */ if ((attotime_compare(timer_get_time(device().machine), attotime_zero) > 0) && m_image_config.is_reset_on_load()) mame_schedule_hard_reset(device().machine); + else + { + if (!m_init_phase) + { + if (mame_get_phase(machine) == MAME_PHASE_RUNNING) + popmessage("Image '%s' was successfully %s.", path, is_create ? "created" : "loaded"); + else + mame_printf_info("Image '%s' was successfully %s.\n", path, is_create ? "created" : "loaded"); + } + } } return err ? FALSE : TRUE; } @@ -357,6 +402,57 @@ bool legacy_image_device_base::load(const char *path) return load_internal(path, FALSE, 0, NULL); } + +/*------------------------------------------------- + image_finish_load - special call - only use + from core +-------------------------------------------------*/ + +bool legacy_image_device_base::finish_load() +{ + bool err = FALSE; + + if (m_is_loading) + { + if (has_been_created() && ((*m_image_config.create_func()) != NULL)) + { + err = (*m_image_config.create_func())(this, m_create_format, m_create_args); + if (err) + { + if (!m_err) + m_err = IMAGE_ERROR_UNSPECIFIED; + } + } + else if ((*m_image_config.load_func()) != NULL) + { + /* using device load */ + err = (*m_image_config.load_func())(this); + if (err) + { + if (!m_err) + m_err = IMAGE_ERROR_UNSPECIFIED; + } + } + } + + m_is_loading = FALSE; + m_create_format = 0; + m_create_args = NULL; + m_init_phase = FALSE; + return err; +} + +/*------------------------------------------------- + create - create a image +-------------------------------------------------*/ + +bool legacy_image_device_base::create(const char *path, const image_device_format *create_format, option_resolution *create_args) +{ + int format_index = (create_format != NULL) ? create_format->m_index : 0; + return load_internal(path, TRUE, format_index, create_args); +} + + /*------------------------------------------------- clear - clear all internal data pertaining to an image @@ -375,26 +471,13 @@ void legacy_image_device_base::clear() m_created = FALSE; } - -/*------------------------------------------------- - unload_internal - internal call to unload - images --------------------------------------------------*/ - -void legacy_image_device_base::unload_internal() -{ - clear(); -} - - - /*------------------------------------------------- unload - main call to unload an image -------------------------------------------------*/ void legacy_image_device_base::unload() { - unload_internal(); + clear(); } diff --git a/src/emu/devlegcy.h b/src/emu/devlegcy.h index 73329a2bf45..c806796d4a1 100644 --- a/src/emu/devlegcy.h +++ b/src/emu/devlegcy.h @@ -592,7 +592,11 @@ public: virtual const char *instance_name() const { return m_instance_name; } virtual const char *brief_instance_name() const { return m_brief_instance_name; } virtual bool uses_file_extension(const char *file_extension) const; - + virtual const option_guide *create_option_guide() const { return m_create_option_guide; } + virtual image_device_format *formatlist() const { return m_formatlist; } + virtual device_image_load_func load_func() const { return load; } + virtual device_image_create_func create_func() const { return create; } + virtual device_image_unload_func unload_func() const { return unload; } protected: // construction/destruction legacy_image_device_config_base(const machine_config &mconfig, device_type type, const char *tag, const device_config *owner, UINT32 clock, device_get_config_func get_config); @@ -637,7 +641,9 @@ public: virtual void set_working_directory(const char *working_directory) { m_working_directory = working_directory; } virtual const char * working_directory(); virtual bool load(const char *path); + virtual bool finish_load(); virtual void unload(); + virtual bool create(const char *path, const image_device_format *create_format, option_resolution *create_args); protected: // construction/destruction legacy_image_device_base(running_machine &machine, const device_config &config); @@ -645,16 +651,7 @@ protected: /* working directory; persists across mounts */ astring m_working_directory; - - /* variables that are only non-zero when an image is mounted */ - core_file *m_file; - astring m_name; - - /* error related info */ - image_error_t err; - astring err_message; - - + void setup_working_directory(); bool try_change_working_directory(const char *subdir); @@ -662,12 +659,10 @@ protected: void determine_open_plan(int is_create, UINT32 *open_plan); image_error_t set_image_filename(const char *filename); image_error_t load_image_by_path(UINT32 open_flags, const char *path); - void clear(); - void unload_internal(); + void clear(); + bool is_loaded(); - /* flags */ - bool m_writeable; - bool m_created; + bool m_is_loading; }; diff --git a/src/emu/diimage.c b/src/emu/diimage.c index de807427fbe..c36ee02be02 100644 --- a/src/emu/diimage.c +++ b/src/emu/diimage.c @@ -38,7 +38,7 @@ ***************************************************************************/ #include "emu.h" - +#include "ui.h" //************************************************************************** @@ -129,7 +129,8 @@ const char *device_config_image_interface::device_brieftypename(iodevice_t type) device_image_interface::device_image_interface(running_machine &machine, const device_config &config, device_t &device) : device_interface(machine, config, device), - m_image_config(dynamic_cast(config)) + m_image_config(dynamic_cast(config)), + m_file(NULL) { } @@ -141,3 +142,192 @@ device_image_interface::device_image_interface(running_machine &machine, const d device_image_interface::~device_image_interface() { } + +/**************************************************************************** + CREATION FORMATS +****************************************************************************/ + +/*------------------------------------------------- + device_get_indexed_creatable_format - + accesses a specific image format available for + image creation by index +-------------------------------------------------*/ + +const image_device_format *device_image_interface::device_get_indexed_creatable_format(int index) +{ + const image_device_format *format = device_get_creatable_formats(); + while(index-- && (format != NULL)) + format = format->m_next; + return format; +} + + + +/*------------------------------------------------- + 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 char *format_name) +{ + const image_device_format *format = device_get_creatable_formats(); + while((format != NULL) && strcmp(format->m_name, format_name)) + format = format->m_next; + return format; +} + +/**************************************************************************** + ERROR HANDLING +****************************************************************************/ + +/*------------------------------------------------- + image_clear_error - clear out any specified + error +-------------------------------------------------*/ + +void device_image_interface::clear_error() +{ + m_err = IMAGE_ERROR_SUCCESS; + if (m_err_message.len()==0) + { + //image_freeptr(image->dev, image->err_message); + m_err_message.reset(); + } +} + + + +/*------------------------------------------------- + error - returns the error text for an image + error +-------------------------------------------------*/ + +const char *device_image_interface::error() +{ + static const char *const messages[] = + { + NULL, + "Internal error", + "Unsupported operation", + "Out of memory", + "File not found", + "Invalid image", + "File already open", + "Unspecified error" + }; + + return m_err_message.len()==0 ? m_err_message : astring(messages[m_err]); +} + + + +/*------------------------------------------------- + seterror - specifies an error on an image +-------------------------------------------------*/ + +void device_image_interface::seterror(image_error_t err, const char *message) +{ + clear_error(); + m_err = err; + if (message != NULL) + { + m_err_message = message; + } +} + + + +/*------------------------------------------------- + message - used to display a message while + loading +-------------------------------------------------*/ + +void device_image_interface::message(const char *format, ...) +{ + 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 */ + ui_popup_time(5, "%s: %s", + basename(), + buffer); +} + + +/**************************************************************************** + Accessor functions + + These provide information about the device; and about the mounted image +****************************************************************************/ + +/*------------------------------------------------- + filename +-------------------------------------------------*/ + +const char *device_image_interface::filename() +{ + const char *name = m_name; + return (name[0] != '\0') ? name : NULL; +} + +/*------------------------------------------------- + basename +-------------------------------------------------*/ + +const char *device_image_interface::basename() +{ + char *fname = (char*)filename(); + const char *c; + + // NULL begets NULL + if (!fname) + return NULL; + + // start at the end and return when we hit a slash or colon + for (c = fname + strlen(fname) - 1; c >= fname; c--) + if (*c == '\\' || *c == '/' || *c == ':') + return c + 1; + + // otherwise, return the whole thing + return fname; +} + + +/*------------------------------------------------- + basename_noext +-------------------------------------------------*/ + +const char *device_image_interface::basename_noext() +{ + const char *s; + char *ext; + + s = basename(); + if (s) + { + ext = strrchr(s, '.'); + if (ext) + *ext = '\0'; + } + return s; +} + + + +/*------------------------------------------------- + filetype +-------------------------------------------------*/ + +const char *device_image_interface::filetype() +{ + const char *s = filename(); + if (s != NULL) + s = strrchr(s, '.'); + return s ? s+1 : NULL; +} diff --git a/src/emu/diimage.h b/src/emu/diimage.h index 586a99796cf..2b9cf0127e1 100644 --- a/src/emu/diimage.h +++ b/src/emu/diimage.h @@ -102,13 +102,15 @@ struct image_device_format astring m_optspec; }; +class device_image_interface; + // device image interface function types -typedef int (*device_image_load_func)(device_t *image); -typedef int (*device_image_create_func)(device_t *image, int format_type, option_resolution *format_options); -typedef void (*device_image_unload_func)(device_t *image); -typedef void (*device_image_display_func)(device_t *image); +typedef int (*device_image_load_func)(device_image_interface *image); +typedef int (*device_image_create_func)(device_image_interface *image, int format_type, option_resolution *format_options); +typedef void (*device_image_unload_func)(device_image_interface *image); +typedef void (*device_image_display_func)(device_image_interface *image); typedef void (*device_image_partialhash_func)(char *, const unsigned char *, unsigned long, unsigned int); -typedef void (*device_image_get_devices_func)(device_t *device); +typedef void (*device_image_get_devices_func)(device_image_interface *device); //************************************************************************** @@ -116,19 +118,19 @@ typedef void (*device_image_get_devices_func)(device_t *device); //************************************************************************** #define DEVICE_IMAGE_LOAD_NAME(name) device_load_##name -#define DEVICE_IMAGE_LOAD(name) int DEVICE_IMAGE_LOAD_NAME(name)(device_t *image) +#define DEVICE_IMAGE_LOAD(name) int DEVICE_IMAGE_LOAD_NAME(name)(device_image_interface *image) #define DEVICE_IMAGE_CREATE_NAME(name) device_create_##name -#define DEVICE_IMAGE_CREATE(name) int DEVICE_IMAGE_CREATE_NAME(name)(device_t *image, int create_format, option_resolution *create_args) +#define DEVICE_IMAGE_CREATE(name) int DEVICE_IMAGE_CREATE_NAME(name)(device_image_interface *image, int create_format, option_resolution *create_args) #define DEVICE_IMAGE_UNLOAD_NAME(name) device_unload_##name -#define DEVICE_IMAGE_UNLOAD(name) void DEVICE_IMAGE_UNLOAD_NAME(name)(device_t *image) +#define DEVICE_IMAGE_UNLOAD(name) void DEVICE_IMAGE_UNLOAD_NAME(name)(device_image_interface *image) #define DEVICE_IMAGE_DISPLAY_NAME(name) device_image_display_func##name -#define DEVICE_IMAGE_DISPLAY(name) void DEVICE_IMAGE_DISPLAY_NAME(name)(device_t *image) +#define DEVICE_IMAGE_DISPLAY(name) void DEVICE_IMAGE_DISPLAY_NAME(name)(device_image_interface *image) #define DEVICE_IMAGE_GET_DEVICES_NAME(name) device_image_get_devices_##name -#define DEVICE_IMAGE_GET_DEVICES(name) void DEVICE_IMAGE_GET_DEVICES_NAME(name)(device_t *device) +#define DEVICE_IMAGE_GET_DEVICES(name) void DEVICE_IMAGE_GET_DEVICES_NAME(name)(device_image_interface *device) // ======================> device_config_image_interface @@ -158,9 +160,16 @@ public: virtual const char *instance_name() const = 0; virtual const char *brief_instance_name() const = 0; virtual bool uses_file_extension(const char *file_extension) const = 0; + virtual const option_guide *create_option_guide() const = 0; + virtual image_device_format *formatlist() const = 0; static const char *device_typename(iodevice_t type); static const char *device_brieftypename(iodevice_t type); + + virtual device_image_load_func load_func() const = 0; + virtual device_image_create_func create_func() const = 0; + virtual device_image_unload_func unload_func() const = 0; + protected: static const image_device_type_info *find_device_type(iodevice_t type); static const image_device_type_info m_device_info_array[]; @@ -182,15 +191,66 @@ public: virtual void set_working_directory(const char *working_directory) = 0; virtual const char * working_directory() = 0; virtual bool load(const char *path) = 0; + virtual bool finish_load() = 0; virtual void unload() = 0; + virtual const image_device_format *device_get_indexed_creatable_format(int index); + virtual const image_device_format *device_get_named_creatable_format(const char *format_name); + const option_guide *image_device_get_creation_option_guide() { return m_image_config.create_option_guide(); } + const image_device_format *device_get_creatable_formats() { return m_image_config.formatlist(); } + + virtual bool create(const char *path, const image_device_format *create_format, option_resolution *create_args) = 0; + + const char *error(); + void seterror(image_error_t err, const char *message); + void message(const char *format, ...); + + bool exists() { return m_name.len() != 0; } + const char *filename(); + const char *basename(); + const char *basename_noext(); + const char *filetype(); + core_file *image_core_file() { return m_file; } + UINT64 length() { check_for_file(); return core_fsize(m_file); } + bool is_writable() { return m_writeable; } + bool has_been_created() { return m_created; } + void make_readonly() { m_writeable = 0; } + UINT32 fread(void *buffer, UINT32 length) { check_for_file(); return core_fread(m_file, buffer, length); } + UINT32 fwrite(const void *buffer, UINT32 length) { check_for_file(); return core_fwrite(m_file, buffer, length); } + int fseek(running_device *image, INT64 offset, int whence) { check_for_file(); return core_fseek(m_file, offset, whence); } + UINT64 ftell() { check_for_file(); return core_ftell(m_file); } + int fgetc() { char ch; if (fread(&ch, 1) != 1) ch = '\0'; return ch; } + char *fgets(char *buffer, UINT32 length) { check_for_file(); return core_fgets(buffer, length, m_file); } + int feof() { check_for_file(); return core_feof(m_file); } + void *ptr() {check_for_file(); return (void *) core_fbuffer(m_file); } // configuration access const device_config_image_interface &image_config() const { return m_image_config; } + + void set_init_phase() { m_init_phase = TRUE; } protected: + void clear_error(); + + void check_for_file() { assert_always(m_file != NULL, "Illegal operation on unmounted image"); } // derived class overrides // configuration const device_config_image_interface &m_image_config; // reference to our device_config_execute_interface + + /* error related info */ + image_error_t m_err; + astring m_err_message; + + /* variables that are only non-zero when an image is mounted */ + core_file *m_file; + astring m_name; + /* flags */ + bool m_writeable; + bool m_created; + bool m_init_phase; + + /* special - used when creating */ + int m_create_format; + option_resolution *m_create_args; }; diff --git a/src/emu/image.c b/src/emu/image.c index 3405a47a7cb..4ece1fb3e88 100644 --- a/src/emu/image.c +++ b/src/emu/image.c @@ -19,26 +19,6 @@ /*************************************************************************** INITIALIZATION HELPERS ***************************************************************************/ -//============================================================ -// filename_basename -//============================================================ - -static const char *filename_basename(const char *filename) -{ - const char *c; - - // NULL begets NULL - if (!filename) - return NULL; - - // start at the end and return when we hit a slash or colon - for (c = filename + strlen(filename) - 1; c >= filename; c--) - if (*c == '\\' || *c == '/' || *c == ':') - return c + 1; - - // otherwise, return the whole thing - return filename; -} /*------------------------------------------------- image_dirs_load - loads image device directory @@ -103,7 +83,24 @@ static void image_dirs_save(running_machine *machine, int config_type, xml_data_ } } +/*------------------------------------------------- + image_unload_all - unload all images and + extract options +-------------------------------------------------*/ +void image_unload_all(running_machine *machine) +{ + device_image_interface *image = NULL; + + // extract the options + //mess_options_extract(machine); + + for (bool gotone = machine->devicelist.first(image); gotone; gotone = image->next(image)) + { + // unload this image + image->unload(); + } +} /*------------------------------------------------- image_device_init - initialize devices for a specific running_machine @@ -124,6 +121,9 @@ void image_device_init(running_machine *machine) { bool result = FALSE; + /* mark init state */ + image->set_init_phase(); + /* try to load this image */ result = image->load(image_name); @@ -131,15 +131,15 @@ void image_device_init(running_machine *machine) if (!result) { /* retrieve image error message */ - const char *image_err = "error";// image_error(image); - char *image_basename = auto_strdup(machine, filename_basename(image_name)); + const char *image_err = image->error(); + const char *image_basename_str = image->basename(); /* unload all images */ - //image_unload_all(machine); + image_unload_all(machine); fatalerror_exitcode(machine, MAMERR_DEVICE, "Device %s load (%s) failed: %s", image->image_config().name(), - image_basename, + image_basename_str, image_err); } } @@ -153,6 +153,40 @@ void image_device_init(running_machine *machine) } } } + +/*------------------------------------------------- + image_postdevice_init - initialize devices for a specific + running_machine +-------------------------------------------------*/ + +void image_postdevice_init(running_machine *machine) +{ + device_image_interface *image = NULL; + + /* make sure that any required devices have been allocated */ + for (bool gotone = machine->devicelist.first(image); gotone; gotone = image->next(image)) + { + int result = image->finish_load(); + /* did the image load fail? */ + if (result) + { + /* retrieve image error message */ + const char *image_err = image->error(); + const char *image_basename_str = image->basename(); + + /* unload all images */ + image_unload_all(machine); + + fatalerror_exitcode(machine, MAMERR_DEVICE, "Device %s load (%s) failed: %s", + image->image_config().name(), + image_basename_str, + image_err); + } + } + + /* add a callback for when we shut down */ + add_exit_callback(machine, image_unload_all); +} /*************************************************************************** INITIALIZATION ***************************************************************************/ diff --git a/src/emu/image.h b/src/emu/image.h index 76072838a21..591a1884ee1 100644 --- a/src/emu/image.h +++ b/src/emu/image.h @@ -19,5 +19,6 @@ #define __IMAGE_H__ void image_init(running_machine *machine); +void image_postdevice_init(running_machine *machine); #endif /* __IMAGE_H__ */ diff --git a/src/emu/mame.c b/src/emu/mame.c index 98c8318e87b..376a4a9aa18 100644 --- a/src/emu/mame.c +++ b/src/emu/mame.c @@ -1422,6 +1422,9 @@ static void init_machine(running_machine *machine) /* start up the devices */ machine->devicelist.start_all(); + + /* finish image devices init process*/ + image_postdevice_init(machine); /* call the game driver's init function */ /* this is where decryption is done and memory maps are altered */