1 // license:BSD-3-Clause 2 // copyright-holders:Miodrag Milanovic 3 /*************************************************************************** 4 5 diimage.h 6 7 Device image interfaces. 8 9 ***************************************************************************/ 10 11 #pragma once 12 13 #ifndef __EMU_H__ 14 #error Dont include this file directly; include emu.h instead. 15 #endif 16 17 #ifndef MAME_EMU_DIIMAGE_H 18 #define MAME_EMU_DIIMAGE_H 19 20 #include <memory> 21 #include <string> 22 #include <vector> 23 24 25 //************************************************************************** 26 // TYPE DEFINITIONS 27 //************************************************************************** 28 29 extern struct io_procs image_ioprocs; 30 31 enum iodevice_t 32 { 33 /* List of all supported devices. Refer to the device by these names only */ 34 IO_UNKNOWN, 35 IO_CARTSLOT, /* 1 - Cartridge Port, as found on most console and on some computers */ 36 IO_FLOPPY, /* 2 - Floppy Disk unit */ 37 IO_HARDDISK, /* 3 - Hard Disk unit */ 38 IO_CYLINDER, /* 4 - Magnetically-Coated Cylinder */ 39 IO_CASSETTE, /* 5 - Cassette Recorder (common on early home computers) */ 40 IO_PUNCHCARD, /* 6 - Card Puncher/Reader */ 41 IO_PUNCHTAPE, /* 7 - Tape Puncher/Reader (reels instead of punchcards) */ 42 IO_PRINTER, /* 8 - Printer device */ 43 IO_SERIAL, /* 9 - Generic Serial Port */ 44 IO_PARALLEL, /* 10 - Generic Parallel Port */ 45 IO_SNAPSHOT, /* 11 - Complete 'snapshot' of the state of the computer */ 46 IO_QUICKLOAD, /* 12 - Allow to load program/data into memory, without matching any actual device */ 47 IO_MEMCARD, /* 13 - Memory card */ 48 IO_CDROM, /* 14 - optical CD-ROM disc */ 49 IO_MAGTAPE, /* 15 - Magnetic tape */ 50 IO_ROM, /* 16 - Individual ROM image - the Amstrad CPC has a few applications that were sold on 16kB ROMs */ 51 IO_MIDIIN, /* 17 - MIDI In port */ 52 IO_MIDIOUT, /* 18 - MIDI Out port */ 53 IO_PICTURE, /* 19 - A single-frame image */ 54 IO_VIDEO, /* 20 - A video file */ 55 IO_COUNT /* 21 - Total Number of IO_devices for searching */ 56 }; 57 58 enum image_error_t 59 { 60 IMAGE_ERROR_SUCCESS, 61 IMAGE_ERROR_INTERNAL, 62 IMAGE_ERROR_UNSUPPORTED, 63 IMAGE_ERROR_OUTOFMEMORY, 64 IMAGE_ERROR_FILENOTFOUND, 65 IMAGE_ERROR_INVALIDIMAGE, 66 IMAGE_ERROR_ALREADYOPEN, 67 IMAGE_ERROR_UNSPECIFIED 68 }; 69 70 struct image_device_type_info 71 { 72 iodevice_t m_type; 73 const char *m_name; 74 const char *m_shortname; 75 }; 76 77 class image_device_format 78 { 79 public: 80 image_device_format(const std::string &name, const std::string &description, const std::string &extensions, const std::string &optspec); 81 ~image_device_format(); 82 name()83 const std::string &name() const noexcept { return m_name; } description()84 const std::string &description() const noexcept { return m_description; } extensions()85 const std::vector<std::string> &extensions() const noexcept { return m_extensions; } optspec()86 const std::string &optspec() const noexcept { return m_optspec; } 87 88 private: 89 std::string m_name; 90 std::string m_description; 91 std::vector<std::string> m_extensions; 92 std::string m_optspec; 93 }; 94 95 96 enum class image_init_result { PASS, FAIL }; 97 enum class image_verify_result { PASS, FAIL }; 98 99 //************************************************************************** 100 // MACROS 101 //************************************************************************** 102 103 #define DEVICE_IMAGE_LOAD_MEMBER(_name) image_init_result _name(device_image_interface &image) 104 #define DECLARE_DEVICE_IMAGE_LOAD_MEMBER(_name) DEVICE_IMAGE_LOAD_MEMBER(_name) 105 106 #define DEVICE_IMAGE_UNLOAD_MEMBER(_name) void _name(device_image_interface &image) 107 #define DECLARE_DEVICE_IMAGE_UNLOAD_MEMBER(_name) DEVICE_IMAGE_UNLOAD_MEMBER(_name) 108 109 110 // ======================> device_image_interface 111 112 // class representing interface-specific live image 113 class device_image_interface : public device_interface 114 { 115 public: 116 typedef device_delegate<image_init_result (device_image_interface &)> load_delegate; 117 typedef device_delegate<void (device_image_interface &)> unload_delegate; 118 119 typedef std::vector<std::unique_ptr<image_device_format>> formatlist_type; 120 121 // construction/destruction 122 device_image_interface(const machine_config &mconfig, device_t &device); 123 virtual ~device_image_interface(); 124 125 static const char *device_typename(iodevice_t type); 126 static const char *device_brieftypename(iodevice_t type); 127 static iodevice_t device_typeid(const char *name); 128 call_load()129 virtual image_init_result call_load() { return image_init_result::PASS; } call_create(int format_type,util::option_resolution * format_options)130 virtual image_init_result call_create(int format_type, util::option_resolution *format_options) { return image_init_result::PASS; } call_unload()131 virtual void call_unload() { } call_display()132 virtual std::string call_display() { return std::string(); } unhashed_header_length()133 virtual u32 unhashed_header_length() const noexcept { return 0; } core_opens_image_file()134 virtual bool core_opens_image_file() const noexcept { return true; } 135 virtual iodevice_t image_type() const noexcept = 0; 136 virtual bool is_readable() const noexcept = 0; 137 virtual bool is_writeable() const noexcept = 0; 138 virtual bool is_creatable() const noexcept = 0; 139 virtual bool must_be_loaded() const noexcept = 0; 140 virtual bool is_reset_on_load() const noexcept = 0; 141 virtual bool support_command_line_image_creation() const noexcept; image_interface()142 virtual const char *image_interface() const noexcept { return nullptr; } 143 virtual const char *file_extensions() const noexcept = 0; 144 virtual const util::option_guide &create_option_guide() const; custom_instance_name()145 virtual const char *custom_instance_name() const noexcept { return nullptr; } custom_brief_instance_name()146 virtual const char *custom_brief_instance_name() const noexcept { return nullptr; } 147 device_get_indexed_creatable_format(int index)148 const image_device_format *device_get_indexed_creatable_format(int index) const noexcept { return (index < m_formatlist.size()) ? m_formatlist.at(index).get() : nullptr; } 149 const image_device_format *device_get_named_creatable_format(const std::string &format_name) noexcept; device_get_creation_option_guide()150 const util::option_guide &device_get_creation_option_guide() const { return create_option_guide(); } 151 152 const char *error(); 153 void seterror(image_error_t err, const char *message); 154 void message(const char *format, ...) ATTR_PRINTF(2,3); 155 exists()156 bool exists() const noexcept { return !m_image_name.empty(); } filename()157 const char *filename() const noexcept { return m_image_name.empty() ? nullptr : m_image_name.c_str(); } basename()158 const char *basename() const noexcept { return m_basename.empty() ? nullptr : m_basename.c_str(); } basename_noext()159 const char *basename_noext() const noexcept { return m_basename_noext.empty() ? nullptr : m_basename_noext.c_str(); } filetype()160 const std::string &filetype() const noexcept { return m_filetype; } is_filetype(const std::string & candidate_filetype)161 bool is_filetype(const std::string &candidate_filetype) { return !core_stricmp(filetype().c_str(), candidate_filetype.c_str()); } is_open()162 bool is_open() const noexcept { return bool(m_file); } image_core_file()163 util::core_file &image_core_file() const noexcept { return *m_file; } length()164 u64 length() { check_for_file(); return m_file->size(); } is_readonly()165 bool is_readonly() const noexcept { return m_readonly; } fread(void * buffer,u32 length)166 u32 fread(void *buffer, u32 length) { check_for_file(); return m_file->read(buffer, length); } fread(optional_shared_ptr<u8> & ptr,u32 length)167 u32 fread(optional_shared_ptr<u8> &ptr, u32 length) { ptr.allocate(length); return fread(ptr.target(), length); } fread(optional_shared_ptr<u8> & ptr,u32 length,offs_t offset)168 u32 fread(optional_shared_ptr<u8> &ptr, u32 length, offs_t offset) { ptr.allocate(length); return fread(ptr + offset, length - offset); } fwrite(const void * buffer,u32 length)169 u32 fwrite(const void *buffer, u32 length) { check_for_file(); return m_file->write(buffer, length); } fseek(s64 offset,int whence)170 int fseek(s64 offset, int whence) { check_for_file(); return m_file->seek(offset, whence); } ftell()171 u64 ftell() { check_for_file(); return m_file->tell(); } fgetc()172 int fgetc() { char ch; if (fread(&ch, 1) != 1) ch = '\0'; return ch; } fgets(char * buffer,u32 length)173 char *fgets(char *buffer, u32 length) { check_for_file(); return m_file->gets(buffer, length); } image_feof()174 int image_feof() { check_for_file(); return m_file->eof(); } ptr()175 void *ptr() {check_for_file(); return const_cast<void *>(m_file->buffer()); } 176 // configuration access 177 longname()178 const std::string &longname() const noexcept { return m_longname; } manufacturer()179 const std::string &manufacturer() const noexcept { return m_manufacturer; } year()180 const std::string &year() const noexcept { return m_year; } supported()181 u32 supported() const noexcept { return m_supported; } 182 183 const software_info *software_entry() const noexcept; part_entry()184 const software_part *part_entry() const noexcept { return m_software_part_ptr; } software_list_name()185 const char *software_list_name() const noexcept { return m_software_list_name.c_str(); } loaded_through_softlist()186 bool loaded_through_softlist() const noexcept { return m_software_part_ptr != nullptr; } 187 set_working_directory(const char * working_directory)188 void set_working_directory(const char *working_directory) { m_working_directory = working_directory; } 189 const std::string &working_directory(); 190 191 u8 *get_software_region(const char *tag); 192 u32 get_software_region_length(const char *tag); 193 const char *get_feature(const char *feature_name) const; 194 bool load_software_region(const char *tag, optional_shared_ptr<u8> &ptr); 195 196 u32 crc(); hash()197 util::hash_collection& hash() { return m_hash; } 198 util::hash_collection calculate_hash_on_file(util::core_file &file) const; 199 200 void battery_load(void *buffer, int length, int fill); 201 void battery_load(void *buffer, int length, const void *def_buffer); 202 void battery_save(const void *buffer, int length); 203 image_type_name()204 const char *image_type_name() const { return device_typename(image_type()); } 205 instance_name()206 const std::string &instance_name() const { return m_instance_name; } brief_instance_name()207 const std::string &brief_instance_name() const { return m_brief_instance_name; } canonical_instance_name()208 const std::string &canonical_instance_name() const { return m_canonical_instance_name; } 209 bool uses_file_extension(const char *file_extension) const; formatlist()210 const formatlist_type &formatlist() const { return m_formatlist; } 211 212 // loads an image file 213 image_init_result load(const std::string &path); 214 215 // loads a softlist item by name 216 image_init_result load_software(const std::string &software_identifier); 217 218 image_init_result finish_load(); 219 void unload(); 220 image_init_result create(const std::string &path, const image_device_format *create_format, util::option_resolution *create_args); 221 image_init_result create(const std::string &path); 222 bool load_software(software_list_device &swlist, const char *swname, const rom_entry *entry); 223 int reopen_for_write(const std::string &path); 224 set_user_loadable(bool user_loadable)225 void set_user_loadable(bool user_loadable) { m_user_loadable = user_loadable; } 226 user_loadable()227 bool user_loadable() const noexcept { return m_user_loadable; } is_reset_and_loading()228 bool is_reset_and_loading() const noexcept { return m_is_reset_and_loading; } full_software_name()229 const std::string &full_software_name() const noexcept { return m_full_software_name; } 230 231 protected: 232 // interface-level overrides 233 virtual void interface_config_complete() override; 234 235 virtual const software_list_loader &get_software_list_loader() const; use_software_list_file_extension_for_filetype()236 virtual const bool use_software_list_file_extension_for_filetype() const { return false; } 237 238 image_init_result load_internal(const std::string &path, bool is_create, int create_format, util::option_resolution *create_args); 239 image_error_t load_image_by_path(u32 open_flags, const std::string &path); 240 void clear(); 241 bool is_loaded(); 242 243 void set_image_filename(const std::string &filename); 244 245 void clear_error(); 246 check_for_file()247 void check_for_file() const { if (!m_file) throw emu_fatalerror("%s(%s): Illegal operation on unmounted image", device().shortname(), device().tag()); } 248 249 void setup_working_directory(); 250 bool try_change_working_directory(const std::string &subdir); 251 make_readonly()252 void make_readonly() noexcept { m_readonly = true; } 253 254 bool image_checkhash(); 255 256 const software_part *find_software_item(const std::string &identifier, bool restrict_to_interface, software_list_device **device = nullptr) const; 257 std::string software_get_default_slot(const char *default_card_slot) const; 258 259 void add_format(std::unique_ptr<image_device_format> &&format); 260 void add_format(std::string &&name, std::string &&description, std::string &&extensions, std::string &&optspec); 261 262 // derived class overrides 263 264 // configuration 265 static const image_device_type_info *find_device_type(iodevice_t type); 266 static const image_device_type_info m_device_info_array[]; 267 268 // error related info 269 image_error_t m_err; 270 std::string m_err_message; 271 272 private: 273 // variables that are only non-zero when an image is mounted 274 util::core_file::ptr m_file; 275 std::unique_ptr<emu_file> m_mame_file; 276 std::string m_image_name; 277 std::string m_basename; 278 std::string m_basename_noext; 279 std::string m_filetype; 280 281 // Software information 282 std::string m_full_software_name; 283 const software_part *m_software_part_ptr; 284 std::string m_software_list_name; 285 286 static image_error_t image_error_from_file_error(osd_file::error filerr); 287 std::vector<u32> determine_open_plan(bool is_create); 288 void update_names(); 289 bool load_software_part(const std::string &identifier); 290 291 bool init_phase() const; 292 static bool run_hash(util::core_file &file, u32 skip_bytes, util::hash_collection &hashes, const char *types); 293 294 // loads an image or software items and resets - called internally when we 295 // load an is_reset_on_load() item 296 void reset_and_load(const std::string &path); 297 298 // creation info 299 formatlist_type m_formatlist; 300 301 // working directory; persists across mounts 302 std::string m_working_directory; 303 304 // info read from the hash file/software list 305 std::string m_longname; 306 std::string m_manufacturer; 307 std::string m_year; 308 u32 m_supported; 309 310 // flags 311 bool m_readonly; 312 bool m_created; 313 314 // special - used when creating 315 int m_create_format; 316 util::option_resolution *m_create_args; 317 318 util::hash_collection m_hash; 319 320 std::string m_instance_name; // e.g. - "cartridge", "floppydisk2" 321 std::string m_brief_instance_name; // e.g. - "cart", "flop2" 322 std::string m_canonical_instance_name; // e.g. - "cartridge1", "floppydisk2" - only used internally in emuopts.cpp 323 324 // in the case of arcade cabinet with fixed carts inserted, 325 // we want to disable command line cart loading... 326 bool m_user_loadable; 327 328 bool m_is_loading; 329 330 bool m_is_reset_and_loading; 331 }; 332 333 // iterator 334 typedef device_interface_iterator<device_image_interface> image_interface_iterator; 335 336 #endif /* MAME_EMU_DIIMAGE_H */ 337