1 // license:BSD-3-Clause
2 // copyright-holders:Nathan Woods
3 /*********************************************************************
4 
5     hashfile.cpp
6 
7     Code for parsing hash info (*.hsi) files
8 
9 *********************************************************************/
10 
11 #include "emu.h"
12 #include "hashfile.h"
13 
14 #include "drivenum.h"
15 #include "emuopts.h"
16 
17 #include "hash.h"
18 #include "pool.h"
19 
20 #include <pugixml.hpp>
21 
22 
23 /*-------------------------------------------------
24     hashfile_lookup
25 -------------------------------------------------*/
26 
read_hash_config(const char * hash_path,const util::hash_collection & hashes,const char * sysname,std::string & result)27 static bool read_hash_config(const char *hash_path, const util::hash_collection &hashes, const char *sysname, std::string &result)
28 {
29 	/* open a file */
30 	emu_file file(hash_path, OPEN_FLAG_READ);
31 	if (file.open(std::string(sysname) + ".hsi") != osd_file::error::NONE)
32 	{
33 		return false;
34 	}
35 
36 	pugi::xml_document doc;
37 
38 	pugi::xml_parse_result res = doc.load_file(file.fullpath());
39 	if (res)
40 	{
41 		// Do search by CRC32 and SHA1
42 		std::string query = "/hashfile/hash[";
43 		auto crc = hashes.internal_string().substr(1,8);
44 		auto sha1 = hashes.internal_string().substr(10, 40);
45 		query += "@crc32='" + crc + "' and @sha1='" + sha1 + "']/extrainfo";
46 		pugi::xpath_node_set tools = doc.select_nodes(query.c_str());
47 		for (pugi::xpath_node_set::const_iterator it = tools.begin(); it != tools.end(); ++it)
48 		{
49 			result = it->node().first_child().value();
50 			return true;
51 		}
52 
53 		// Try search by CRC32 only
54 		query = "/hashfile/hash[";
55 		query += "@crc32='" + crc + "']/extrainfo";
56 		tools = doc.select_nodes(query.c_str());
57 		for (pugi::xpath_node_set::const_iterator it = tools.begin(); it != tools.end(); ++it)
58 		{
59 			result = it->node().first_child().value();
60 			return true;
61 		}
62 
63 	}
64 	return false;
65 }
66 
67 
hashfile_extrainfo(const char * hash_path,const game_driver & driver,const util::hash_collection & hashes,std::string & result)68 bool hashfile_extrainfo(const char *hash_path, const game_driver &driver, const util::hash_collection &hashes, std::string &result)
69 {
70 	/* now read the hash file */
71 	int drv = driver_list::find(driver);
72 	int compat, open = drv;
73 	bool hashfound;
74 	do
75 	{
76 		hashfound = read_hash_config(hash_path, hashes, driver_list::driver(open).name, result);
77 		// first check if there are compatible systems
78 		compat = driver_list::compatible_with(open);
79 		// if so, try to open its hashfile
80 		if (compat != -1)
81 			open = compat;
82 		// otherwise, try with the parent
83 		else
84 		{
85 			drv = driver_list::clone(drv);
86 			open = drv;
87 		}
88 	}
89 	// if no extrainfo has been found but we can try a compatible or a parent set, go back
90 	while (!hashfound && open != -1);
91 	return hashfound;
92 }
93 
94 
95 
hashfile_extrainfo(device_image_interface & image,std::string & result)96 bool hashfile_extrainfo(device_image_interface &image, std::string &result)
97 {
98 	return hashfile_extrainfo(
99 		image.device().mconfig().options().hash_path(),
100 		image.device().mconfig().gamedrv(),
101 		image.hash(),
102 		result);
103 }
104 
105 
106