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