diff options
Diffstat (limited to 'src/emu/hashfile.cpp')
-rw-r--r-- | src/emu/hashfile.cpp | 549 |
1 files changed, 30 insertions, 519 deletions
diff --git a/src/emu/hashfile.cpp b/src/emu/hashfile.cpp index 0d41f278f37..1d3a2b63171 100644 --- a/src/emu/hashfile.cpp +++ b/src/emu/hashfile.cpp @@ -10,549 +10,60 @@ #include "hashfile.h" #include "pool.h" -#include "expat.h" #include "emuopts.h" #include "hash.h" #include "drivenum.h" - - -/*************************************************************************** - TYPE DEFINITIONS -***************************************************************************/ - -struct hash_info -{ - hash_collection *hashes; - const char *extrainfo; -}; - -struct hash_file; - -typedef void (*hashfile_error_func)(const char *message); - - - -/*************************************************************************** - FUNCTION PROTOTYPES -***************************************************************************/ - -/* opens a hash file; if is_preload is non-zero, the entire file is preloaded */ -hash_file *hashfile_open(emu_options &options, const char *sysname, int is_preload, hashfile_error_func error_proc); - -/* closes a hash file and associated resources */ -void hashfile_close(hash_file *hashfile); - -/* looks up information in a hash file */ -const hash_info *hashfile_lookup(hash_file *hashfile, const hash_collection *hashes); - -/*************************************************************************** - TYPE DEFINITIONS -***************************************************************************/ - -struct hash_file -{ - emu_file *file; - object_pool *pool; - - hash_info **preloaded_hashes; - int preloaded_hash_count; - - void (*error_proc)(const char *message); -}; - - - -enum hash_parse_position -{ - HASH_POS_ROOT, - HASH_POS_MAIN, - HASH_POS_HASH -}; - - - -struct hash_parse_state -{ - XML_Parser parser; - hash_file *hashfile; - int done; - - int (*selector_proc)(hash_file *hashfile, void *param, const char *name, const hash_collection *hashes); - void (*use_proc)(hash_file *hashfile, void *param, hash_info *hi); - void (*error_proc)(const char *message); - void *param; - - enum hash_parse_position pos; - char **text_dest; - hash_info *hi; -}; - - - -/*************************************************************************** - CORE IMPLEMENTATION -***************************************************************************/ +#define PUGIXML_HEADER_ONLY +#include "pugixml/src/pugixml.hpp" /*------------------------------------------------- - parse_error --------------------------------------------------*/ - -static void ATTR_PRINTF(2,3) parse_error(struct hash_parse_state *state, const char *fmt, ...) -{ - char buf[256]; - va_list va; - - if (state->error_proc) - { - va_start(va, fmt); - vsnprintf(buf, ARRAY_LENGTH(buf), fmt, va); - va_end(va); - (*state->error_proc)(buf); - } -} - - - -/*------------------------------------------------- - unknown_tag --------------------------------------------------*/ - -static void unknown_tag(struct hash_parse_state *state, const char *tagname) -{ - parse_error(state, "[%lu:%lu]: Unknown tag: %s\n", - XML_GetCurrentLineNumber(state->parser), - XML_GetCurrentColumnNumber(state->parser), - tagname); -} - - - -/*------------------------------------------------- - unknown_attribute --------------------------------------------------*/ - -static void unknown_attribute(struct hash_parse_state *state, const char *attrname) -{ - parse_error(state, "[%lu:%lu]: Unknown attribute: %s\n", - XML_GetCurrentLineNumber(state->parser), - XML_GetCurrentColumnNumber(state->parser), - attrname); -} - - - -/*------------------------------------------------- - unknown_attribute_value --------------------------------------------------*/ - -static void unknown_attribute_value(struct hash_parse_state *state, - const char *attrname, const char *attrvalue) -{ - parse_error(state, "[%lu:%lu]: Unknown attribute value: %s\n", - XML_GetCurrentLineNumber(state->parser), - XML_GetCurrentColumnNumber(state->parser), - attrvalue); -} - - - -/*------------------------------------------------- - start_handler --------------------------------------------------*/ - -static void start_handler(void *data, const char *tagname, const char **attributes) -{ - struct hash_parse_state *state = (struct hash_parse_state *) data; - const char *name; - hash_info *hi; - char **text_dest; - hash_collection hashes; - std::string all_functions; - char functions; -// iodevice_t device; - int i; - - switch(state->pos) - { - case HASH_POS_ROOT: - if (!strcmp(tagname, "hashfile")) - { - } - else - { - unknown_tag(state, tagname); - } - break; - - case HASH_POS_MAIN: - if (!strcmp(tagname, "hash")) - { - // we are now examining a hash tag - name = nullptr; -// device = IO_COUNT; - - while(attributes[0]) - { - functions = 0; - if (!strcmp(attributes[0], "name")) - { - /* name attribute */ - name = attributes[1]; - } - else if (!strcmp(attributes[0], "crc32")) - { - /* crc32 attribute */ - functions = hash_collection::HASH_CRC; - } - else if (!strcmp(attributes[0], "sha1")) - { - /* sha1 attribute */ - functions = hash_collection::HASH_SHA1; - } - else if (!strcmp(attributes[0], "type")) - { - /* type attribute */ - i = 0;//device_typeid(attributes[1]); - if (i < 0) - unknown_attribute_value(state, attributes[0], attributes[1]); - else - { - // device = (iodevice_t) i; - } - } - else - { - /* unknown attribute */ - unknown_attribute(state, attributes[0]); - } - - if (functions) - { - hashes.add_from_string(functions, attributes[1], strlen(attributes[1])); - all_functions.append(1, functions); - } - - attributes += 2; - } - - /* do we use this hash? */ - if (!state->selector_proc || state->selector_proc(state->hashfile, state->param, name, &hashes)) - { - hi = (hash_info*)pool_malloc_lib(state->hashfile->pool, sizeof(hash_info)); - if (!hi) - return; - memset(hi, 0, sizeof(*hi)); - - hi->hashes = &hashes; - state->hi = hi; - } - } - else - { - unknown_tag(state, tagname); - } - break; - - case HASH_POS_HASH: - text_dest = nullptr; - - if (!strcmp(tagname, "year")) { - } - else if (!strcmp(tagname, "manufacturer")){ - } - else if (!strcmp(tagname, "status")){ - } - else if (!strcmp(tagname, "pcb")){ - } - else if (!strcmp(tagname, "extrainfo")) { - text_dest = (char **) &state->hi->extrainfo; - } - else - unknown_tag(state, tagname); - - if (text_dest && state->hi) - state->text_dest = text_dest; - break; - } - state->pos = (hash_parse_position) (state->pos + 1); -} - - - -/*------------------------------------------------- - end_handler --------------------------------------------------*/ - -static void end_handler(void *data, const char *name) -{ - struct hash_parse_state *state = (struct hash_parse_state *) data; - state->text_dest = nullptr; - - state->pos = (hash_parse_position) (state->pos - 1); - switch(state->pos) - { - case HASH_POS_ROOT: - case HASH_POS_HASH: - break; - - case HASH_POS_MAIN: - if (state->hi) - { - if (state->use_proc) - (*state->use_proc)(state->hashfile, state->param, state->hi); - state->hi = nullptr; - } - break; - } -} - - - -/*------------------------------------------------- - data_handler + hashfile_lookup -------------------------------------------------*/ -static void data_handler(void *data, const XML_Char *s, int len) +bool read_hash_config(device_image_interface &image, const char *sysname, std::string &result) { - struct hash_parse_state *state = (struct hash_parse_state *) data; - int text_len; - char *text; - - if (state->text_dest) + /* open a file */ + emu_file file(image.device().mconfig().options().hash_path(), OPEN_FLAG_READ); + if (file.open(sysname, ".hsi") != osd_file::error::NONE) { - text = *state->text_dest; - - text_len = text ? strlen(text) : 0; - text = (char*)pool_realloc_lib(state->hashfile->pool, text, text_len + len + 1); - if (!text) - return; - - memcpy(&text[text_len], s, len); - text[text_len + len] = '\0'; - *state->text_dest = text; + return false; } -} - - - -/*------------------------------------------------- - hashfile_parse --------------------------------------------------*/ - -static void hashfile_parse(hash_file *hashfile, - int (*selector_proc)(hash_file *hashfile, void *param, const char *name, const hash_collection *hashes), - void (*use_proc)(hash_file *hashfile, void *param, hash_info *hi), - void (*error_proc)(const char *message), - void *param) -{ - struct hash_parse_state state; - char buf[1024]; - UINT32 len; - hashfile->file->seek(0, SEEK_SET); - memset(&state, 0, sizeof(state)); - state.hashfile = hashfile; - state.selector_proc = selector_proc; - state.use_proc = use_proc; - state.error_proc = error_proc; - state.param = param; + pugi::xml_document doc; - /* create the XML parser */ - state.parser = XML_ParserCreate_MM(nullptr, nullptr, nullptr); - if (!state.parser) - goto done; - - XML_SetUserData(state.parser, &state); - XML_SetElementHandler(state.parser, start_handler, end_handler); - XML_SetCharacterDataHandler(state.parser, data_handler); - - while(!state.done) + pugi::xml_parse_result res = doc.load_file(file.fullpath()); + if (res) { - len = hashfile->file->read(buf, sizeof(buf)); - state.done = hashfile->file->eof(); - if (XML_Parse(state.parser, buf, len, state.done) == XML_STATUS_ERROR) + // Do search by CRC32 and SHA1 + std::string query = "/hashfile/hash["; + auto crc = image.hash().internal_string().substr(1,8); + auto sha1 = image.hash().internal_string().substr(10, 40); + query += "@crc32='" + crc + "' and @sha1='" + sha1 + "']/extrainfo"; + pugi::xpath_node_set tools = doc.select_nodes(query.c_str()); + for (pugi::xpath_node_set::const_iterator it = tools.begin(); it != tools.end(); ++it) { - parse_error(&state, "[%lu:%lu]: %s\n", - XML_GetCurrentLineNumber(state.parser), - XML_GetCurrentColumnNumber(state.parser), - XML_ErrorString(XML_GetErrorCode(state.parser))); - goto done; + result = it->node().first_child().value(); + return true; } - } - -done: - if (state.parser) - XML_ParserFree(state.parser); -} - - - -/*------------------------------------------------- - preload_use_proc --------------------------------------------------*/ - -static void preload_use_proc(hash_file *hashfile, void *param, hash_info *hi) -{ - hash_info **new_preloaded_hashes; - - new_preloaded_hashes = (hash_info **)pool_realloc_lib(hashfile->pool, hashfile->preloaded_hashes, - (hashfile->preloaded_hash_count + 1) * sizeof(*new_preloaded_hashes)); - if (!new_preloaded_hashes) - return; - - hashfile->preloaded_hashes = new_preloaded_hashes; - hashfile->preloaded_hashes[hashfile->preloaded_hash_count++] = hi; -} - - - -/*------------------------------------------------- - hashfile_open --------------------------------------------------*/ - -hash_file *hashfile_open(emu_options &options, const char *sysname, int is_preload, - void (*error_proc)(const char *message)) -{ - hash_file *hashfile = nullptr; - object_pool *pool = nullptr; - osd_file::error filerr; - - /* create a pool for this hash file */ - pool = pool_alloc_lib(error_proc); - if (!pool) - goto error; - - /* allocate space for this hash file */ - hashfile = (hash_file *) pool_malloc_lib(pool, sizeof(*hashfile)); - if (!hashfile) - goto error; - - /* set up the hashfile structure */ - memset(hashfile, 0, sizeof(*hashfile)); - hashfile->pool = pool; - hashfile->error_proc = error_proc; - - /* open a file */ - hashfile->file = global_alloc(emu_file(options.hash_path(), OPEN_FLAG_READ)); - filerr = hashfile->file->open(sysname, ".hsi"); - if (filerr != osd_file::error::NONE) - { - global_free(hashfile->file); - hashfile->file = nullptr; - goto error; - } - - if (is_preload) - hashfile_parse(hashfile, nullptr, preload_use_proc, hashfile->error_proc, nullptr); - - return hashfile; - -error: - if (hashfile != nullptr) - hashfile_close(hashfile); - return nullptr; -} - - - -/*------------------------------------------------- - hashfile_close --------------------------------------------------*/ - -void hashfile_close(hash_file *hashfile) -{ - global_free(hashfile->file); - pool_free_lib(hashfile->pool); -} - - - -/*------------------------------------------------- - singular_selector_proc --------------------------------------------------*/ - -struct hashlookup_params -{ - const hash_collection *hashes; - hash_info *hi; -}; - -static int singular_selector_proc(hash_file *hashfile, void *param, const char *name, const hash_collection *hashes) -{ - struct hashlookup_params *hlparams = (struct hashlookup_params *) param; - return (*hashes == *hlparams->hashes); -} - - - -/*------------------------------------------------- - singular_use_proc --------------------------------------------------*/ - -static void singular_use_proc(hash_file *hashfile, void *param, hash_info *hi) -{ - struct hashlookup_params *hlparams = (struct hashlookup_params *) param; - hlparams->hi = hi; -} - - -/*------------------------------------------------- - hashfile_lookup --------------------------------------------------*/ - -const hash_info *hashfile_lookup(hash_file *hashfile, const hash_collection *hashes) -{ - struct hashlookup_params param; - int i; - - param.hashes = hashes; - param.hi = nullptr; - - for (i = 0; i < hashfile->preloaded_hash_count; i++) - { - if (singular_selector_proc(hashfile, ¶m, nullptr, hashfile->preloaded_hashes[i]->hashes)) - return hashfile->preloaded_hashes[i]; - } - - hashfile_parse(hashfile, singular_selector_proc, singular_use_proc, - hashfile->error_proc, (void *) ¶m); - return param.hi; -} - -const char *extra_info = nullptr; - -bool read_hash_config(device_image_interface &image, const char *sysname, std::string &result) -{ - hash_file *hashfile; - const hash_info *info; - - /* open the hash file */ - hashfile = hashfile_open(image.device().mconfig().options(), sysname, FALSE, nullptr); - if (!hashfile) - return false; - - /* look up this entry in the hash file */ - info = hashfile_lookup(hashfile, &image.hash()); + // Try search by CRC32 only + query = "/hashfile/hash["; + query += "@crc32='" + crc + "']/extrainfo"; + tools = doc.select_nodes(query.c_str()); + for (pugi::xpath_node_set::const_iterator it = tools.begin(); it != tools.end(); ++it) + { + result = it->node().first_child().value(); + return true; + } - if (!info || !info->extrainfo) - { - hashfile_close(hashfile); - return false; } - - result.assign(info->extrainfo); - - /* copy the relevant entries */ - hashfile_close(hashfile); - return true; + return false; } bool hashfile_extrainfo(device_image_interface &image, std::string &result) { /* now read the hash file */ image.crc(); - extra_info = nullptr; int drv = driver_list::find(image.device().mconfig().gamedrv()); int compat, open = drv; bool hashfound; |