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