summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/image.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/image.c')
-rw-r--r--trunk/src/emu/image.c470
1 files changed, 470 insertions, 0 deletions
diff --git a/trunk/src/emu/image.c b/trunk/src/emu/image.c
new file mode 100644
index 00000000000..501b5cfafe6
--- /dev/null
+++ b/trunk/src/emu/image.c
@@ -0,0 +1,470 @@
+/***************************************************************************
+
+ image.c
+
+ Core image functions and definitions.
+
+ Copyright Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+#include <ctype.h>
+
+#include "emu.h"
+#include "emuopts.h"
+#include "image.h"
+#include "config.h"
+#include "xmlfile.h"
+#include "formats/ioprocs.h"
+
+/* ----------------------------------------------------------------------- */
+
+static int image_fseek_thunk(void *file, INT64 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 UINT64 image_fsize_thunk(void *file)
+{
+ device_image_interface *image = (device_image_interface *) file;
+ return image->length();
+}
+
+/* ----------------------------------------------------------------------- */
+
+struct io_procs image_ioprocs =
+{
+ NULL,
+ image_fseek_thunk,
+ image_fread_thunk,
+ image_fwrite_thunk,
+ image_fsize_thunk
+};
+
+/***************************************************************************
+ INITIALIZATION HELPERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ image_dirs_load - loads image device directory
+ configuration items
+-------------------------------------------------*/
+
+static void image_dirs_load(running_machine &machine, int config_type, xml_data_node *parentnode)
+{
+ xml_data_node *node;
+ const char *dev_instance;
+ const char *working_directory;
+
+ if ((config_type == CONFIG_TYPE_GAME) && (parentnode != NULL))
+ {
+ for (node = xml_get_sibling(parentnode->child, "device"); node; node = xml_get_sibling(node->next, "device"))
+ {
+ dev_instance = xml_get_attribute_string(node, "instance", NULL);
+
+ if ((dev_instance != NULL) && (dev_instance[0] != '\0'))
+ {
+ image_interface_iterator iter(machine.root_device());
+ for (device_image_interface *image = iter.first(); image != NULL; image = iter.next())
+ {
+ if (!strcmp(dev_instance, image->instance_name())) {
+ working_directory = xml_get_attribute_string(node, "directory", NULL);
+ if (working_directory != NULL)
+ image->set_working_directory(working_directory);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+
+/*-------------------------------------------------
+ image_dirs_save - saves out image device
+ directories to the configuration file
+-------------------------------------------------*/
+
+static void image_dirs_save(running_machine &machine, int config_type, xml_data_node *parentnode)
+{
+ xml_data_node *node;
+ const char *dev_instance;
+
+ /* only care about game-specific data */
+ if (config_type == CONFIG_TYPE_GAME)
+ {
+ image_interface_iterator iter(machine.root_device());
+ for (device_image_interface *image = iter.first(); image != NULL; image = iter.next())
+ {
+ dev_instance = image->instance_name();
+
+ node = xml_add_child(parentnode, "device", NULL);
+ if (node != NULL)
+ {
+ xml_set_attribute(node, "instance", dev_instance);
+ xml_set_attribute(node, "directory", image->working_directory());
+ }
+ }
+ }
+}
+
+/*-------------------------------------------------
+ write_config - emit current option statuses as
+ INI files
+-------------------------------------------------*/
+
+static int write_config(emu_options &options, const char *filename, const game_driver *gamedrv)
+{
+ char buffer[128];
+ int retval = 1;
+
+ if (gamedrv != NULL)
+ {
+ sprintf(buffer, "%s.ini", gamedrv->name);
+ filename = buffer;
+ }
+
+ emu_file file(options.ini_path(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE);
+ file_error filerr = file.open(filename);
+ if (filerr == FILERR_NONE)
+ {
+ astring inistring;
+ options.output_ini(inistring);
+ file.puts(inistring);
+ retval = 0;
+ }
+ return retval;
+}
+
+/*-------------------------------------------------
+ image_options_extract - extract device options
+ out of core into the options
+-------------------------------------------------*/
+
+static void image_options_extract(running_machine &machine)
+{
+ /* only extract the device options if we've added them
+ no need to assert in case they are missing */
+ {
+ int index = 0;
+
+ image_interface_iterator iter(machine.root_device());
+ for (device_image_interface *image = iter.first(); image != NULL; image = iter.next())
+ {
+ const char *filename = image->filename();
+
+ /* and set the option */
+ astring error;
+ machine.options().set_value(image->instance_name(), filename ? filename : "", OPTION_PRIORITY_CMDLINE, error);
+
+ index++;
+ }
+ }
+
+ /* write the config, if appropriate */
+ if (machine.options().write_config())
+ write_config(machine.options(), NULL, &machine.system());
+}
+
+/*-------------------------------------------------
+ image_unload_all - unload all images and
+ extract options
+-------------------------------------------------*/
+
+void image_unload_all(running_machine &machine)
+{
+ // extract the options
+ image_options_extract(machine);
+
+ image_interface_iterator iter(machine.root_device());
+ for (device_image_interface *image = iter.first(); image != NULL; image = iter.next())
+ {
+ // unload this image
+ image->unload();
+ }
+}
+/*-------------------------------------------------
+ image_device_init - initialize devices for a specific
+ running_machine
+-------------------------------------------------*/
+
+void image_device_init(running_machine &machine)
+{
+ const char *image_name;
+
+ /* make sure that any required devices have been allocated */
+ image_interface_iterator iter(machine.root_device());
+ for (device_image_interface *image = iter.first(); image != NULL; image = iter.next())
+ {
+ /* is an image specified for this image */
+ image_name = machine.options().device_option(*image);
+
+ if ((image_name != NULL) && (image_name[0] != '\0'))
+ {
+ /* mark init state */
+ image->set_init_phase();
+
+ /* try to load this image */
+ bool result = image->load(image_name);
+
+ /* did the image load fail? */
+ if (result)
+ {
+ /* retrieve image error message */
+ astring image_err = astring(image->error());
+ astring image_basename(image_name);
+
+ /* unload all images */
+ image_unload_all(machine);
+
+ fatalerror_exitcode(machine, MAMERR_DEVICE, "Device %s load (%s) failed: %s",
+ image->device().name(),
+ image_basename.cstr(),
+ image_err.cstr());
+ }
+ }
+ }
+
+ for (device_image_interface *image = iter.first(); image != NULL; image = iter.next())
+ {
+ /* is an image specified for this image */
+ image_name = image->filename();
+
+ if (!((image_name != NULL) && (image_name[0] != '\0')))
+ {
+ /* no image... must this device be loaded? */
+ if (image->must_be_loaded())
+ {
+ fatalerror_exitcode(machine, MAMERR_DEVICE, "Driver requires that device \"%s\" must have an image to load", image->instance_name());
+ }
+ }
+ }
+}
+
+/*-------------------------------------------------
+ image_postdevice_init - initialize devices for a specific
+ running_machine
+-------------------------------------------------*/
+
+void image_postdevice_init(running_machine &machine)
+{
+ /* make sure that any required devices have been allocated */
+ image_interface_iterator iter(machine.root_device());
+ for (device_image_interface *image = iter.first(); image != NULL; image = iter.next())
+ {
+ int result = image->finish_load();
+ /* did the image load fail? */
+ if (result)
+ {
+ /* retrieve image error message */
+ astring image_err = astring(image->error());
+
+ /* unload all images */
+ image_unload_all(machine);
+
+ fatalerror_exitcode(machine, MAMERR_DEVICE, "Device %s load failed: %s",
+ image->device().name(),
+ image_err.cstr());
+ }
+ }
+
+ /* add a callback for when we shut down */
+ machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(image_unload_all), &machine));
+}
+/***************************************************************************
+ INITIALIZATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ image_init - start up the image system
+-------------------------------------------------*/
+
+void image_init(running_machine &machine)
+{
+ image_device_init(machine);
+ config_register(machine, "image_directories", config_saveload_delegate(FUNC(image_dirs_load), &machine), config_saveload_delegate(FUNC(image_dirs_save), &machine));
+}
+
+
+/****************************************************************************
+ Battery functions
+
+ These functions provide transparent access to battery-backed RAM on an
+ image; typically for cartridges.
+****************************************************************************/
+
+static char *stripspace(const char *src)
+{
+ static char buff[512];
+ if( src )
+ {
+ char *dst;
+ while( *src && isspace(*src) )
+ src++;
+ strcpy(buff, src);
+ dst = buff + strlen(buff);
+ while( dst >= buff && isspace(*--dst) )
+ *dst = '\0';
+ return buff;
+ }
+ return NULL;
+}
+
+//============================================================
+// strip_extension
+//============================================================
+
+static char *strip_extension(const char *filename)
+{
+ char *newname;
+ char *c;
+
+ // NULL begets NULL
+ if (!filename)
+ return NULL;
+
+ // allocate space for it
+ newname = (char *) malloc(strlen(filename) + 1);
+ if (!newname)
+ return NULL;
+
+ // copy in the name
+ strcpy(newname, filename);
+
+ // search backward for a period, failing if we hit a slash or a colon
+ for (c = newname + strlen(newname) - 1; c >= newname; c--)
+ {
+ // if we hit a period, NULL terminate and break
+ if (*c == '.')
+ {
+ *c = 0;
+ break;
+ }
+
+ // if we hit a slash or colon just stop
+ if (*c == '\\' || *c == '/' || *c == ':')
+ break;
+ }
+
+ return newname;
+}
+
+/*-------------------------------------------------
+ image_info_astring - populate an allocated
+ string with the image info text
+-------------------------------------------------*/
+
+astring &image_info_astring(running_machine &machine, astring &string)
+{
+ string.printf("%s\n\n", machine.system().description);
+
+#if 0
+ if (mess_ram_size > 0)
+ {
+ char buf2[RAM_STRING_BUFLEN];
+ string.catprintf("RAM: %s\n\n", ram_string(buf2, mess_ram_size));
+ }
+#endif
+
+ image_interface_iterator iter(machine.root_device());
+ for (device_image_interface *image = iter.first(); image != NULL; image = iter.next())
+ {
+ const char *name = image->filename();
+ if (name != NULL)
+ {
+ const char *base_filename;
+ const char *info;
+ char *base_filename_noextension;
+
+ base_filename = image->basename();
+ base_filename_noextension = strip_extension(base_filename);
+
+ /* display device type and filename */
+ string.catprintf("%s: %s\n", image->device().name(), base_filename);
+
+ /* display long filename, if present and doesn't correspond to name */
+ info = image->longname();
+ if (info && (!base_filename_noextension || mame_stricmp(info, base_filename_noextension)))
+ string.catprintf("%s\n", info);
+
+ /* display manufacturer, if available */
+ info = image->manufacturer();
+ if (info != NULL)
+ {
+ string.catprintf("%s", info);
+ info = stripspace(image->year());
+ if (info && *info)
+ string.catprintf(", %s", info);
+ string.catprintf("\n");
+ }
+
+ /* display supported information, if available */
+ switch(image->supported()) {
+ case SOFTWARE_SUPPORTED_NO : string.catprintf("Not supported\n"); break;
+ case SOFTWARE_SUPPORTED_PARTIAL : string.catprintf("Partialy supported\n"); break;
+ default : break;
+ }
+
+ if (base_filename_noextension != NULL)
+ free(base_filename_noextension);
+ }
+ else
+ {
+ string.catprintf("%s: ---\n", image->device().name());
+ }
+ }
+ return string;
+}
+
+
+/*-------------------------------------------------
+ image_battery_load_by_name - retrieves the battery
+ backed RAM for an image. A filename may be supplied
+ to the function.
+-------------------------------------------------*/
+
+void image_battery_load_by_name(emu_options &options, const char *filename, void *buffer, int length, int fill)
+{
+ file_error filerr;
+ int bytes_read = 0;
+
+ assert_always(buffer && (length > 0), "Must specify sensical buffer/length");
+
+ /* try to open the battery file and read it in, if possible */
+ emu_file file(options.nvram_directory(), OPEN_FLAG_READ);
+ filerr = file.open(filename);
+ if (filerr == FILERR_NONE)
+ bytes_read = file.read(buffer, length);
+
+ /* fill remaining bytes (if necessary) */
+ memset(((char *) buffer) + bytes_read, fill, length - bytes_read);
+}
+
+/*-------------------------------------------------
+ image_battery_save_by_name - stores the battery
+ backed RAM for an image. A filename may be supplied
+ to the function.
+-------------------------------------------------*/
+void image_battery_save_by_name(emu_options &options, const char *filename, const void *buffer, int length)
+{
+ assert_always(buffer && (length > 0), "Must specify sensical buffer/length");
+
+ /* try to open the battery file and write it out, if possible */
+ emu_file file(options.nvram_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
+ file_error filerr = file.open(filename);
+ if (filerr == FILERR_NONE)
+ file.write(buffer, length);
+}