1 // license:BSD-3-Clause
2 // copyright-holders:Nicola Salmoria,Paul Priest,Aaron Giles,Vas Crabb
3 /*********************************************************************
4 
5     romload.cpp
6 
7     ROM loading functions.
8 
9 *********************************************************************/
10 
11 #include "emu.h"
12 #include "romload.h"
13 
14 #include "emuopts.h"
15 #include "drivenum.h"
16 #include "softlist_dev.h"
17 #include "ui/uimain.h"
18 
19 #include <algorithm>
20 #include <set>
21 
22 
23 #define LOG_LOAD 0
24 #define LOG(...) do { if (LOG_LOAD) debugload(__VA_ARGS__); } while(0)
25 
26 
27 /***************************************************************************
28     CONSTANTS
29 ***************************************************************************/
30 
31 #define TEMPBUFFER_MAX_SIZE     (1024 * 1024 * 1024)
32 
33 /***************************************************************************
34     HELPERS
35 ****************************************************************************/
36 
37 namespace {
38 
next_parent_system(game_driver const & system)39 auto next_parent_system(game_driver const &system)
40 {
41 	return
42 			[sys = &system, roms = std::vector<rom_entry>()] () mutable -> rom_entry const *
43 			{
44 				if (!sys)
45 					return nullptr;
46 				int const parent(driver_list::find(sys->parent));
47 				if (0 > parent)
48 				{
49 					sys = nullptr;
50 					return nullptr;
51 				}
52 				else
53 				{
54 					sys = &driver_list::driver(parent);
55 					roms = rom_build_entries(sys->rom);
56 					return &roms[0];
57 				}
58 			};
59 }
60 
61 
next_parent_software(std::vector<software_info const * > const & parents)62 auto next_parent_software(std::vector<software_info const *> const &parents)
63 {
64 	auto part(parents.front()->parts().end());
65 	return
66 			[&parents, current = parents.cbegin(), part, end = part] () mutable -> const rom_entry *
67 			{
68 				if (part == end)
69 				{
70 					if (parents.end() == current)
71 						return nullptr;
72 					part = (*current)->parts().cbegin();
73 					end = (*current)->parts().cend();
74 					do { ++current; } while ((parents.cend() != current) && (*current)->parts().empty());
75 				}
76 				return &(*part++).romdata()[0];
77 			};
78 }
79 
80 
make_software_searchpath(software_list_device & swlist,software_info const & swinfo,std::vector<software_info const * > & parents)81 std::vector<std::string> make_software_searchpath(software_list_device &swlist, software_info const &swinfo, std::vector<software_info const *> &parents)
82 {
83 	std::vector<std::string> result;
84 
85 	// search <rompath>/<list>/<software> following parents
86 	for (software_info const *i = &swinfo; i; )
87 	{
88 		if (std::find(parents.begin(), parents.end(), i) != parents.end())
89 			break;
90 		parents.emplace_back(i);
91 		result.emplace_back(util::string_format("%s" PATH_SEPARATOR "%s", swlist.list_name(), i->shortname()));
92 		i = i->parentname().empty() ? nullptr : swlist.find(i->parentname());
93 	}
94 
95 	// search <rompath>/<software> following parents
96 	for (software_info const *i : parents)
97 		result.emplace_back(i->shortname());
98 
99 	return result;
100 }
101 
102 
do_open_disk(const emu_options & options,std::initializer_list<std::reference_wrapper<const std::vector<std::string>>> searchpath,const rom_entry * romp,chd_file & chd,std::function<const rom_entry * ()> next_parent)103 chd_error do_open_disk(const emu_options &options, std::initializer_list<std::reference_wrapper<const std::vector<std::string> > > searchpath, const rom_entry *romp, chd_file &chd, std::function<const rom_entry * ()> next_parent)
104 {
105 	// hashes are fixed, but we might need to try multiple filenames
106 	std::set<std::string> tried;
107 	const util::hash_collection hashes(ROM_GETHASHDATA(romp));
108 	std::string filename, fullpath;
109 	const rom_entry *parent(nullptr);
110 	chd_error result(CHDERR_FILE_NOT_FOUND);
111 	while (romp && (CHDERR_NONE != result))
112 	{
113 		filename = ROM_GETNAME(romp);
114 		filename.append(".chd");
115 		if (tried.insert(filename).second)
116 		{
117 			// piggyback on emu_file to find the disk image file
118 			std::unique_ptr<emu_file> imgfile;
119 			for (const std::vector<std::string> &paths : searchpath)
120 			{
121 				imgfile.reset(new emu_file(options.media_path(), paths, OPEN_FLAG_READ));
122 				imgfile->set_restrict_to_mediapath(1);
123 				const osd_file::error filerr(imgfile->open(filename, OPEN_FLAG_READ));
124 				if (osd_file::error::NONE == filerr)
125 					break;
126 				else
127 					imgfile.reset();
128 			}
129 
130 			// if we couldn't open a candidate file, report an error; otherwise reopen it as a CHD
131 			if (imgfile)
132 			{
133 				fullpath = imgfile->fullpath();
134 				imgfile.reset();
135 				result = chd.open(fullpath.c_str());
136 			}
137 		}
138 
139 		// walk the parents looking for a CHD with the same hashes but a different name
140 		if (CHDERR_NONE != result)
141 		{
142 			while (romp)
143 			{
144 				// find a file in a disk region
145 				if (parent)
146 					romp = rom_next_file(romp);
147 				while (!parent || !romp)
148 				{
149 					if (!parent)
150 					{
151 						parent = next_parent();
152 						if (!parent)
153 						{
154 							romp = nullptr;
155 							break;
156 						}
157 						while (ROMENTRY_ISPARAMETER(parent) || ROMENTRY_ISSYSTEM_BIOS(parent) || ROMENTRY_ISDEFAULT_BIOS(parent))
158 							++parent;
159 						if (ROMENTRY_ISEND(parent))
160 							parent = nullptr;
161 					}
162 					else
163 					{
164 						parent = rom_next_region(parent);
165 					}
166 					while (parent && !ROMREGION_ISDISKDATA(parent))
167 						parent = rom_next_region(parent);
168 					if (parent)
169 						romp = rom_first_file(parent);
170 				}
171 
172 				// try it if it matches the hashes
173 				if (romp && (util::hash_collection(ROM_GETHASHDATA(romp)) == hashes))
174 					break;
175 			}
176 		}
177 	}
178 	return result;
179 }
180 
181 } // anonymous namespace
182 
183 
184 /***************************************************************************
185     ROM LOADING
186 ***************************************************************************/
187 
188 /*-------------------------------------------------
189     rom_first_region - return pointer to first ROM
190     region
191 -------------------------------------------------*/
192 
rom_first_region(const device_t & device)193 const rom_entry *rom_first_region(const device_t &device)
194 {
195 	return rom_first_region(&device.rom_region_vector().front());
196 }
197 
rom_first_region(const rom_entry * romp)198 const rom_entry *rom_first_region(const rom_entry *romp)
199 {
200 	while (ROMENTRY_ISPARAMETER(romp) || ROMENTRY_ISSYSTEM_BIOS(romp) || ROMENTRY_ISDEFAULT_BIOS(romp))
201 		romp++;
202 	return !ROMENTRY_ISEND(romp) ? romp : nullptr;
203 }
204 
205 
206 /*-------------------------------------------------
207     rom_next_region - return pointer to next ROM
208     region
209 -------------------------------------------------*/
210 
rom_next_region(const rom_entry * romp)211 const rom_entry *rom_next_region(const rom_entry *romp)
212 {
213 	romp++;
214 	while (!ROMENTRY_ISREGIONEND(romp))
215 		romp++;
216 	while (ROMENTRY_ISPARAMETER(romp))
217 		romp++;
218 	return ROMENTRY_ISEND(romp) ? nullptr : romp;
219 }
220 
221 
222 /*-------------------------------------------------
223     rom_first_file - return pointer to first ROM
224     file
225 -------------------------------------------------*/
226 
rom_first_file(const rom_entry * romp)227 const rom_entry *rom_first_file(const rom_entry *romp)
228 {
229 	romp++;
230 	while (!ROMENTRY_ISFILE(romp) && !ROMENTRY_ISREGIONEND(romp))
231 		romp++;
232 	return ROMENTRY_ISREGIONEND(romp) ? nullptr : romp;
233 }
234 
235 
236 /*-------------------------------------------------
237     rom_next_file - return pointer to next ROM
238     file
239 -------------------------------------------------*/
240 
rom_next_file(const rom_entry * romp)241 const rom_entry *rom_next_file(const rom_entry *romp)
242 {
243 	romp++;
244 	while (!ROMENTRY_ISFILE(romp) && !ROMENTRY_ISREGIONEND(romp))
245 		romp++;
246 	return ROMENTRY_ISREGIONEND(romp) ? nullptr : romp;
247 }
248 
249 
250 /*-------------------------------------------------
251     rom_first_parameter - return pointer to the first
252     per-game parameter
253 -------------------------------------------------*/
254 
rom_first_parameter(const device_t & device)255 const rom_entry *rom_first_parameter(const device_t &device)
256 {
257 	const rom_entry *romp = &device.rom_region_vector().front();
258 	while (romp && !ROMENTRY_ISEND(romp) && !ROMENTRY_ISPARAMETER(romp))
259 		romp++;
260 	return (romp != nullptr && !ROMENTRY_ISEND(romp)) ? romp : nullptr;
261 }
262 
263 
264 /*-------------------------------------------------
265     rom_next_parameter - return pointer to the next
266     per-game parameter
267 -------------------------------------------------*/
268 
rom_next_parameter(const rom_entry * romp)269 const rom_entry *rom_next_parameter(const rom_entry *romp)
270 {
271 	romp++;
272 	while (!ROMENTRY_ISREGIONEND(romp) && !ROMENTRY_ISPARAMETER(romp))
273 		romp++;
274 	return ROMENTRY_ISEND(romp) ? nullptr : romp;
275 }
276 
277 
278 /*-------------------------------------------------
279     rom_file_size - return the expected size of a
280     file given the ROM description
281 -------------------------------------------------*/
282 
rom_file_size(const rom_entry * romp)283 u32 rom_file_size(const rom_entry *romp)
284 {
285 	u32 maxlength = 0;
286 
287 	/* loop until we run out of reloads */
288 	do
289 	{
290 		/* loop until we run out of continues/ignores */
291 		u32 curlength = ROM_GETLENGTH(romp++);
292 		while (ROMENTRY_ISCONTINUE(romp) || ROMENTRY_ISIGNORE(romp))
293 			curlength += ROM_GETLENGTH(romp++);
294 
295 		/* track the maximum length */
296 		maxlength = std::max(maxlength, curlength);
297 	}
298 	while (ROMENTRY_ISRELOAD(romp));
299 
300 	return maxlength;
301 }
302 
303 
304 /*-------------------------------------------------
305     debugload - log data to a file
306 -------------------------------------------------*/
307 
debugload(const char * string,...)308 static void CLIB_DECL ATTR_PRINTF(1,2) debugload(const char *string, ...)
309 {
310 	static int opened;
311 	va_list arg;
312 	FILE *f;
313 
314 	f = fopen("romload.log", opened++ ? "a" : "w");
315 	if (f)
316 	{
317 		va_start(arg, string);
318 		vfprintf(f, string, arg);
319 		va_end(arg);
320 		fclose(f);
321 	}
322 }
323 
324 
325 /***************************************************************************
326     HARD DISK HANDLING
327 ***************************************************************************/
328 
329 /*-------------------------------------------------
330     get_disk_handle - return a pointer to the
331     CHD file associated with the given region
332 -------------------------------------------------*/
333 
get_disk_handle(const char * region)334 chd_file *rom_load_manager::get_disk_handle(const char *region)
335 {
336 	for (auto &curdisk : m_chd_list)
337 		if (strcmp(curdisk->region(), region) == 0)
338 			return &curdisk->chd();
339 	return nullptr;
340 }
341 
342 
343 /*-------------------------------------------------
344     set_disk_handle - set a pointer to the CHD
345     file associated with the given region
346 -------------------------------------------------*/
347 
set_disk_handle(const char * region,const char * fullpath)348 int rom_load_manager::set_disk_handle(const char *region, const char *fullpath)
349 {
350 	auto chd = std::make_unique<open_chd>(region);
351 	auto err = chd->orig_chd().open(fullpath);
352 	if (err == CHDERR_NONE)
353 		m_chd_list.push_back(std::move(chd));
354 	return err;
355 }
356 
357 /*-------------------------------------------------
358     determine_bios_rom - determine system_bios
359     from SystemBios structure and OPTION_BIOS
360 -------------------------------------------------*/
361 
determine_bios_rom(device_t & device,const char * specbios)362 void rom_load_manager::determine_bios_rom(device_t &device, const char *specbios)
363 {
364 	// default is applied by the device at config complete time
365 	if (specbios && *specbios && core_stricmp(specbios, "default"))
366 	{
367 		bool found(false);
368 		for (const rom_entry &rom : device.rom_region_vector())
369 		{
370 			if (ROMENTRY_ISSYSTEM_BIOS(&rom))
371 			{
372 				char const *const biosname = ROM_GETNAME(&rom);
373 				int const bios_flags = ROM_GETBIOSFLAGS(&rom);
374 				char bios_number[20];
375 
376 				// Allow '-bios n' to still be used
377 				sprintf(bios_number, "%d", bios_flags - 1);
378 				if (!core_stricmp(bios_number, specbios) || !core_stricmp(biosname, specbios))
379 				{
380 					found = true;
381 					device.set_system_bios(bios_flags);
382 					break;
383 				}
384 			}
385 		}
386 
387 		// if we got neither an empty string nor 'default' then warn the user
388 		if (!found)
389 		{
390 			m_errorstring.append(util::string_format("%s: invalid BIOS \"%s\", reverting to default\n", device.tag(), specbios));
391 			m_warnings++;
392 		}
393 	}
394 
395 	// log final result
396 	LOG("For \"%s\" using System BIOS: %d\n", device.tag(), device.system_bios());
397 }
398 
399 
400 /*-------------------------------------------------
401     count_roms - counts the total number of ROMs
402     that will need to be loaded
403 -------------------------------------------------*/
404 
count_roms()405 void rom_load_manager::count_roms()
406 {
407 	const rom_entry *region, *rom;
408 
409 	/* start with 0 */
410 	m_romstotal = 0;
411 	m_romstotalsize = 0;
412 
413 	/* loop over regions, then over files */
414 	for (device_t &device : device_iterator(machine().config().root_device()))
415 		for (region = rom_first_region(device); region != nullptr; region = rom_next_region(region))
416 			for (rom = rom_first_file(region); rom != nullptr; rom = rom_next_file(rom))
417 				if (ROM_GETBIOSFLAGS(rom) == 0 || ROM_GETBIOSFLAGS(rom) == device.system_bios())
418 				{
419 					m_romstotal++;
420 					m_romstotalsize += rom_file_size(rom);
421 				}
422 }
423 
424 
425 /*-------------------------------------------------
426     fill_random - fills an area of memory with
427     random data
428 -------------------------------------------------*/
429 
fill_random(u8 * base,u32 length)430 void rom_load_manager::fill_random(u8 *base, u32 length)
431 {
432 	while (length--)
433 		*base++ = machine().rand();
434 }
435 
436 
437 /*-------------------------------------------------
438     handle_missing_file - handles error generation
439     for missing files
440 -------------------------------------------------*/
441 
handle_missing_file(const rom_entry * romp,const std::vector<std::string> & tried_file_names,chd_error chderr)442 void rom_load_manager::handle_missing_file(const rom_entry *romp, const std::vector<std::string> &tried_file_names, chd_error chderr)
443 {
444 	std::string tried;
445 	if (!tried_file_names.empty())
446 	{
447 		tried = " (tried in";
448 		for (const std::string &path : tried_file_names)
449 		{
450 			tried += ' ';
451 			tried += path;
452 		}
453 		tried += ')';
454 	}
455 
456 	std::string name(ROM_GETNAME(romp));
457 
458 	const bool is_chd(chderr != CHDERR_NONE);
459 	if (is_chd)
460 		name += ".chd";
461 
462 	const bool is_chd_error(is_chd && chderr != CHDERR_FILE_NOT_FOUND);
463 	if (is_chd_error)
464 		m_errorstring.append(string_format("%s CHD ERROR: %s\n", name.c_str(), chd_file::error_string(chderr)));
465 
466 	if (ROM_ISOPTIONAL(romp))
467 	{
468 		// optional files are okay
469 		if (!is_chd_error)
470 			m_errorstring.append(string_format("OPTIONAL %s NOT FOUND%s\n", name, tried));
471 		m_warnings++;
472 	}
473 	else if (util::hash_collection(ROM_GETHASHDATA(romp)).flag(util::hash_collection::FLAG_NO_DUMP))
474 	{
475 		// no good dumps are okay
476 		if (!is_chd_error)
477 			m_errorstring.append(string_format("%s NOT FOUND (NO GOOD DUMP KNOWN)%s\n", name, tried));
478 		m_knownbad++;
479 	}
480 	else
481 	{
482 		// anything else is bad
483 		if (!is_chd_error)
484 			m_errorstring.append(string_format("%s NOT FOUND%s\n", name, tried));
485 		m_errors++;
486 	}
487 }
488 
489 
490 /*-------------------------------------------------
491     dump_wrong_and_correct_checksums - dump an
492     error message containing the wrong and the
493     correct checksums for a given ROM
494 -------------------------------------------------*/
495 
dump_wrong_and_correct_checksums(const util::hash_collection & hashes,const util::hash_collection & acthashes)496 void rom_load_manager::dump_wrong_and_correct_checksums(const util::hash_collection &hashes, const util::hash_collection &acthashes)
497 {
498 	m_errorstring.append(string_format("    EXPECTED: %s\n", hashes.macro_string().c_str()));
499 	m_errorstring.append(string_format("       FOUND: %s\n", acthashes.macro_string().c_str()));
500 }
501 
502 
503 /*-------------------------------------------------
504     verify_length_and_hash - verify the length
505     and hash signatures of a file
506 -------------------------------------------------*/
507 
verify_length_and_hash(emu_file * file,const char * name,u32 explength,const util::hash_collection & hashes)508 void rom_load_manager::verify_length_and_hash(emu_file *file, const char *name, u32 explength, const util::hash_collection &hashes)
509 {
510 	// we've already complained if there is no file
511 	if (!file)
512 		return;
513 
514 	// verify length
515 	u64 const actlength = file->size();
516 	if (explength != actlength)
517 	{
518 		m_errorstring.append(string_format("%s WRONG LENGTH (expected: %08x found: %08x)\n", name, explength, actlength));
519 		m_warnings++;
520 	}
521 
522 	if (hashes.flag(util::hash_collection::FLAG_NO_DUMP))
523 	{
524 		// If there is no good dump known, write it
525 		m_errorstring.append(string_format("%s NO GOOD DUMP KNOWN\n", name));
526 		m_knownbad++;
527 	}
528 	else
529 	{
530 		// verify checksums
531 		util::hash_collection const &acthashes = file->hashes(hashes.hash_types().c_str());
532 		if (hashes != acthashes)
533 		{
534 			// otherwise, it's just bad
535 			util::hash_collection const &all_acthashes = (acthashes.hash_types() == util::hash_collection::HASH_TYPES_ALL)
536 					? acthashes
537 					: file->hashes(util::hash_collection::HASH_TYPES_ALL);
538 			m_errorstring.append(string_format("%s WRONG CHECKSUMS:\n", name));
539 			dump_wrong_and_correct_checksums(hashes, all_acthashes);
540 			m_warnings++;
541 		}
542 		else if (hashes.flag(util::hash_collection::FLAG_BAD_DUMP))
543 		{
544 			// If it matches, but it is actually a bad dump, write it
545 			m_errorstring.append(string_format("%s ROM NEEDS REDUMP\n", name));
546 			m_knownbad++;
547 		}
548 	}
549 }
550 
551 
552 /*-------------------------------------------------
553     display_loading_rom_message - display
554     messages about ROM loading to the user
555 -------------------------------------------------*/
556 
display_loading_rom_message(const char * name,bool from_list)557 void rom_load_manager::display_loading_rom_message(const char *name, bool from_list)
558 {
559 	std::string buffer;
560 	if (name)
561 		buffer = util::string_format("%s (%d%%)", from_list ? "Loading Software" : "Loading Machine", u32(100 * m_romsloadedsize / m_romstotalsize));
562 	else
563 		buffer = "Loading Complete";
564 
565 	if (!machine().ui().is_menu_active())
566 		machine().ui().set_startup_text(buffer.c_str(), false);
567 }
568 
569 
570 /*-------------------------------------------------
571     display_rom_load_results - display the final
572     results of ROM loading
573 -------------------------------------------------*/
574 
display_rom_load_results(bool from_list)575 void rom_load_manager::display_rom_load_results(bool from_list)
576 {
577 	/* final status display */
578 	display_loading_rom_message(nullptr, from_list);
579 
580 	/* if we had errors, they are fatal */
581 	if (m_errors != 0)
582 	{
583 		/* create the error message and exit fatally */
584 		osd_printf_error("%s", m_errorstring);
585 		throw emu_fatalerror(EMU_ERR_MISSING_FILES, "Required files are missing, the machine cannot be run.");
586 	}
587 
588 	/* if we had warnings, output them, but continue */
589 	if ((m_warnings) || (m_knownbad))
590 	{
591 		m_errorstring.append("WARNING: the machine might not run correctly.");
592 		osd_printf_warning("%s\n", m_errorstring);
593 	}
594 }
595 
596 
597 /*-------------------------------------------------
598     region_post_process - post-process a region,
599     byte swapping and inverting data as necessary
600 -------------------------------------------------*/
601 
region_post_process(memory_region * region,bool invert)602 void rom_load_manager::region_post_process(memory_region *region, bool invert)
603 {
604 	// do nothing if no region
605 	if (region == nullptr)
606 		return;
607 
608 	LOG("+ datawidth=%dbit endian=%s\n", region->bitwidth(),
609 			region->endianness() == ENDIANNESS_LITTLE ? "little" : "big");
610 
611 	/* if the region is inverted, do that now */
612 	if (invert)
613 	{
614 		LOG("+ Inverting region\n");
615 		u8 *base = region->base();
616 		for (int i = 0; i < region->bytes(); i++)
617 			*base++ ^= 0xff;
618 	}
619 
620 	/* swap the endianness if we need to */
621 	if (region->bytewidth() > 1 && region->endianness() != ENDIANNESS_NATIVE)
622 	{
623 		LOG("+ Byte swapping region\n");
624 		int datawidth = region->bytewidth();
625 		u8 *base = region->base();
626 		for (int i = 0; i < region->bytes(); i += datawidth)
627 		{
628 			u8 temp[8];
629 			memcpy(temp, base, datawidth);
630 			for (int j = datawidth - 1; j >= 0; j--)
631 				*base++ = temp[j];
632 		}
633 	}
634 }
635 
636 
637 /*-------------------------------------------------
638     open_rom_file - open a ROM file, searching
639     up the parent and loading by checksum
640 -------------------------------------------------*/
641 
open_rom_file(std::initializer_list<std::reference_wrapper<const std::vector<std::string>>> searchpath,const rom_entry * romp,std::vector<std::string> & tried_file_names,bool from_list)642 std::unique_ptr<emu_file> rom_load_manager::open_rom_file(std::initializer_list<std::reference_wrapper<const std::vector<std::string> > > searchpath, const rom_entry *romp, std::vector<std::string> &tried_file_names, bool from_list)
643 {
644 	osd_file::error filerr = osd_file::error::NOT_FOUND;
645 	u32 const romsize = rom_file_size(romp);
646 	tried_file_names.clear();
647 
648 	// update status display
649 	display_loading_rom_message(ROM_GETNAME(romp), from_list);
650 
651 	// extract CRC to use for searching
652 	u32 crc = 0;
653 	bool const has_crc = util::hash_collection(ROM_GETHASHDATA(romp)).crc(crc);
654 
655 	// attempt reading up the chain through the parents
656 	// it also automatically attempts any kind of load by checksum supported by the archives.
657 	std::unique_ptr<emu_file> result;
658 	for (const std::vector<std::string> &paths : searchpath)
659 	{
660 		result = open_rom_file(paths, tried_file_names, has_crc, crc, ROM_GETNAME(romp), filerr);
661 		if (result)
662 			break;
663 	}
664 
665 	// update counters
666 	m_romsloaded++;
667 	m_romsloadedsize += romsize;
668 
669 	// return the result
670 	if (osd_file::error::NONE != filerr)
671 		return nullptr;
672 	else
673 		return result;
674 }
675 
676 
open_rom_file(const std::vector<std::string> & paths,std::vector<std::string> & tried,bool has_crc,u32 crc,const std::string & name,osd_file::error & filerr)677 std::unique_ptr<emu_file> rom_load_manager::open_rom_file(const std::vector<std::string> &paths, std::vector<std::string> &tried, bool has_crc, u32 crc, const std::string &name, osd_file::error &filerr)
678 {
679 	// record the set names we search
680 	tried.insert(tried.end(), paths.begin(), paths.end());
681 
682 	// attempt to open the file
683 	std::unique_ptr<emu_file> result(new emu_file(machine().options().media_path(), paths, OPEN_FLAG_READ));
684 	result->set_restrict_to_mediapath(1);
685 	if (has_crc)
686 		filerr = result->open(name, crc);
687 	else
688 		filerr = result->open(name);
689 
690 	// don't return anything if unsuccessful
691 	if (osd_file::error::NONE != filerr)
692 		return nullptr;
693 	else
694 		return result;
695 }
696 
697 
698 /*-------------------------------------------------
699     rom_fread - cheesy fread that fills with
700     random data for a nullptr file
701 -------------------------------------------------*/
702 
rom_fread(emu_file * file,u8 * buffer,int length,const rom_entry * parent_region)703 int rom_load_manager::rom_fread(emu_file *file, u8 *buffer, int length, const rom_entry *parent_region)
704 {
705 	if (file) // files just pass through
706 		return file->read(buffer, length);
707 
708 	if (!ROMREGION_ISERASE(parent_region)) // otherwise, fill with randomness unless it was already specifically erased
709 		fill_random(buffer, length);
710 
711 	return length;
712 }
713 
714 
715 /*-------------------------------------------------
716     read_rom_data - read ROM data for a single
717     entry
718 -------------------------------------------------*/
719 
read_rom_data(emu_file * file,const rom_entry * parent_region,const rom_entry * romp)720 int rom_load_manager::read_rom_data(emu_file *file, const rom_entry *parent_region, const rom_entry *romp)
721 {
722 	int datashift = ROM_GETBITSHIFT(romp);
723 	int datamask = ((1 << ROM_GETBITWIDTH(romp)) - 1) << datashift;
724 	int numbytes = ROM_GETLENGTH(romp);
725 	int groupsize = ROM_GETGROUPSIZE(romp);
726 	int skip = ROM_GETSKIPCOUNT(romp);
727 	int reversed = ROM_ISREVERSED(romp);
728 	int numgroups = (numbytes + groupsize - 1) / groupsize;
729 	u8 *base = m_region->base() + ROM_GETOFFSET(romp);
730 	u32 tempbufsize;
731 	int i;
732 
733 	LOG("Loading ROM data: offs=%X len=%X mask=%02X group=%d skip=%d reverse=%d\n", ROM_GETOFFSET(romp), numbytes, datamask, groupsize, skip, reversed);
734 
735 	/* make sure the length was an even multiple of the group size */
736 	if (numbytes % groupsize != 0)
737 		osd_printf_warning("Warning in RomModule definition: %s length not an even multiple of group size\n", ROM_GETNAME(romp));
738 
739 	/* make sure we only fill within the region space */
740 	if (ROM_GETOFFSET(romp) + numgroups * groupsize + (numgroups - 1) * skip > m_region->bytes())
741 		throw emu_fatalerror("Error in RomModule definition: %s out of memory region space\n", ROM_GETNAME(romp));
742 
743 	/* make sure the length was valid */
744 	if (numbytes == 0)
745 		throw emu_fatalerror("Error in RomModule definition: %s has an invalid length\n", ROM_GETNAME(romp));
746 
747 	/* special case for simple loads */
748 	if (datamask == 0xff && (groupsize == 1 || !reversed) && skip == 0)
749 		return rom_fread(file, base, numbytes, parent_region);
750 
751 	/* use a temporary buffer for complex loads */
752 	tempbufsize = std::min(TEMPBUFFER_MAX_SIZE, numbytes);
753 	std::vector<u8> tempbuf(tempbufsize);
754 
755 	/* chunky reads for complex loads */
756 	skip += groupsize;
757 	while (numbytes > 0)
758 	{
759 		int evengroupcount = (tempbufsize / groupsize) * groupsize;
760 		int bytesleft = (numbytes > evengroupcount) ? evengroupcount : numbytes;
761 		u8 *bufptr = &tempbuf[0];
762 
763 		/* read as much as we can */
764 		LOG("  Reading %X bytes into buffer\n", bytesleft);
765 		if (rom_fread(file, bufptr, bytesleft, parent_region) != bytesleft)
766 			return 0;
767 		numbytes -= bytesleft;
768 
769 		LOG("  Copying to %p\n", base);
770 
771 		/* unmasked cases */
772 		if (datamask == 0xff)
773 		{
774 			/* non-grouped data */
775 			if (groupsize == 1)
776 				for (i = 0; i < bytesleft; i++, base += skip)
777 					*base = *bufptr++;
778 
779 			/* grouped data -- non-reversed case */
780 			else if (!reversed)
781 				while (bytesleft)
782 				{
783 					for (i = 0; i < groupsize && bytesleft; i++, bytesleft--)
784 						base[i] = *bufptr++;
785 					base += skip;
786 				}
787 
788 			/* grouped data -- reversed case */
789 			else
790 				while (bytesleft)
791 				{
792 					for (i = groupsize - 1; i >= 0 && bytesleft; i--, bytesleft--)
793 						base[i] = *bufptr++;
794 					base += skip;
795 				}
796 		}
797 
798 		/* masked cases */
799 		else
800 		{
801 			/* non-grouped data */
802 			if (groupsize == 1)
803 				for (i = 0; i < bytesleft; i++, base += skip)
804 					*base = (*base & ~datamask) | ((*bufptr++ << datashift) & datamask);
805 
806 			/* grouped data -- non-reversed case */
807 			else if (!reversed)
808 				while (bytesleft)
809 				{
810 					for (i = 0; i < groupsize && bytesleft; i++, bytesleft--)
811 						base[i] = (base[i] & ~datamask) | ((*bufptr++ << datashift) & datamask);
812 					base += skip;
813 				}
814 
815 			/* grouped data -- reversed case */
816 			else
817 				while (bytesleft)
818 				{
819 					for (i = groupsize - 1; i >= 0 && bytesleft; i--, bytesleft--)
820 						base[i] = (base[i] & ~datamask) | ((*bufptr++ << datashift) & datamask);
821 					base += skip;
822 				}
823 		}
824 	}
825 
826 	LOG("  All done\n");
827 	return ROM_GETLENGTH(romp);
828 }
829 
830 
831 /*-------------------------------------------------
832     fill_rom_data - fill a region of ROM space
833 -------------------------------------------------*/
834 
fill_rom_data(const rom_entry * romp)835 void rom_load_manager::fill_rom_data(const rom_entry *romp)
836 {
837 	u32 numbytes = ROM_GETLENGTH(romp);
838 	int skip = ROM_GETSKIPCOUNT(romp);
839 	u8 *base = m_region->base() + ROM_GETOFFSET(romp);
840 
841 	// make sure we fill within the region space
842 	if (ROM_GETOFFSET(romp) + numbytes > m_region->bytes())
843 		throw emu_fatalerror("Error in RomModule definition: FILL out of memory region space\n");
844 
845 	// make sure the length was valid
846 	if (numbytes == 0)
847 		throw emu_fatalerror("Error in RomModule definition: FILL has an invalid length\n");
848 
849 	// for fill bytes, the byte that gets filled is the first byte of the hashdata string
850 	u8 fill_byte = u8(strtol(ROM_GETHASHDATA(romp), nullptr, 0));
851 
852 	// fill the data (filling value is stored in place of the hashdata)
853 	if(skip != 0)
854 	{
855 		for (int i = 0; i < numbytes; i+= skip + 1)
856 			base[i] = fill_byte;
857 	}
858 	else
859 		memset(base, fill_byte, numbytes);
860 }
861 
862 
863 /*-------------------------------------------------
864     copy_rom_data - copy a region of ROM space
865 -------------------------------------------------*/
866 
copy_rom_data(const rom_entry * romp)867 void rom_load_manager::copy_rom_data(const rom_entry *romp)
868 {
869 	u8 *base = m_region->base() + ROM_GETOFFSET(romp);
870 	const char *srcrgntag = ROM_GETNAME(romp);
871 	u32 numbytes = ROM_GETLENGTH(romp);
872 	u32 srcoffs = u32(strtol(ROM_GETHASHDATA(romp), nullptr, 0));  /* srcoffset in place of hashdata */
873 
874 	/* make sure we copy within the region space */
875 	if (ROM_GETOFFSET(romp) + numbytes > m_region->bytes())
876 		throw emu_fatalerror("Error in RomModule definition: COPY out of target memory region space\n");
877 
878 	/* make sure the length was valid */
879 	if (numbytes == 0)
880 		throw emu_fatalerror("Error in RomModule definition: COPY has an invalid length\n");
881 
882 	/* make sure the source was valid */
883 	memory_region *region = machine().root_device().memregion(srcrgntag);
884 	if (region == nullptr)
885 		throw emu_fatalerror("Error in RomModule definition: COPY from an invalid region\n");
886 
887 	/* make sure we find within the region space */
888 	if (srcoffs + numbytes > region->bytes())
889 		throw emu_fatalerror("Error in RomModule definition: COPY out of source memory region space\n");
890 
891 	/* fill the data */
892 	memcpy(base, region->base() + srcoffs, numbytes);
893 }
894 
895 
896 /*-------------------------------------------------
897     process_rom_entries - process all ROM entries
898     for a region
899 -------------------------------------------------*/
900 
process_rom_entries(std::initializer_list<std::reference_wrapper<const std::vector<std::string>>> searchpath,u8 bios,const rom_entry * parent_region,const rom_entry * romp,bool from_list)901 void rom_load_manager::process_rom_entries(std::initializer_list<std::reference_wrapper<const std::vector<std::string> > > searchpath, u8 bios, const rom_entry *parent_region, const rom_entry *romp, bool from_list)
902 {
903 	u32 lastflags = 0;
904 	std::vector<std::string> tried_file_names;
905 
906 	// loop until we hit the end of this region
907 	while (!ROMENTRY_ISREGIONEND(romp))
908 	{
909 		tried_file_names.clear();
910 
911 		if (ROMENTRY_ISCONTINUE(romp))
912 			throw emu_fatalerror("Error in RomModule definition: ROM_CONTINUE not preceded by ROM_LOAD\n");
913 
914 		if (ROMENTRY_ISIGNORE(romp))
915 			throw emu_fatalerror("Error in RomModule definition: ROM_IGNORE not preceded by ROM_LOAD\n");
916 
917 		if (ROMENTRY_ISRELOAD(romp))
918 			throw emu_fatalerror("Error in RomModule definition: ROM_RELOAD not preceded by ROM_LOAD\n");
919 
920 		if (ROMENTRY_ISFILL(romp))
921 		{
922 			if (!ROM_GETBIOSFLAGS(romp) || (ROM_GETBIOSFLAGS(romp) == bios))
923 				fill_rom_data(romp);
924 
925 			romp++;
926 		}
927 		else if (ROMENTRY_ISCOPY(romp))
928 		{
929 			copy_rom_data(romp++);
930 		}
931 		else if (ROMENTRY_ISFILE(romp))
932 		{
933 			// handle files
934 			bool const irrelevantbios = (ROM_GETBIOSFLAGS(romp) != 0) && (ROM_GETBIOSFLAGS(romp) != bios);
935 			rom_entry const *baserom = romp;
936 			int explength = 0;
937 
938 			// open the file if it is a non-BIOS or matches the current BIOS
939 			LOG("Opening ROM file: %s\n", ROM_GETNAME(romp));
940 			std::unique_ptr<emu_file> file;
941 			if (!irrelevantbios)
942 			{
943 				file = open_rom_file(searchpath, romp, tried_file_names, from_list);
944 				if (!file)
945 					handle_missing_file(romp, tried_file_names, CHDERR_NONE);
946 			}
947 
948 			// loop until we run out of reloads
949 			do
950 			{
951 				// loop until we run out of continues/ignores
952 				do
953 				{
954 					rom_entry modified_romp = *romp++;
955 					//int readresult;
956 
957 					// handle flag inheritance
958 					if (!ROM_INHERITSFLAGS(&modified_romp))
959 						lastflags = modified_romp.get_flags();
960 					else
961 						modified_romp.set_flags((modified_romp.get_flags() & ~ROM_INHERITEDFLAGS) | lastflags);
962 
963 					explength += ROM_GETLENGTH(&modified_romp);
964 
965 					// attempt to read using the modified entry
966 					if (!ROMENTRY_ISIGNORE(&modified_romp) && !irrelevantbios)
967 						/*readresult = */read_rom_data(file.get(), parent_region, &modified_romp);
968 				}
969 				while (ROMENTRY_ISCONTINUE(romp) || ROMENTRY_ISIGNORE(romp));
970 
971 				// if this was the first use of this file, verify the length and CRC
972 				if (baserom)
973 				{
974 					LOG("Verifying length (%X) and checksums\n", explength);
975 					verify_length_and_hash(file.get(), ROM_GETNAME(baserom), explength, util::hash_collection(ROM_GETHASHDATA(baserom)));
976 					LOG("Verify finished\n");
977 				}
978 
979 				// re-seek to the start and clear the baserom so we don't reverify
980 				if (file)
981 					file->seek(0, SEEK_SET);
982 				baserom = nullptr;
983 				explength = 0;
984 			}
985 			while (ROMENTRY_ISRELOAD(romp));
986 
987 			// close the file
988 			if (file)
989 			{
990 				LOG("Closing ROM file\n");
991 				file.reset();
992 			}
993 		}
994 		else
995 		{
996 			romp++; // something else - skip
997 		}
998 	}
999 }
1000 
1001 
1002 /*-------------------------------------------------
1003     open_disk_diff - open a DISK diff file
1004 -------------------------------------------------*/
1005 
open_disk_diff(emu_options & options,const rom_entry * romp,chd_file & source,chd_file & diff_chd)1006 chd_error rom_load_manager::open_disk_diff(emu_options &options, const rom_entry *romp, chd_file &source, chd_file &diff_chd)
1007 {
1008 	// TODO: use system name and/or software list name in the path - the current setup doesn't scale
1009 	std::string fname = std::string(ROM_GETNAME(romp)).append(".dif");
1010 
1011 	/* try to open the diff */
1012 	LOG("Opening differencing image file: %s\n", fname.c_str());
1013 	emu_file diff_file(options.diff_directory(), OPEN_FLAG_READ | OPEN_FLAG_WRITE);
1014 	osd_file::error filerr = diff_file.open(fname);
1015 	if (filerr == osd_file::error::NONE)
1016 	{
1017 		std::string fullpath(diff_file.fullpath());
1018 		diff_file.close();
1019 
1020 		LOG("Opening differencing image file: %s\n", fullpath.c_str());
1021 		return diff_chd.open(fullpath.c_str(), true, &source);
1022 	}
1023 
1024 	/* didn't work; try creating it instead */
1025 	LOG("Creating differencing image: %s\n", fname.c_str());
1026 	diff_file.set_openflags(OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
1027 	filerr = diff_file.open(fname);
1028 	if (filerr == osd_file::error::NONE)
1029 	{
1030 		std::string fullpath(diff_file.fullpath());
1031 		diff_file.close();
1032 
1033 		/* create the CHD */
1034 		LOG("Creating differencing image file: %s\n", fullpath.c_str());
1035 		chd_codec_type compression[4] = { CHD_CODEC_NONE };
1036 		chd_error err = diff_chd.create(fullpath.c_str(), source.logical_bytes(), source.hunk_bytes(), compression, source);
1037 		if (err != CHDERR_NONE)
1038 			return err;
1039 
1040 		return diff_chd.clone_all_metadata(source);
1041 	}
1042 
1043 	return CHDERR_FILE_NOT_FOUND;
1044 }
1045 
1046 
1047 /*-------------------------------------------------
1048     process_disk_entries - process all disk entries
1049     for a region
1050 -------------------------------------------------*/
1051 
process_disk_entries(std::initializer_list<std::reference_wrapper<const std::vector<std::string>>> searchpath,const char * regiontag,const rom_entry * romp,std::function<const rom_entry * ()> next_parent)1052 void rom_load_manager::process_disk_entries(std::initializer_list<std::reference_wrapper<const std::vector<std::string> > > searchpath, const char *regiontag, const rom_entry *romp, std::function<const rom_entry * ()> next_parent)
1053 {
1054 	/* remove existing disk entries for this region */
1055 	m_chd_list.erase(std::remove_if(m_chd_list.begin(), m_chd_list.end(),
1056 			[regiontag] (std::unique_ptr<open_chd> &chd) { return !strcmp(chd->region(), regiontag); }), m_chd_list.end());
1057 
1058 	/* loop until we hit the end of this region */
1059 	for ( ; !ROMENTRY_ISREGIONEND(romp); romp++)
1060 	{
1061 		/* handle files */
1062 		if (ROMENTRY_ISFILE(romp))
1063 		{
1064 			auto chd = std::make_unique<open_chd>(regiontag);
1065 			chd_error err;
1066 
1067 			/* make the filename of the source */
1068 			const std::string filename = std::string(ROM_GETNAME(romp)).append(".chd");
1069 
1070 			/* first open the source drive */
1071 			// FIXME: we've lost the ability to search parents here
1072 			LOG("Opening disk image: %s\n", filename.c_str());
1073 			err = do_open_disk(machine().options(), searchpath, romp, chd->orig_chd(), next_parent);
1074 			if (err != CHDERR_NONE)
1075 			{
1076 				handle_missing_file(romp, std::vector<std::string>(), err);
1077 				chd = nullptr;
1078 				continue;
1079 			}
1080 
1081 			/* get the header and extract the SHA1 */
1082 			util::hash_collection acthashes;
1083 			acthashes.add_sha1(chd->orig_chd().sha1());
1084 
1085 			/* verify the hash */
1086 			const util::hash_collection hashes(ROM_GETHASHDATA(romp));
1087 			if (hashes != acthashes)
1088 			{
1089 				m_errorstring.append(string_format("%s WRONG CHECKSUMS:\n", filename));
1090 				dump_wrong_and_correct_checksums(hashes, acthashes);
1091 				m_warnings++;
1092 			}
1093 			else if (hashes.flag(util::hash_collection::FLAG_BAD_DUMP))
1094 			{
1095 				m_errorstring.append(string_format("%s CHD NEEDS REDUMP\n", filename));
1096 				m_knownbad++;
1097 			}
1098 
1099 			/* if not read-only, make the diff file */
1100 			if (!DISK_ISREADONLY(romp))
1101 			{
1102 				/* try to open or create the diff */
1103 				err = open_disk_diff(machine().options(), romp, chd->orig_chd(), chd->diff_chd());
1104 				if (err != CHDERR_NONE)
1105 				{
1106 					m_errorstring.append(string_format("%s DIFF CHD ERROR: %s\n", filename, chd_file::error_string(err)));
1107 					m_errors++;
1108 					chd = nullptr;
1109 					continue;
1110 				}
1111 			}
1112 
1113 			/* we're okay, add to the list of disks */
1114 			LOG("Assigning to handle %d\n", DISK_GETINDEX(romp));
1115 			m_chd_list.push_back(std::move(chd));
1116 		}
1117 	}
1118 }
1119 
1120 
1121 /*-------------------------------------------------
1122     get_software_searchpath - get search path
1123     for a software list item
1124 -------------------------------------------------*/
1125 
get_software_searchpath(software_list_device & swlist,const software_info & swinfo)1126 std::vector<std::string> rom_load_manager::get_software_searchpath(software_list_device &swlist, const software_info &swinfo)
1127 {
1128 	std::vector<software_info const *> parents;
1129 	return make_software_searchpath(swlist, swinfo, parents);
1130 }
1131 
1132 
1133 /*-------------------------------------------------
1134     open_disk_image - open a disk image for a
1135     device
1136 -------------------------------------------------*/
1137 
open_disk_image(const emu_options & options,const device_t & device,const rom_entry * romp,chd_file & image_chd)1138 chd_error rom_load_manager::open_disk_image(const emu_options &options, const device_t &device, const rom_entry *romp, chd_file &image_chd)
1139 {
1140 	const std::vector<std::string> searchpath(device.searchpath());
1141 
1142 	driver_device const *const driver(dynamic_cast<driver_device const *>(&device));
1143 	std::function<const rom_entry * ()> next_parent;
1144 	if (driver)
1145 		next_parent = next_parent_system(driver->system());
1146 	else
1147 		next_parent = [] () { return nullptr; };
1148 	return do_open_disk(options, { searchpath }, romp, image_chd, std::move(next_parent));
1149 }
1150 
1151 
1152 /*-------------------------------------------------
1153     open_disk_image - open a disk image for a
1154     software item
1155 -------------------------------------------------*/
1156 
open_disk_image(const emu_options & options,software_list_device & swlist,const software_info & swinfo,const rom_entry * romp,chd_file & image_chd)1157 chd_error rom_load_manager::open_disk_image(const emu_options &options, software_list_device &swlist, const software_info &swinfo, const rom_entry *romp, chd_file &image_chd)
1158 {
1159 	std::vector<software_info const *> parents;
1160 	std::vector<std::string> searchpath = make_software_searchpath(swlist, swinfo, parents);
1161 	searchpath.emplace_back(swlist.list_name()); // look for loose disk images in software list directory
1162 	return do_open_disk(options, { searchpath }, romp, image_chd, next_parent_software(parents));
1163 }
1164 
1165 
1166 /*-------------------------------------------------
1167     normalize_flags_for_device - modify the region
1168     flags for the given device
1169 -------------------------------------------------*/
1170 
normalize_flags_for_device(const char * rgntag,u8 & width,endianness_t & endian)1171 void rom_load_manager::normalize_flags_for_device(const char *rgntag, u8 &width, endianness_t &endian)
1172 {
1173 	device_t *device = machine().root_device().subdevice(rgntag);
1174 	device_memory_interface *memory;
1175 	if (device != nullptr && device->interface(memory))
1176 	{
1177 		const address_space_config *spaceconfig = memory->space_config();
1178 		if (spaceconfig != nullptr)
1179 		{
1180 			int buswidth;
1181 
1182 			/* set the endianness */
1183 			if (spaceconfig->endianness() == ENDIANNESS_LITTLE)
1184 				endian = ENDIANNESS_LITTLE;
1185 			else
1186 				endian = ENDIANNESS_BIG;
1187 
1188 			/* set the width */
1189 			buswidth = spaceconfig->data_width();
1190 			if (buswidth <= 8)
1191 				width = 1;
1192 			else if (buswidth <= 16)
1193 				width = 2;
1194 			else if (buswidth <= 32)
1195 				width = 4;
1196 			else
1197 				width = 8;
1198 		}
1199 	}
1200 }
1201 
1202 
1203 /*-------------------------------------------------
1204     load_software_part_region - load a software part
1205 
1206     This is used by MESS when loading a piece of
1207     software. The code should be merged with
1208     process_region_list or updated to use a slight
1209     more general process_region_list.
1210 -------------------------------------------------*/
1211 
load_software_part_region(device_t & device,software_list_device & swlist,const char * swname,const rom_entry * start_region)1212 void rom_load_manager::load_software_part_region(device_t &device, software_list_device &swlist, const char *swname, const rom_entry *start_region)
1213 {
1214 	m_errorstring.clear();
1215 	m_softwarningstring.clear();
1216 
1217 	m_romstotal = 0;
1218 	m_romstotalsize = 0;
1219 	m_romsloadedsize = 0;
1220 
1221 	std::vector<const software_info *> parents;
1222 	std::vector<std::string> swsearch, disksearch, devsearch;
1223 	const software_info *const swinfo = swlist.find(swname);
1224 	if (swinfo)
1225 	{
1226 		// dispay a warning for unsupported software
1227 		// TODO: list supported clones like we do for machines?
1228 		const u32 supported(swinfo->supported());
1229 		if (supported == SOFTWARE_SUPPORTED_PARTIAL)
1230 		{
1231 			m_errorstring.append(string_format("WARNING: support for software %s (in list %s) is only partial\n", swname, swlist.list_name()));
1232 			m_softwarningstring.append(string_format("Support for software %s (in list %s) is only partial\n", swname, swlist.list_name()));
1233 		}
1234 		if (supported == SOFTWARE_SUPPORTED_NO)
1235 		{
1236 			m_errorstring.append(string_format("WARNING: support for software %s (in list %s) is only preliminary\n", swname, swlist.list_name()));
1237 			m_softwarningstring.append(string_format("Support for software %s (in list %s) is only preliminary\n", swname, swlist.list_name()));
1238 		}
1239 
1240 		// walk the chain of parents and add them to the search path
1241 		swsearch = make_software_searchpath(swlist, *swinfo, parents);
1242 	}
1243 	else
1244 	{
1245 		swsearch.emplace_back(util::string_format("%s" PATH_SEPARATOR "%s", swlist.list_name(), swname));
1246 		swsearch.emplace_back(swname);
1247 	}
1248 
1249 	// this is convenient for CD-only lists so you don't need an extra level of directories containing one file each
1250 	disksearch.emplace_back(swlist.list_name());
1251 
1252 	// for historical reasons, add the search path for the software list device's owner
1253 	const device_t *const listowner = swlist.owner();
1254 	if (listowner)
1255 		devsearch = listowner->searchpath();
1256 
1257 	// loop until we hit the end
1258 	std::function<const rom_entry * ()> next_parent;
1259 	for (const rom_entry *region = start_region; region != nullptr; region = rom_next_region(region))
1260 	{
1261 		u32 regionlength = ROMREGION_GETLENGTH(region);
1262 
1263 		std::string regiontag = device.subtag(ROMREGION_GETTAG(region));
1264 		LOG("Processing region \"%s\" (length=%X)\n", regiontag.c_str(), regionlength);
1265 
1266 		// the first entry must be a region
1267 		assert(ROMENTRY_ISREGION(region));
1268 
1269 		// if this is a device region, override with the device width and endianness
1270 		endianness_t endianness = ROMREGION_ISBIGENDIAN(region) ? ENDIANNESS_BIG : ENDIANNESS_LITTLE;
1271 		u8 width = ROMREGION_GETWIDTH(region) / 8;
1272 		memory_region *memregion = machine().root_device().memregion(regiontag);
1273 		if (memregion != nullptr)
1274 		{
1275 			normalize_flags_for_device(regiontag.c_str(), width, endianness);
1276 
1277 			// clear old region (TODO: should be moved to an image unload function)
1278 			machine().memory().region_free(memregion->name());
1279 		}
1280 
1281 		// remember the base and length
1282 		m_region = machine().memory().region_alloc(regiontag.c_str(), regionlength, width, endianness);
1283 		LOG("Allocated %X bytes @ %p\n", m_region->bytes(), m_region->base());
1284 
1285 		if (ROMREGION_ISERASE(region)) // clear the region if it's requested
1286 			memset(m_region->base(), ROMREGION_GETERASEVAL(region), m_region->bytes());
1287 		else if (m_region->bytes() <= 0x400000) // or if it's sufficiently small (<= 4MB)
1288 			memset(m_region->base(), 0, m_region->bytes());
1289 #ifdef MAME_DEBUG
1290 		else // if we're debugging, fill region with random data to catch errors
1291 			fill_random(m_region->base(), m_region->bytes());
1292 #endif
1293 
1294 		// update total number of roms
1295 		for (const rom_entry *rom = rom_first_file(region); rom != nullptr; rom = rom_next_file(rom))
1296 		{
1297 			m_romstotal++;
1298 			m_romstotalsize += rom_file_size(rom);
1299 		}
1300 
1301 		// now process the entries in the region
1302 		if (ROMREGION_ISROMDATA(region))
1303 		{
1304 			if (devsearch.empty())
1305 				process_rom_entries({ swsearch }, 0U, region, region + 1, true);
1306 			else
1307 				process_rom_entries({ swsearch, devsearch }, 0U, region, region + 1, true);
1308 		}
1309 		else if (ROMREGION_ISDISKDATA(region))
1310 		{
1311 			if (!next_parent)
1312 			{
1313 				if (!parents.empty())
1314 					next_parent = next_parent_software(parents);
1315 				else
1316 					next_parent = [] () { return nullptr; };
1317 			}
1318 			if (devsearch.empty())
1319 				process_disk_entries({ swsearch, disksearch }, regiontag.c_str(), region + 1, next_parent);
1320 			else
1321 				process_disk_entries({ swsearch, disksearch, devsearch }, regiontag.c_str(), region + 1, next_parent);
1322 		}
1323 	}
1324 
1325 	// now go back and post-process all the regions
1326 	for (const rom_entry *region = start_region; region != nullptr; region = rom_next_region(region))
1327 		region_post_process(device.memregion(ROMREGION_GETTAG(region)), ROMREGION_ISINVERTED(region));
1328 
1329 	// display the results and exit
1330 	display_rom_load_results(true);
1331 }
1332 
1333 
1334 /*-------------------------------------------------
1335     process_region_list - process a region list
1336 -------------------------------------------------*/
1337 
process_region_list()1338 void rom_load_manager::process_region_list()
1339 {
1340 	// loop until we hit the end
1341 	device_iterator deviter(machine().root_device());
1342 	std::vector<std::string> searchpath;
1343 	for (device_t &device : deviter)
1344 	{
1345 		searchpath.clear();
1346 		std::function<const rom_entry * ()> next_parent;
1347 		for (const rom_entry *region = rom_first_region(device); region != nullptr; region = rom_next_region(region))
1348 		{
1349 			u32 regionlength = ROMREGION_GETLENGTH(region);
1350 
1351 			std::string regiontag = device.subtag(ROM_GETNAME(region));
1352 			LOG("Processing region \"%s\" (length=%X)\n", regiontag.c_str(), regionlength);
1353 
1354 			// the first entry must be a region
1355 			assert(ROMENTRY_ISREGION(region));
1356 
1357 			if (ROMREGION_ISROMDATA(region))
1358 			{
1359 				// if this is a device region, override with the device width and endianness
1360 				u8 width = ROMREGION_GETWIDTH(region) / 8;
1361 				endianness_t endianness = ROMREGION_ISBIGENDIAN(region) ? ENDIANNESS_BIG : ENDIANNESS_LITTLE;
1362 				normalize_flags_for_device(regiontag.c_str(), width, endianness);
1363 
1364 				// remember the base and length
1365 				m_region = machine().memory().region_alloc(regiontag.c_str(), regionlength, width, endianness);
1366 				LOG("Allocated %X bytes @ %p\n", m_region->bytes(), m_region->base());
1367 
1368 				if (ROMREGION_ISERASE(region)) // clear the region if it's requested
1369 					memset(m_region->base(), ROMREGION_GETERASEVAL(region), m_region->bytes());
1370 				else if (m_region->bytes() <= 0x400000) // or if it's sufficiently small (<= 4MB)
1371 					memset(m_region->base(), 0, m_region->bytes());
1372 #ifdef MAME_DEBUG
1373 				else // if we're debugging, fill region with random data to catch errors
1374 					fill_random(m_region->base(), m_region->bytes());
1375 #endif
1376 
1377 				// now process the entries in the region
1378 				if (searchpath.empty())
1379 					searchpath = device.searchpath();
1380 				assert(!searchpath.empty());
1381 				process_rom_entries({ searchpath }, device.system_bios(), region, region + 1, false);
1382 			}
1383 			else if (ROMREGION_ISDISKDATA(region))
1384 			{
1385 				if (searchpath.empty())
1386 					searchpath = device.searchpath();
1387 				assert(!searchpath.empty());
1388 				if (!next_parent)
1389 				{
1390 					driver_device const *const driver(dynamic_cast<driver_device const *>(&device));
1391 					if (driver)
1392 						next_parent = next_parent_system(driver->system());
1393 					else
1394 						next_parent = [] () { return nullptr; };
1395 				}
1396 				process_disk_entries({ searchpath }, regiontag.c_str(), region + 1, next_parent);
1397 			}
1398 		}
1399 	}
1400 
1401 	// now go back and post-process all the regions
1402 	for (device_t &device : deviter)
1403 		for (const rom_entry *region = rom_first_region(device); region != nullptr; region = rom_next_region(region))
1404 			region_post_process(device.memregion(ROM_GETNAME(region)), ROMREGION_ISINVERTED(region));
1405 
1406 	// and finally register all per-game parameters
1407 	for (device_t &device : deviter)
1408 	{
1409 		for (const rom_entry *param = rom_first_parameter(device); param != nullptr; param = rom_next_parameter(param))
1410 		{
1411 			std::string regiontag = device.subtag(param->name());
1412 			machine().parameters().add(regiontag, param->hashdata());
1413 		}
1414 	}
1415 }
1416 
1417 
1418 /*-------------------------------------------------
1419     rom_init - load the ROMs and open the disk
1420     images associated with the given machine
1421 -------------------------------------------------*/
1422 
rom_load_manager(running_machine & machine)1423 rom_load_manager::rom_load_manager(running_machine &machine)
1424 	: m_machine(machine)
1425 	, m_warnings(0)
1426 	, m_knownbad(0)
1427 	, m_errors(0)
1428 	, m_romsloaded(0)
1429 	, m_romstotal(0)
1430 	, m_romsloadedsize(0)
1431 	, m_romstotalsize(0)
1432 	, m_chd_list()
1433 	, m_region(nullptr)
1434 	, m_errorstring()
1435 	, m_softwarningstring()
1436 {
1437 	// figure out which BIOS we are using
1438 	std::map<std::string, std::string> card_bios;
1439 	for (device_t &device : device_iterator(machine.config().root_device()))
1440 	{
1441 		device_slot_interface const *const slot(dynamic_cast<device_slot_interface *>(&device));
1442 		if (slot)
1443 		{
1444 			device_t const *const card(slot->get_card_device());
1445 			slot_option const &slot_opt(machine.options().slot_option(slot->slot_name()));
1446 			if (card && !slot_opt.bios().empty())
1447 				card_bios.emplace(std::make_pair(std::string(card->tag()), slot_opt.bios()));
1448 		}
1449 
1450 		if (device.rom_region())
1451 		{
1452 			std::string specbios;
1453 			if (!device.owner())
1454 			{
1455 				specbios = machine.options().bios();
1456 			}
1457 			else
1458 			{
1459 				auto const found(card_bios.find(device.tag()));
1460 				if (card_bios.end() != found)
1461 				{
1462 					specbios = std::move(found->second);
1463 					card_bios.erase(found);
1464 				}
1465 			}
1466 			determine_bios_rom(device, specbios.c_str());
1467 		}
1468 	}
1469 
1470 	// count the total number of ROMs
1471 	count_roms();
1472 
1473 	// reset the disk list
1474 	m_chd_list.clear();
1475 
1476 	// process the ROM entries we were passed
1477 	process_region_list();
1478 
1479 	// display the results and exit
1480 	display_rom_load_results(false);
1481 }
1482 
1483 
1484 // -------------------------------------------------
1485 // rom_build_entries - builds a rom_entry vector
1486 // from a tiny_rom_entry array
1487 // -------------------------------------------------
1488 
rom_build_entries(const tiny_rom_entry * tinyentries)1489 std::vector<rom_entry> rom_build_entries(const tiny_rom_entry *tinyentries)
1490 {
1491 	std::vector<rom_entry> result;
1492 	if (tinyentries)
1493 	{
1494 		int i = 0;
1495 		do
1496 		{
1497 			result.emplace_back(tinyentries[i]);
1498 		}
1499 		while (!ROMENTRY_ISEND(tinyentries[i++]));
1500 	}
1501 	else
1502 	{
1503 		tiny_rom_entry const end_entry = { nullptr, nullptr, 0, 0, ROMENTRYTYPE_END };
1504 		result.emplace_back(end_entry);
1505 	}
1506 	return result;
1507 }
1508