1 // license:BSD-3-Clause
2 // copyright-holders:Miodrag Milanovic
3 /***************************************************************************
4 
5     diimage.cpp
6 
7     Device image interfaces.
8 
9 ***************************************************************************/
10 
11 #include "emu.h"
12 
13 #include "emuopts.h"
14 #include "drivenum.h"
15 #include "romload.h"
16 #include "ui/uimain.h"
17 #include "zippath.h"
18 #include "softlist.h"
19 #include "softlist_dev.h"
20 #include "formats/ioprocs.h"
21 
22 #include <cstring>
23 #include <regex>
24 
25 
26 //**************************************************************************
27 //  DEVICE CONFIG IMAGE INTERFACE
28 //**************************************************************************
29 const image_device_type_info device_image_interface::m_device_info_array[] =
30 	{
31 		{ IO_UNKNOWN,   "unknown",      "unkn" }, /*  0 */
32 		{ IO_CARTSLOT,  "cartridge",    "cart" }, /*  1 */
33 		{ IO_FLOPPY,    "floppydisk",   "flop" }, /*  2 */
34 		{ IO_HARDDISK,  "harddisk",     "hard" }, /*  3 */
35 		{ IO_CYLINDER,  "cylinder",     "cyln" }, /*  4 */
36 		{ IO_CASSETTE,  "cassette",     "cass" }, /*  5 */
37 		{ IO_PUNCHCARD, "punchcard",    "pcrd" }, /*  6 */
38 		{ IO_PUNCHTAPE, "punchtape",    "ptap" }, /*  7 */
39 		{ IO_PRINTER,   "printout",     "prin" }, /*  8 */
40 		{ IO_SERIAL,    "serial",       "serl" }, /*  9 */
41 		{ IO_PARALLEL,  "parallel",     "parl" }, /* 10 */
42 		{ IO_SNAPSHOT,  "snapshot",     "dump" }, /* 11 */
43 		{ IO_QUICKLOAD, "quickload",    "quik" }, /* 12 */
44 		{ IO_MEMCARD,   "memcard",      "memc" }, /* 13 */
45 		{ IO_CDROM,     "cdrom",        "cdrm" }, /* 14 */
46 		{ IO_MAGTAPE,   "magtape",      "magt" }, /* 15 */
47 		{ IO_ROM,       "romimage",     "rom"  }, /* 16 */
48 		{ IO_MIDIIN,    "midiin",       "min"  }, /* 17 */
49 		{ IO_MIDIOUT,   "midiout",      "mout" }, /* 18 */
50 		{ IO_PICTURE,   "picture",      "pic"  }, /* 19 */
51 		{ IO_VIDEO,     "vidfile",      "vid"  }  /* 20 */
52 	};
53 
54 
55 //**************************************************************************
56 //  IMAGE DEVICE FORMAT
57 //**************************************************************************
58 
59 //-------------------------------------------------
60 //  ctor
61 //-------------------------------------------------
62 
image_device_format(const std::string & name,const std::string & description,const std::string & extensions,const std::string & optspec)63 image_device_format::image_device_format(const std::string &name, const std::string &description, const std::string &extensions, const std::string &optspec)
64 	: m_name(name), m_description(description), m_optspec(optspec)
65 {
66 	std::regex comma_regex("\\,");
67 	std::copy(
68 		std::sregex_token_iterator(extensions.begin(), extensions.end(), comma_regex, -1),
69 		std::sregex_token_iterator(),
70 		std::back_inserter(m_extensions));
71 }
72 
73 
74 //-------------------------------------------------
75 //  dtor
76 //-------------------------------------------------
77 
~image_device_format()78 image_device_format::~image_device_format()
79 {
80 }
81 
82 
83 //**************************************************************************
84 //  DEVICE IMAGE INTERFACE
85 //**************************************************************************
86 
87 //-------------------------------------------------
88 //  device_image_interface - constructor
89 //-------------------------------------------------
90 
device_image_interface(const machine_config & mconfig,device_t & device)91 device_image_interface::device_image_interface(const machine_config &mconfig, device_t &device)
92 	: device_interface(device, "image")
93 	, m_err()
94 	, m_file()
95 	, m_mame_file()
96 	, m_software_part_ptr(nullptr)
97 	, m_supported(0)
98 	, m_readonly(false)
99 	, m_created(false)
100 	, m_create_format(0)
101 	, m_create_args(nullptr)
102 	, m_user_loadable(true)
103 	, m_is_loading(false)
104 	, m_is_reset_and_loading(false)
105 {
106 }
107 
108 
109 //-------------------------------------------------
110 //  ~device_image_interface - destructor
111 //-------------------------------------------------
112 
~device_image_interface()113 device_image_interface::~device_image_interface()
114 {
115 }
116 
117 
118 //-------------------------------------------------
119 //  interface_config_complete - perform any
120 //  operations now that the configuration is
121 //  complete
122 //-------------------------------------------------
123 
interface_config_complete()124 void device_image_interface::interface_config_complete()
125 {
126 	// set brief and instance name
127 	update_names();
128 }
129 
130 
131 //-------------------------------------------------
132 //  find_device_type - search trough list of
133 //  device types to extract data
134 //-------------------------------------------------
135 
find_device_type(iodevice_t type)136 const image_device_type_info *device_image_interface::find_device_type(iodevice_t type)
137 {
138 	int i;
139 	for (i = 0; i < ARRAY_LENGTH(device_image_interface::m_device_info_array); i++)
140 	{
141 		if (m_device_info_array[i].m_type == type)
142 			return &m_device_info_array[i];
143 	}
144 	return nullptr;
145 }
146 
147 //-------------------------------------------------
148 //  device_typename - retrieves device type name
149 //-------------------------------------------------
150 
device_typename(iodevice_t type)151 const char *device_image_interface::device_typename(iodevice_t type)
152 {
153 	const image_device_type_info *info = find_device_type(type);
154 	return (info != nullptr) ? info->m_name : "unknown";
155 }
156 
157 //-------------------------------------------------
158 //  device_brieftypename - retrieves device
159 //  brief type name
160 //-------------------------------------------------
161 
device_brieftypename(iodevice_t type)162 const char *device_image_interface::device_brieftypename(iodevice_t type)
163 {
164 	const image_device_type_info *info = find_device_type(type);
165 	return (info != nullptr) ? info->m_shortname : "unk";
166 }
167 
168 //-------------------------------------------------
169 //  device_typeid - retrieves device type id
170 //-------------------------------------------------
171 
device_typeid(const char * name)172 iodevice_t device_image_interface::device_typeid(const char *name)
173 {
174 	int i;
175 	for (i = 0; i < ARRAY_LENGTH(device_image_interface::m_device_info_array); i++)
176 	{
177 		if (!core_stricmp(name, m_device_info_array[i].m_name) || !core_stricmp(name, m_device_info_array[i].m_shortname))
178 			return m_device_info_array[i].m_type;
179 	}
180 	return (iodevice_t)-1;
181 }
182 
183 //-------------------------------------------------
184 //  set_image_filename - specifies the filename of
185 //  an image
186 //-------------------------------------------------
187 
set_image_filename(const std::string & filename)188 void device_image_interface::set_image_filename(const std::string &filename)
189 {
190 	m_image_name = filename;
191 	util::zippath_parent(m_working_directory, filename);
192 	m_basename.assign(m_image_name);
193 
194 	// find the last "path separator"
195 	auto iter = std::find_if(
196 		m_image_name.rbegin(),
197 		m_image_name.rend(),
198 		[](char c) { return (c == '\\') || (c == '/') || (c == ':'); });
199 
200 	if (iter != m_image_name.rend())
201 		m_basename.assign(iter.base(), m_image_name.end());
202 
203 	m_basename_noext = m_basename;
204 	auto loc = m_basename_noext.find_last_of('.');
205 	if (loc != std::string::npos)
206 		m_basename_noext = m_basename_noext.substr(0, loc);
207 
208 	m_filetype = core_filename_extract_extension(m_basename, true);
209 }
210 
211 
212 /****************************************************************************
213     CREATION FORMATS
214 ****************************************************************************/
215 
216 //-------------------------------------------------
217 //  device_get_named_creatable_format -
218 //  accesses a specific image format available for
219 //  image creation by name
220 //-------------------------------------------------
221 
device_get_named_creatable_format(const std::string & format_name)222 const image_device_format *device_image_interface::device_get_named_creatable_format(const std::string &format_name) noexcept
223 {
224 	for (auto &format : m_formatlist)
225 		if (format->name() == format_name)
226 			return format.get();
227 	return nullptr;
228 }
229 
230 
231 //-------------------------------------------------
232 //  add_format
233 //-------------------------------------------------
234 
add_format(std::unique_ptr<image_device_format> && format)235 void device_image_interface::add_format(std::unique_ptr<image_device_format> &&format)
236 {
237 	m_formatlist.push_back(std::move(format));
238 }
239 
240 
241 //-------------------------------------------------
242 //  add_format
243 //-------------------------------------------------
244 
add_format(std::string && name,std::string && description,std::string && extensions,std::string && optspec)245 void device_image_interface::add_format(std::string &&name, std::string &&description, std::string &&extensions, std::string &&optspec)
246 {
247 	auto format = std::make_unique<image_device_format>(std::move(name), std::move(description), std::move(extensions), std::move(optspec));
248 	add_format(std::move(format));
249 }
250 
251 
252 /****************************************************************************
253     ERROR HANDLING
254 ****************************************************************************/
255 
256 //-------------------------------------------------
257 //  image_clear_error - clear out any specified
258 //  error
259 //-------------------------------------------------
260 
clear_error()261 void device_image_interface::clear_error()
262 {
263 	m_err = IMAGE_ERROR_SUCCESS;
264 	if (!m_err_message.empty())
265 	{
266 		m_err_message.clear();
267 	}
268 }
269 
270 
271 
272 //-------------------------------------------------
273 //  error - returns the error text for an image
274 //  error
275 //-------------------------------------------------
276 
277 static const char *const messages[] =
278 {
279 	"",
280 	"Internal error",
281 	"Unsupported operation",
282 	"Out of memory",
283 	"File not found",
284 	"Invalid image",
285 	"File already open",
286 	"Unspecified error"
287 };
288 
error()289 const char *device_image_interface::error()
290 {
291 	return (!m_err_message.empty()) ? m_err_message.c_str() : messages[m_err];
292 }
293 
294 
295 
296 //-------------------------------------------------
297 //  seterror - specifies an error on an image
298 //-------------------------------------------------
299 
seterror(image_error_t err,const char * message)300 void device_image_interface::seterror(image_error_t err, const char *message)
301 {
302 	clear_error();
303 	m_err = err;
304 	if (message != nullptr)
305 	{
306 		m_err_message = message;
307 	}
308 }
309 
310 
311 
312 //-------------------------------------------------
313 //  message - used to display a message while
314 //  loading
315 //-------------------------------------------------
316 
message(const char * format,...)317 void device_image_interface::message(const char *format, ...)
318 {
319 	va_list args;
320 	char buffer[256];
321 
322 	/* format the message */
323 	va_start(args, format);
324 	vsnprintf(buffer, ARRAY_LENGTH(buffer), format, args);
325 	va_end(args);
326 
327 	/* display the popup for a standard amount of time */
328 	device().machine().ui().popup_time(5, "%s: %s",
329 		basename(),
330 		buffer);
331 }
332 
333 
334 /***************************************************************************
335     WORKING DIRECTORIES
336 ***************************************************************************/
337 
338 //-------------------------------------------------
339 //  try_change_working_directory - tries to change
340 //  the working directory, but only if the directory
341 //  actually exists
342 //-------------------------------------------------
343 
try_change_working_directory(const std::string & subdir)344 bool device_image_interface::try_change_working_directory(const std::string &subdir)
345 {
346 	const osd::directory::entry *entry;
347 	bool success = false;
348 	bool done = false;
349 
350 	auto directory = osd::directory::open(m_working_directory);
351 	if (directory)
352 	{
353 		while (!done && (entry = directory->read()) != nullptr)
354 		{
355 			if (!core_stricmp(subdir.c_str(), entry->name))
356 			{
357 				done = true;
358 				success = entry->type == osd::directory::entry::entry_type::DIR;
359 			}
360 		}
361 
362 		directory.reset();
363 	}
364 
365 	// did we successfully identify the directory?
366 	if (success)
367 		m_working_directory = util::zippath_combine(m_working_directory, subdir);
368 
369 	return success;
370 }
371 
372 
373 //-------------------------------------------------
374 //  setup_working_directory - sets up the working
375 //  directory according to a few defaults
376 //-------------------------------------------------
377 
setup_working_directory()378 void device_image_interface::setup_working_directory()
379 {
380 	bool success = false;
381 	// get user-specified directory and make sure it exists
382 	m_working_directory = device().mconfig().options().sw_path();
383 	// if multipath, get first
384 	size_t i = m_working_directory.find_first_of(';');
385 	if (i != std::string::npos)
386 		m_working_directory.resize(i);
387 	// validate directory
388 	if (!m_working_directory.empty())
389 		if (osd::directory::open(m_working_directory))
390 			success = true;
391 
392 	// if not exist, use previous method
393 	if (!success)
394 	{
395 		// first set up the working directory to be the starting directory
396 		osd_get_full_path(m_working_directory, ".");
397 		// now try browsing down to "software"
398 		if (try_change_working_directory("software"))
399 			success = true;
400 	}
401 
402 	if (success)
403 	{
404 		// now down to a directory for this computer
405 		int gamedrv = driver_list::find(device().machine().system());
406 		while(gamedrv != -1 && !try_change_working_directory(driver_list::driver(gamedrv).name))
407 		{
408 			gamedrv = driver_list::compatible_with(gamedrv);
409 		}
410 	}
411 }
412 
413 
414 //-------------------------------------------------
415 //  working_directory - returns the working
416 //  directory to use for this image; this is
417 //  valid even if not mounted
418 //-------------------------------------------------
419 
working_directory()420 const std::string &device_image_interface::working_directory()
421 {
422 	// check to see if we've never initialized the working directory
423 	if (m_working_directory.empty())
424 		setup_working_directory();
425 
426 	return m_working_directory;
427 }
428 
429 
430 //-------------------------------------------------
431 //  software_entry - return a pointer to the
432 //  software_info structure from the softlist
433 //-------------------------------------------------
434 
software_entry() const435 const software_info *device_image_interface::software_entry() const noexcept
436 {
437 	return !m_software_part_ptr ? nullptr : &m_software_part_ptr->info();
438 }
439 
440 
441 //-------------------------------------------------
442 //  get_software_region
443 //-------------------------------------------------
444 
get_software_region(const char * tag)445 u8 *device_image_interface::get_software_region(const char *tag)
446 {
447 	if (!loaded_through_softlist())
448 		return nullptr;
449 
450 	std::string full_tag = util::string_format("%s:%s", device().tag(), tag);
451 	memory_region *region = device().machine().root_device().memregion(full_tag);
452 	return region != nullptr ? region->base() : nullptr;
453 }
454 
455 
456 //-------------------------------------------------
457 //  image_get_software_region_length
458 //-------------------------------------------------
459 
get_software_region_length(const char * tag)460 u32 device_image_interface::get_software_region_length(const char *tag)
461 {
462 	std::string full_tag = util::string_format("%s:%s", device().tag(), tag);
463 	memory_region *region = device().machine().root_device().memregion(full_tag);
464 	return region != nullptr ? region->bytes() : 0;
465 }
466 
467 
468 //-------------------------------------------------
469 //  image_get_feature
470 //-------------------------------------------------
471 
get_feature(const char * feature_name) const472 const char *device_image_interface::get_feature(const char *feature_name) const
473 {
474 	return !m_software_part_ptr ? nullptr : m_software_part_ptr->feature(feature_name);
475 }
476 
477 
478 //-------------------------------------------------
479 //  load_software_region -
480 //-------------------------------------------------
481 
load_software_region(const char * tag,optional_shared_ptr<u8> & ptr)482 bool device_image_interface::load_software_region(const char *tag, optional_shared_ptr<u8> &ptr)
483 {
484 	size_t size = get_software_region_length(tag);
485 
486 	if (size)
487 	{
488 		ptr.allocate(size);
489 
490 		memcpy(ptr, get_software_region(tag), size);
491 	}
492 
493 	return size > 0;
494 }
495 
496 
497 // ****************************************************************************
498 // Hash info loading
499 //
500 // If the hash is not checked and the relevant info not loaded, force that info
501 // to be loaded
502 // ****************************************************************************
503 
run_hash(util::core_file & file,u32 skip_bytes,util::hash_collection & hashes,const char * types)504 bool device_image_interface::run_hash(util::core_file &file, u32 skip_bytes, util::hash_collection &hashes, const char *types)
505 {
506 	// reset the hash; we want to override existing data
507 	hashes.reset();
508 
509 	// figure out the size, and "cap" the skip bytes
510 	u64 size = file.size();
511 	skip_bytes = (u32) std::min((u64) skip_bytes, size);
512 
513 	// seek to the beginning
514 	file.seek(skip_bytes, SEEK_SET);
515 	u64 position = skip_bytes;
516 
517 	// keep on reading hashes
518 	hashes.begin(types);
519 	while (position < size)
520 	{
521 		uint8_t buffer[8192];
522 
523 		// read bytes
524 		const u32 count = (u32) std::min(size - position, (u64) sizeof(buffer));
525 		const u32 actual_count = file.read(buffer, count);
526 		if (actual_count == 0)
527 			return false;
528 		position += actual_count;
529 
530 		// and compute the hashes
531 		hashes.buffer(buffer, actual_count);
532 	}
533 	hashes.end();
534 
535 	// cleanup
536 	file.seek(0, SEEK_SET);
537 	return true;
538 }
539 
540 
541 
image_checkhash()542 bool device_image_interface::image_checkhash()
543 {
544 	// only calculate CRC if it hasn't been calculated, and the open_mode is read only
545 	u32 crcval;
546 	if (!m_hash.crc(crcval) && is_readonly() && !m_created)
547 	{
548 		// do not cause a linear read of 600 megs please
549 		// TODO: use SHA1 in the CHD header as the hash
550 		if (image_type() == IO_CDROM)
551 			return true;
552 
553 		// Skip calculating the hash when we have an image mounted through a software list
554 		if (loaded_through_softlist())
555 			return true;
556 
557 		// run the hash
558 		if (!run_hash(*m_file, unhashed_header_length(), m_hash, util::hash_collection::HASH_TYPES_ALL))
559 			return false;
560 	}
561 	return true;
562 }
563 
564 
calculate_hash_on_file(util::core_file & file) const565 util::hash_collection device_image_interface::calculate_hash_on_file(util::core_file &file) const
566 {
567 	// calculate the hash
568 	util::hash_collection hash;
569 	if (!run_hash(file, unhashed_header_length(), hash, util::hash_collection::HASH_TYPES_ALL))
570 		hash.reset();
571 	return hash;
572 }
573 
574 
crc()575 u32 device_image_interface::crc()
576 {
577 	u32 crc = 0;
578 
579 	image_checkhash();
580 	m_hash.crc(crc);
581 
582 	return crc;
583 }
584 
585 
586 //-------------------------------------------------
587 //  support_command_line_image_creation - do we
588 //  want to support image creation from the front
589 //  end command line?
590 //-------------------------------------------------
591 
support_command_line_image_creation() const592 bool device_image_interface::support_command_line_image_creation() const noexcept
593 {
594 	bool result;
595 	switch (image_type())
596 	{
597 	case IO_PRINTER:
598 	case IO_SERIAL:
599 	case IO_PARALLEL:
600 		// going by the assumption that these device image types should support this
601 		// behavior; ideally we'd get rid of IO_* and just push this to the specific
602 		// devices
603 		result = true;
604 		break;
605 	default:
606 		result = false;
607 		break;
608 	}
609 	return result;
610 }
611 
612 
613 // ****************************************************************************
614 // Battery functions
615 //
616 // These functions provide transparent access to battery-backed RAM on an
617 // image; typically for cartridges.
618 // ****************************************************************************
619 
620 
621 //-------------------------------------------------
622 //  battery_load - retrieves the battery
623 //  backed RAM for an image. The file name is
624 //  created from the machine driver name and the
625 //  image name.
626 //-------------------------------------------------
627 
battery_load(void * buffer,int length,int fill)628 void device_image_interface::battery_load(void *buffer, int length, int fill)
629 {
630 	if (!buffer || (length <= 0))
631 		throw emu_fatalerror("device_image_interface::battery_load: Must specify sensical buffer/length");
632 
633 	osd_file::error filerr;
634 	int bytes_read = 0;
635 	std::string fname = std::string(device().machine().system().name).append(PATH_SEPARATOR).append(m_basename_noext).append(".nv");
636 
637 	/* try to open the battery file and read it in, if possible */
638 	emu_file file(device().machine().options().nvram_directory(), OPEN_FLAG_READ);
639 	filerr = file.open(fname);
640 	if (filerr == osd_file::error::NONE)
641 		bytes_read = file.read(buffer, length);
642 
643 	// fill remaining bytes (if necessary)
644 	memset(((char *)buffer) + bytes_read, fill, length - bytes_read);
645 }
646 
battery_load(void * buffer,int length,const void * def_buffer)647 void device_image_interface::battery_load(void *buffer, int length, const void *def_buffer)
648 {
649 	if (!buffer || (length <= 0))
650 		throw emu_fatalerror("device_image_interface::battery_load: Must specify sensical buffer/length");
651 
652 	osd_file::error filerr;
653 	int bytes_read = 0;
654 	std::string fname = std::string(device().machine().system().name).append(PATH_SEPARATOR).append(m_basename_noext).append(".nv");
655 
656 	// try to open the battery file and read it in, if possible
657 	emu_file file(device().machine().options().nvram_directory(), OPEN_FLAG_READ);
658 	filerr = file.open(fname);
659 	if (filerr == osd_file::error::NONE)
660 		bytes_read = file.read(buffer, length);
661 
662 	// if no file was present, copy the default contents
663 	if (!bytes_read && def_buffer)
664 		std::memcpy(buffer, def_buffer, length);
665 }
666 
667 
668 //-------------------------------------------------
669 //  battery_save - stores the battery
670 //  backed RAM for an image. The file name is
671 //  created from the machine driver name and the
672 //  image name.
673 //-------------------------------------------------
674 
battery_save(const void * buffer,int length)675 void device_image_interface::battery_save(const void *buffer, int length)
676 {
677 	if (!buffer || (length <= 0))
678 		throw emu_fatalerror("device_image_interface::battery_save: Must specify sensical buffer/length");
679 
680 	if (!device().machine().options().nvram_save())
681 		return;
682 
683 	std::string fname = std::string(device().machine().system().name).append(PATH_SEPARATOR).append(m_basename_noext).append(".nv");
684 
685 	// try to open the battery file and write it out, if possible
686 	emu_file file(device().machine().options().nvram_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
687 	osd_file::error filerr = file.open(fname);
688 	if (filerr == osd_file::error::NONE)
689 		file.write(buffer, length);
690 }
691 
692 
693 //-------------------------------------------------
694 //  uses_file_extension - update configuration
695 //  based on completed device setup
696 //-------------------------------------------------
697 
uses_file_extension(const char * file_extension) const698 bool device_image_interface::uses_file_extension(const char *file_extension) const
699 {
700 	bool result = false;
701 
702 	if (file_extension[0] == '.')
703 		file_extension++;
704 
705 	/* find the extensions */
706 	std::string extensions(file_extensions());
707 	char *ext = strtok((char*)extensions.c_str(),",");
708 	while (ext != nullptr)
709 	{
710 		if (!core_stricmp(ext, file_extension))
711 		{
712 			result = true;
713 			break;
714 		}
715 		ext = strtok (nullptr, ",");
716 	}
717 	return result;
718 }
719 
720 
721 // ***************************************************************************
722 // IMAGE LOADING
723 // ***************************************************************************
724 
725 //-------------------------------------------------
726 //  is_loaded - quick check to determine whether an
727 //  image is loaded
728 //-------------------------------------------------
729 
is_loaded()730 bool device_image_interface::is_loaded()
731 {
732 	return (m_file != nullptr);
733 }
734 
735 //-------------------------------------------------
736 //  image_error_from_file_error - converts an image
737 //  error to a file error
738 //-------------------------------------------------
739 
image_error_from_file_error(osd_file::error filerr)740 image_error_t device_image_interface::image_error_from_file_error(osd_file::error filerr)
741 {
742 	switch (filerr)
743 	{
744 	case osd_file::error::NONE:
745 		return IMAGE_ERROR_SUCCESS;
746 
747 	case osd_file::error::NOT_FOUND:
748 	case osd_file::error::ACCESS_DENIED:
749 		// file not found (or otherwise cannot open)
750 		return IMAGE_ERROR_FILENOTFOUND;
751 
752 	case osd_file::error::OUT_OF_MEMORY:
753 		// out of memory
754 		return IMAGE_ERROR_OUTOFMEMORY;
755 
756 	case osd_file::error::ALREADY_OPEN:
757 		// this shouldn't happen
758 		return IMAGE_ERROR_ALREADYOPEN;
759 
760 	case osd_file::error::FAILURE:
761 	case osd_file::error::TOO_MANY_FILES:
762 	case osd_file::error::INVALID_DATA:
763 	default:
764 		// other errors
765 		return IMAGE_ERROR_INTERNAL;
766 	}
767 }
768 
769 
770 //-------------------------------------------------
771 //  load_image_by_path - loads an image with a
772 //  specific path
773 //-------------------------------------------------
774 
load_image_by_path(u32 open_flags,const std::string & path)775 image_error_t device_image_interface::load_image_by_path(u32 open_flags, const std::string &path)
776 {
777 	std::string revised_path;
778 
779 	// attempt to read the file
780 	auto const filerr = util::zippath_fopen(path, open_flags, m_file, revised_path);
781 	if (filerr != osd_file::error::NONE)
782 		return image_error_from_file_error(filerr);
783 
784 	m_readonly = (open_flags & OPEN_FLAG_WRITE) ? 0 : 1;
785 	m_created = (open_flags & OPEN_FLAG_CREATE) ? 1 : 0;
786 	set_image_filename(revised_path);
787 	return IMAGE_ERROR_SUCCESS;
788 }
789 
790 
791 //-------------------------------------------------
792 //  reopen_for_write
793 //-------------------------------------------------
794 
reopen_for_write(const std::string & path)795 int device_image_interface::reopen_for_write(const std::string &path)
796 {
797 	m_file.reset();
798 
799 	std::string revised_path;
800 
801 	// attempt to open the file for writing
802 	auto const filerr = util::zippath_fopen(path, OPEN_FLAG_READ|OPEN_FLAG_WRITE|OPEN_FLAG_CREATE, m_file, revised_path);
803 	if (filerr != osd_file::error::NONE)
804 		return image_error_from_file_error(filerr);
805 
806 	// success!
807 	m_readonly = 0;
808 	m_created = 1;
809 	set_image_filename(revised_path);
810 
811 	return IMAGE_ERROR_SUCCESS;
812 }
813 
814 
815 //-------------------------------------------------
816 //  determine_open_plan - determines which open
817 //  flags to use, and in what order
818 //-------------------------------------------------
819 
determine_open_plan(bool is_create)820 std::vector<u32> device_image_interface::determine_open_plan(bool is_create)
821 {
822 	std::vector<u32> open_plan;
823 
824 	// emit flags into a vector
825 	if (!is_create && is_readable() && is_writeable())
826 		open_plan.push_back(OPEN_FLAG_READ | OPEN_FLAG_WRITE);
827 	if (!is_create && !is_readable() && is_writeable())
828 		open_plan.push_back(OPEN_FLAG_WRITE);
829 	if (!is_create && is_readable())
830 		open_plan.push_back(OPEN_FLAG_READ);
831 	if (is_create && is_writeable() && is_creatable())
832 		open_plan.push_back(OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE);
833 
834 	return open_plan;
835 }
836 
837 
838 //-------------------------------------------------
839 //  verify_length_and_hash - verify the length
840 //  and hash signatures of a file
841 //-------------------------------------------------
842 
verify_length_and_hash(emu_file * file,const char * name,u32 explength,const util::hash_collection & hashes)843 static int verify_length_and_hash(emu_file *file, const char *name, u32 explength, const util::hash_collection &hashes)
844 {
845 	int retval = 0;
846 	if (!file)
847 		return 0;
848 
849 	// verify length
850 	u32 actlength = file->size();
851 	if (explength != actlength)
852 	{
853 		osd_printf_error("%s WRONG LENGTH (expected: %d found: %d)\n", name, explength, actlength);
854 		retval++;
855 	}
856 
857 	util::hash_collection &acthashes = file->hashes(hashes.hash_types().c_str());
858 	if (hashes.flag(util::hash_collection::FLAG_NO_DUMP))
859 	{
860 		// If there is no good dump known, write it
861 		osd_printf_error("%s NO GOOD DUMP KNOWN\n", name);
862 	}
863 	else if (hashes != acthashes)
864 	{
865 		// otherwise, it's just bad
866 		osd_printf_error("%s WRONG CHECKSUMS:\n", name);
867 		osd_printf_error("    EXPECTED: %s\n", hashes.macro_string());
868 		osd_printf_error("       FOUND: %s\n", acthashes.macro_string());
869 		retval++;
870 	}
871 	else if (hashes.flag(util::hash_collection::FLAG_BAD_DUMP))
872 	{
873 		// If it matches, but it is actually a bad dump, write it
874 		osd_printf_error("%s NEEDS REDUMP\n",name);
875 	}
876 	return retval;
877 }
878 
879 
880 //-------------------------------------------------
881 //  load_software - software image loading
882 //-------------------------------------------------
883 
load_software(software_list_device & swlist,const char * swname,const rom_entry * start)884 bool device_image_interface::load_software(software_list_device &swlist, const char *swname, const rom_entry *start)
885 {
886 	bool retval = false;
887 	int warningcount = 0;
888 	for (const rom_entry *region = start; region; region = rom_next_region(region))
889 	{
890 		// loop until we hit the end of this region
891 		for (const rom_entry *romp = region + 1; !ROMENTRY_ISREGIONEND(romp); romp++)
892 		{
893 			// handle files
894 			if (ROMENTRY_ISFILE(romp))
895 			{
896 				const software_info *const swinfo = swlist.find(swname);
897 				if (!swinfo)
898 					return false;
899 
900 				const u32 supported = swinfo->supported();
901 				if (supported == SOFTWARE_SUPPORTED_PARTIAL)
902 					osd_printf_error("WARNING: support for software %s (in list %s) is only partial\n", swname, swlist.list_name());
903 				if (supported == SOFTWARE_SUPPORTED_NO)
904 					osd_printf_error("WARNING: support for software %s (in list %s) is only preliminary\n", swname, swlist.list_name());
905 
906 				u32 crc = 0;
907 				const bool has_crc = util::hash_collection(ROM_GETHASHDATA(romp)).crc(crc);
908 				std::vector<const software_info *> parents;
909 				std::vector<std::string> searchpath = rom_load_manager::get_software_searchpath(swlist, *swinfo);
910 
911 				// for historical reasons, add the search path for the software list device's owner
912 				const device_t *const listowner = swlist.owner();
913 				if (listowner)
914 				{
915 					std::vector<std::string> devsearch = listowner->searchpath();
916 					for (std::string &path : devsearch)
917 						searchpath.emplace_back(std::move(path));
918 				}
919 
920 				// try to load the file
921 				m_mame_file.reset(new emu_file(device().machine().options().media_path(), searchpath, OPEN_FLAG_READ));
922 				m_mame_file->set_restrict_to_mediapath(1);
923 				osd_file::error filerr;
924 				if (has_crc)
925 					filerr = m_mame_file->open(ROM_GETNAME(romp), crc);
926 				else
927 					filerr = m_mame_file->open(ROM_GETNAME(romp));
928 				if (filerr != osd_file::error::NONE)
929 					m_mame_file.reset();
930 
931 				warningcount += verify_length_and_hash(m_mame_file.get(), ROM_GETNAME(romp), ROM_GETLENGTH(romp), util::hash_collection(ROM_GETHASHDATA(romp)));
932 
933 				if (filerr == osd_file::error::NONE)
934 					filerr = util::core_file::open_proxy(*m_mame_file, m_file);
935 				if (filerr == osd_file::error::NONE)
936 					retval = true;
937 
938 				break; // load first item for start
939 			}
940 		}
941 	}
942 
943 	if (warningcount > 0)
944 		osd_printf_error("WARNING: the software item might not run correctly.\n");
945 
946 	return retval;
947 }
948 
949 
950 //-------------------------------------------------
951 //  load_internal - core image loading
952 //-------------------------------------------------
953 
load_internal(const std::string & path,bool is_create,int create_format,util::option_resolution * create_args)954 image_init_result device_image_interface::load_internal(const std::string &path, bool is_create, int create_format, util::option_resolution *create_args)
955 {
956 	// first unload the image
957 	unload();
958 
959 	// clear any possible error messages
960 	clear_error();
961 
962 	// we are now loading
963 	m_is_loading = true;
964 
965 	// record the filename
966 	set_image_filename(path);
967 
968 	if (core_opens_image_file())
969 	{
970 		// determine open plan
971 		std::vector<u32> open_plan = determine_open_plan(is_create);
972 
973 		// attempt to open the file in various ways
974 		for (auto iter = open_plan.cbegin(); !m_file && iter != open_plan.cend(); iter++)
975 		{
976 			// open the file
977 			m_err = load_image_by_path(*iter, path);
978 			if (m_err && (m_err != IMAGE_ERROR_FILENOTFOUND))
979 				goto done;
980 		}
981 
982 		// did we fail to find the file?
983 		if (!is_loaded())
984 		{
985 			m_err = IMAGE_ERROR_FILENOTFOUND;
986 			goto done;
987 		}
988 	}
989 
990 	// call device load or create
991 	m_create_format = create_format;
992 	m_create_args = create_args;
993 
994 	if (init_phase()==false) {
995 		m_err = (finish_load() == image_init_result::PASS) ? IMAGE_ERROR_SUCCESS : IMAGE_ERROR_INTERNAL;
996 		if (m_err)
997 			goto done;
998 	}
999 	// success!
1000 
1001 done:
1002 	if (m_err!=0) {
1003 		if (!init_phase())
1004 		{
1005 			if (device().machine().phase() == machine_phase::RUNNING)
1006 				device().popmessage("Error: Unable to %s image '%s': %s", is_create ? "create" : "load", path, error());
1007 			else
1008 				osd_printf_error("Error: Unable to %s image '%s': %s\n", is_create ? "create" : "load", path, error());
1009 		}
1010 		clear();
1011 	}
1012 	return m_err ? image_init_result::FAIL : image_init_result::PASS;
1013 }
1014 
1015 
1016 //-------------------------------------------------
1017 //  load - load an image into MAME
1018 //-------------------------------------------------
1019 
load(const std::string & path)1020 image_init_result device_image_interface::load(const std::string &path)
1021 {
1022 	// is this a reset on load item?
1023 	if (is_reset_on_load() && !init_phase())
1024 	{
1025 		reset_and_load(path);
1026 		return image_init_result::PASS;
1027 	}
1028 
1029 	return load_internal(path, false, 0, nullptr);
1030 }
1031 
1032 
1033 //-------------------------------------------------
1034 //  load_software - loads a softlist item by name
1035 //-------------------------------------------------
1036 
load_software(const std::string & software_identifier)1037 image_init_result device_image_interface::load_software(const std::string &software_identifier)
1038 {
1039 	// Is this a software part that forces a reset and we're at runtime?  If so, get this loaded through reset_and_load
1040 	if (is_reset_on_load() && !init_phase())
1041 	{
1042 		reset_and_load(software_identifier);
1043 		return image_init_result::PASS;
1044 	}
1045 
1046 	// Prepare to load
1047 	unload();
1048 	clear_error();
1049 	m_is_loading = true;
1050 
1051 	// Check if there's a software list defined for this device and use that if we're not creating an image
1052 	bool softload = load_software_part(software_identifier);
1053 	if (!softload)
1054 	{
1055 		m_is_loading = false;
1056 		return image_init_result::FAIL;
1057 	}
1058 
1059 	// set up softlist stuff
1060 	m_full_software_name = m_software_part_ptr->info().shortname();
1061 
1062 	// specify image name with softlist-derived names
1063 	m_image_name = m_full_software_name;
1064 	m_basename = m_full_software_name;
1065 	m_basename_noext = m_full_software_name;
1066 	m_filetype = use_software_list_file_extension_for_filetype() && m_mame_file != nullptr
1067 		? core_filename_extract_extension(m_mame_file->filename(), true)
1068 		: "";
1069 
1070 	// Copy some image information when we have been loaded through a software list
1071 	software_info &swinfo = m_software_part_ptr->info();
1072 
1073 	// sanitize
1074 	if (swinfo.longname().empty() || swinfo.publisher().empty() || swinfo.year().empty())
1075 		fatalerror("Each entry in an XML list must have all of the following fields: description, publisher, year!\n");
1076 
1077 	// store
1078 	m_longname = swinfo.longname();
1079 	m_manufacturer = swinfo.publisher();
1080 	m_year = swinfo.year();
1081 
1082 	// set file type
1083 	std::string filename = (m_mame_file != nullptr) && (m_mame_file->filename() != nullptr)
1084 			? m_mame_file->filename()
1085 			: "";
1086 	m_filetype = core_filename_extract_extension(filename, true);
1087 
1088 	// call finish_load if necessary
1089 	if (init_phase() == false && (finish_load() != image_init_result::PASS))
1090 		return image_init_result::FAIL;
1091 
1092 	return image_init_result::PASS;
1093 }
1094 
1095 
1096 //-------------------------------------------------
1097 //  image_finish_load - special call - only use
1098 //  from core
1099 //-------------------------------------------------
1100 
finish_load()1101 image_init_result device_image_interface::finish_load()
1102 {
1103 	image_init_result err = image_init_result::PASS;
1104 
1105 	if (m_is_loading)
1106 	{
1107 		if (!image_checkhash())
1108 		{
1109 			m_err = IMAGE_ERROR_INVALIDIMAGE;
1110 			err = image_init_result::FAIL;
1111 		}
1112 
1113 		if (err == image_init_result::PASS)
1114 		{
1115 			if (m_created)
1116 			{
1117 				err = call_create(m_create_format, m_create_args);
1118 				if (err != image_init_result::PASS)
1119 				{
1120 					if (!m_err)
1121 						m_err = IMAGE_ERROR_UNSPECIFIED;
1122 				}
1123 			}
1124 			else
1125 			{
1126 				// using device load
1127 				err = call_load();
1128 				if (err != image_init_result::PASS)
1129 				{
1130 					if (!m_err)
1131 						m_err = IMAGE_ERROR_UNSPECIFIED;
1132 				}
1133 			}
1134 		}
1135 	}
1136 	m_is_loading = false;
1137 	m_create_format = 0;
1138 	m_create_args = nullptr;
1139 	return err;
1140 }
1141 
1142 
1143 //-------------------------------------------------
1144 //  create - create a image
1145 //-------------------------------------------------
1146 
create(const std::string & path)1147 image_init_result device_image_interface::create(const std::string &path)
1148 {
1149 	return create(path, nullptr, nullptr);
1150 }
1151 
1152 
1153 //-------------------------------------------------
1154 //  create - create a image
1155 //-------------------------------------------------
1156 
create(const std::string & path,const image_device_format * create_format,util::option_resolution * create_args)1157 image_init_result device_image_interface::create(const std::string &path, const image_device_format *create_format, util::option_resolution *create_args)
1158 {
1159 	int format_index = 0;
1160 	int cnt = 0;
1161 	for (auto &format : m_formatlist)
1162 	{
1163 		if (create_format == format.get()) {
1164 			format_index = cnt;
1165 			break;
1166 		}
1167 		cnt++;
1168 	}
1169 	return load_internal(path, true, format_index, create_args);
1170 }
1171 
1172 
1173 //-------------------------------------------------
1174 //  reset_and_load - called internally when we try
1175 //  to load an is_reset_on_load() item; will reset
1176 //  the emulation and record this image to be loaded
1177 //-------------------------------------------------
1178 
reset_and_load(const std::string & path)1179 void device_image_interface::reset_and_load(const std::string &path)
1180 {
1181 	// first make sure the reset is scheduled
1182 	device().machine().schedule_hard_reset();
1183 
1184 	// and record the new load
1185 	device().machine().options().image_option(instance_name()).specify(path);
1186 
1187 	// record that we're reset and loading
1188 	m_is_reset_and_loading = true;
1189 }
1190 
1191 
1192 //-------------------------------------------------
1193 //  clear - clear all internal data pertaining
1194 //  to an image
1195 //-------------------------------------------------
1196 
clear()1197 void device_image_interface::clear()
1198 {
1199 	m_mame_file.reset();
1200 	m_file.reset();
1201 
1202 	m_image_name.clear();
1203 	m_readonly = false;
1204 	m_created = false;
1205 	m_create_format = 0;
1206 	m_create_args = nullptr;
1207 
1208 	m_longname.clear();
1209 	m_manufacturer.clear();
1210 	m_year.clear();
1211 	m_basename.clear();
1212 	m_basename_noext.clear();
1213 	m_filetype.clear();
1214 
1215 	m_full_software_name.clear();
1216 	m_software_part_ptr = nullptr;
1217 	m_software_list_name.clear();
1218 }
1219 
1220 
1221 //-------------------------------------------------
1222 //  unload - main call to unload an image
1223 //-------------------------------------------------
1224 
unload()1225 void device_image_interface::unload()
1226 {
1227 	if (is_loaded() || loaded_through_softlist())
1228 	{
1229 		call_unload();
1230 	}
1231 	clear();
1232 	clear_error();
1233 }
1234 
1235 
1236 //-------------------------------------------------
1237 //  create_option_guide
1238 //-------------------------------------------------
1239 
OPTION_GUIDE_START(null_option_guide)1240 OPTION_GUIDE_START(null_option_guide)
1241 OPTION_GUIDE_END
1242 
1243 const util::option_guide &device_image_interface::create_option_guide() const
1244 {
1245 	return null_option_guide;
1246 }
1247 
1248 //-------------------------------------------------
1249 //  update_names - update brief and instance names
1250 //-------------------------------------------------
1251 
update_names()1252 void device_image_interface::update_names()
1253 {
1254 	const char *inst_name = custom_instance_name();
1255 	const char *brief_name = custom_brief_instance_name();
1256 	if (inst_name == nullptr)
1257 		inst_name = device_typename(image_type());
1258 	if (brief_name == nullptr)
1259 		brief_name = device_brieftypename(image_type());
1260 
1261 	// count instances of the general image type, or device type if custom
1262 	int count = 0;
1263 	int index = -1;
1264 	for (const device_image_interface &image : image_interface_iterator(device().mconfig().root_device()))
1265 	{
1266 		if (this == &image)
1267 			index = count;
1268 		const char *other_name = image.custom_instance_name();
1269 		if (!other_name)
1270 			other_name = device_typename(image.image_type());
1271 
1272 		if (other_name == inst_name || !strcmp(other_name, inst_name))
1273 			count++;
1274 	}
1275 
1276 	m_canonical_instance_name = string_format("%s%d", inst_name, index + 1);
1277 	if (count > 1)
1278 	{
1279 		m_instance_name = m_canonical_instance_name;
1280 		m_brief_instance_name = string_format("%s%d", brief_name, index + 1);
1281 	}
1282 	else
1283 	{
1284 		m_instance_name = inst_name;
1285 		m_brief_instance_name = brief_name;
1286 	}
1287 }
1288 
1289 //-------------------------------------------------
1290 //  find_software_item
1291 //-------------------------------------------------
1292 
find_software_item(const std::string & identifier,bool restrict_to_interface,software_list_device ** dev) const1293 const software_part *device_image_interface::find_software_item(const std::string &identifier, bool restrict_to_interface, software_list_device **dev) const
1294 {
1295 	// split full software name into software list name and short software name
1296 	std::string list_name, software_name, part_name;
1297 	if (!software_name_parse(identifier, &list_name, &software_name, &part_name))
1298 		return nullptr;
1299 
1300 	// determine interface
1301 	const char *interface = restrict_to_interface
1302 		? image_interface()
1303 		: nullptr;
1304 
1305 	// find the software list if explicitly specified
1306 	for (software_list_device &swlistdev : software_list_device_iterator(device().mconfig().root_device()))
1307 	{
1308 		if (list_name.empty() || (list_name == swlistdev.list_name()))
1309 		{
1310 			const software_info *info = swlistdev.find(software_name);
1311 			if (info != nullptr)
1312 			{
1313 				const software_part *part = info->find_part(part_name, interface);
1314 				if (part != nullptr)
1315 				{
1316 					if (dev != nullptr)
1317 						*dev = &swlistdev;
1318 					return part;
1319 				}
1320 			}
1321 		}
1322 
1323 		if (software_name == swlistdev.list_name())
1324 		{
1325 			// ad hoc handling for the case path = swlist_name:swinfo_name (e.g.
1326 			// gameboy:sml) which is not handled properly by software_name_split
1327 			// since the function cannot distinguish between this and the case
1328 			// path = swinfo_name:swpart_name
1329 			const software_info *info = swlistdev.find(part_name);
1330 			if (info != nullptr)
1331 			{
1332 				const software_part *part = info->find_part("", interface);
1333 				if (part != nullptr)
1334 				{
1335 					if (dev != nullptr)
1336 						*dev = &swlistdev;
1337 					return part;
1338 				}
1339 			}
1340 		}
1341 	}
1342 
1343 	// if explicitly specified and not found, just error here
1344 	if (dev != nullptr)
1345 		*dev = nullptr;
1346 	return nullptr;
1347 }
1348 
1349 
1350 //-------------------------------------------------
1351 //  get_software_list_loader
1352 //-------------------------------------------------
1353 
get_software_list_loader() const1354 const software_list_loader &device_image_interface::get_software_list_loader() const
1355 {
1356 	return false_software_list_loader::instance();
1357 }
1358 
1359 
1360 //-------------------------------------------------
1361 //  load_software_part
1362 //
1363 //  Load a software part for a device. The part to
1364 //  load is determined by the "path", software lists
1365 //  configured for a driver, and the interface
1366 //  supported by the device.
1367 //
1368 //  returns true if the software could be loaded,
1369 //  false otherwise. If the software could be loaded
1370 //  sw_info and sw_part are also set.
1371 //-------------------------------------------------
1372 
load_software_part(const std::string & identifier)1373 bool device_image_interface::load_software_part(const std::string &identifier)
1374 {
1375 	// if no match has been found, we suggest similar shortnames
1376 	software_list_device *swlist;
1377 	m_software_part_ptr = find_software_item(identifier, true, &swlist);
1378 	if (m_software_part_ptr == nullptr)
1379 	{
1380 		software_list_device::display_matches(device().machine().config(), image_interface(), identifier);
1381 		return false;
1382 	}
1383 
1384 	// Load the software part
1385 	const char *swname = m_software_part_ptr->info().shortname().c_str();
1386 	const rom_entry *start_entry = m_software_part_ptr->romdata().data();
1387 	const software_list_loader &loader = get_software_list_loader();
1388 	bool result = loader.load_software(*this, *swlist, swname, start_entry);
1389 
1390 	// check compatibility
1391 	switch (swlist->is_compatible(*m_software_part_ptr))
1392 	{
1393 		case SOFTWARE_IS_COMPATIBLE:
1394 			break;
1395 
1396 		case SOFTWARE_IS_INCOMPATIBLE:
1397 			swlist->popmessage("WARNING! the set %s might not work on this system due to incompatible filter(s) '%s'\n", m_software_part_ptr->info().shortname(), swlist->filter());
1398 			break;
1399 
1400 		case SOFTWARE_NOT_COMPATIBLE:
1401 			swlist->popmessage("WARNING! the set %s might not work on this system due to missing filter(s) '%s'\n", m_software_part_ptr->info().shortname(), swlist->filter());
1402 			break;
1403 	}
1404 
1405 	// check requirements and load those images
1406 	const char *requirement = m_software_part_ptr->feature("requirement");
1407 	if (requirement != nullptr)
1408 	{
1409 		const software_part *req_swpart = find_software_item(requirement, false);
1410 		if (req_swpart != nullptr)
1411 		{
1412 			device_image_interface *req_image = software_list_device::find_mountable_image(device().mconfig(), *req_swpart);
1413 			if (req_image != nullptr)
1414 				req_image->load_software(requirement);
1415 		}
1416 	}
1417 
1418 	m_software_list_name = swlist->list_name();
1419 	return result;
1420 }
1421 
1422 //-------------------------------------------------
1423 //  software_get_default_slot
1424 //-------------------------------------------------
1425 
software_get_default_slot(const char * default_card_slot) const1426 std::string device_image_interface::software_get_default_slot(const char *default_card_slot) const
1427 {
1428 	std::string result;
1429 
1430 	const std::string &image_name(device().mconfig().options().image_option(instance_name()).value());
1431 	if (!image_name.empty())
1432 	{
1433 		result.assign(default_card_slot);
1434 		const software_part *swpart = find_software_item(image_name, true);
1435 		if (swpart != nullptr)
1436 		{
1437 			const char *slot = swpart->feature("slot");
1438 			if (slot != nullptr)
1439 				result.assign(slot);
1440 		}
1441 	}
1442 	return result;
1443 }
1444 
1445 
1446 //-------------------------------------------------
1447 //  init_phase
1448 //-------------------------------------------------
1449 
init_phase() const1450 bool device_image_interface::init_phase() const
1451 {
1452 	// diimage.cpp has quite a bit of logic that randomly decides to behave
1453 	// differently at startup; this is an enc[r]apsulation of the "logic"
1454 	// that switches these behaviors
1455 	return !device().has_running_machine()
1456 		|| device().machine().phase() == machine_phase::INIT;
1457 }
1458 
1459 
1460 //----------------------------------------------------------------------------
1461 
image_fseek_thunk(void * file,s64 offset,int whence)1462 static int image_fseek_thunk(void *file, s64 offset, int whence)
1463 {
1464 	device_image_interface *image = (device_image_interface *) file;
1465 	return image->fseek(offset, whence);
1466 }
1467 
image_fread_thunk(void * file,void * buffer,size_t length)1468 static size_t image_fread_thunk(void *file, void *buffer, size_t length)
1469 {
1470 	device_image_interface *image = (device_image_interface *) file;
1471 	return image->fread(buffer, length);
1472 }
1473 
image_fwrite_thunk(void * file,const void * buffer,size_t length)1474 static size_t image_fwrite_thunk(void *file, const void *buffer, size_t length)
1475 {
1476 	device_image_interface *image = (device_image_interface *) file;
1477 	return image->fwrite(buffer, length);
1478 }
1479 
image_fsize_thunk(void * file)1480 static u64 image_fsize_thunk(void *file)
1481 {
1482 	device_image_interface *image = (device_image_interface *) file;
1483 	return image->length();
1484 }
1485 
1486 //----------------------------------------------------------------------------
1487 
1488 struct io_procs image_ioprocs =
1489 {
1490 	nullptr,
1491 	image_fseek_thunk,
1492 	image_fread_thunk,
1493 	image_fwrite_thunk,
1494 	image_fsize_thunk
1495 };
1496