diff options
Diffstat (limited to 'trunk/src/emu/image.c')
-rw-r--r-- | trunk/src/emu/image.c | 470 |
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); +} |