From d2a7b5f332d42f1a7d47102cecd4dcadd3d15acd Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 17 Jun 2010 06:57:05 +0000 Subject: hashfile moved from MESS to emu section (needed for now in image support until softlist implementation is finished), this doesn't affect mame side (no whatsnew) --- src/emu/emu.mak | 1 + src/emu/hashfile.c | 591 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/emu/hashfile.h | 62 ++++++ 3 files changed, 654 insertions(+) create mode 100644 src/emu/hashfile.c create mode 100644 src/emu/hashfile.h (limited to 'src') diff --git a/src/emu/emu.mak b/src/emu/emu.mak index 91c964f2a83..55e0923f6be 100644 --- a/src/emu/emu.mak +++ b/src/emu/emu.mak @@ -63,6 +63,7 @@ EMUOBJS = \ $(EMUOBJ)/emupal.o \ $(EMUOBJ)/fileio.o \ $(EMUOBJ)/hash.o \ + $(EMUOBJ)/hashfile.o \ $(EMUOBJ)/info.o \ $(EMUOBJ)/input.o \ $(EMUOBJ)/inputseq.o \ diff --git a/src/emu/hashfile.c b/src/emu/hashfile.c new file mode 100644 index 00000000000..021c1cc21ef --- /dev/null +++ b/src/emu/hashfile.c @@ -0,0 +1,591 @@ +/********************************************************************* + + hashfile.c + + Code for parsing hash info (*.hsi) files + +*********************************************************************/ + +#include "hashfile.h" +#include "pool.h" +#include "expat.h" +#include "emuopts.h" +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +struct _hash_file +{ + mame_file *file; + object_pool *pool; + unsigned int functions[IO_COUNT]; + + hash_info **preloaded_hashes; + int preloaded_hash_count; + + void (*error_proc)(const char *message); +}; + + + +enum hash_parse_position +{ + POS_ROOT, + POS_MAIN, + 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 char *hash); + 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; +}; + + + +/*************************************************************************** + PROTOTYPES +***************************************************************************/ + +static void *expat_malloc(size_t size); +static void *expat_realloc(void *ptr, size_t size); +static void expat_free(void *ptr); + + + +/*************************************************************************** + CORE IMPLEMENTATION +***************************************************************************/ + +/*------------------------------------------------- + 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; + char hash_string[HASH_BUF_SIZE]; + unsigned int functions, all_functions; + iodevice_t device; + int i; + + switch(state->pos) + { + case POS_ROOT: + if (!strcmp(tagname, "hashfile")) + { + } + else + { + unknown_tag(state, tagname); + } + break; + + case POS_MAIN: + if (!strcmp(tagname, "hash")) + { + // we are now examining a hash tag + name = NULL; + memset(hash_string, 0, sizeof(hash_string)); + all_functions = 0; + 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_CRC; + } + else if (!strcmp(attributes[0], "md5")) + { + /* md5 attribute */ + functions = HASH_MD5; + } + else if (!strcmp(attributes[0], "sha1")) + { + /* sha1 attribute */ + functions = 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) + { + hash_data_insert_printable_checksum(hash_string, functions, attributes[1]); + all_functions |= functions; + } + + attributes += 2; + } + + if (device == IO_COUNT) + { + for (i = 0; i < IO_COUNT; i++) + state->hashfile->functions[i] |= all_functions; + } + else + state->hashfile->functions[device] |= all_functions; + + /* do we use this hash? */ + if (!state->selector_proc || state->selector_proc(state->hashfile, state->param, name, hash_string)) + { + hi = (hash_info*)pool_malloc_lib(state->hashfile->pool, sizeof(hash_info)); + if (!hi) + return; + memset(hi, 0, sizeof(*hi)); + + hi->longname = pool_strdup_lib(state->hashfile->pool, name); + if (!hi->longname) + return; + + strcpy(hi->hash, hash_string); + state->hi = hi; + } + } + else + { + unknown_tag(state, tagname); + } + break; + + case POS_HASH: + text_dest = NULL; + + if (!strcmp(tagname, "year")) + text_dest = (char **) &state->hi->year; + else if (!strcmp(tagname, "manufacturer")) + text_dest = (char **) &state->hi->manufacturer; + else if (!strcmp(tagname, "status")) + text_dest = (char **) &state->hi->playable; + else if (!strcmp(tagname, "pcb")) + text_dest = (char **) &state->hi->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 = NULL; + + state->pos = (hash_parse_position) (state->pos - 1); + switch(state->pos) + { + case POS_ROOT: + case POS_HASH: + break; + + case POS_MAIN: + if (state->hi) + { + if (state->use_proc) + (*state->use_proc)(state->hashfile, state->param, state->hi); + state->hi = NULL; + } + break; + } +} + + + +/*------------------------------------------------- + data_handler +-------------------------------------------------*/ + +static void data_handler(void *data, const XML_Char *s, int len) +{ + struct hash_parse_state *state = (struct hash_parse_state *) data; + int text_len; + char *text; + + if (state->text_dest) + { + 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; + } +} + + + +/*------------------------------------------------- + hashfile_parse +-------------------------------------------------*/ + +static void hashfile_parse(hash_file *hashfile, + int (*selector_proc)(hash_file *hashfile, void *param, const char *name, const char *hash), + 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; + XML_Memory_Handling_Suite memcallbacks; + + mame_fseek(hashfile->file, 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; + + /* create the XML parser */ + memcallbacks.malloc_fcn = expat_malloc; + memcallbacks.realloc_fcn = expat_realloc; + memcallbacks.free_fcn = expat_free; + state.parser = XML_ParserCreate_MM(NULL, &memcallbacks, NULL); + 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) + { + len = mame_fread(hashfile->file, buf, sizeof(buf)); + state.done = mame_feof(hashfile->file); + if (XML_Parse(state.parser, buf, len, state.done) == XML_STATUS_ERROR) + { + parse_error(&state, "[%lu:%lu]: %s\n", + XML_GetCurrentLineNumber(state.parser), + XML_GetCurrentColumnNumber(state.parser), + XML_ErrorString(XML_GetErrorCode(state.parser))); + goto done; + } + } + +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_options +-------------------------------------------------*/ + +hash_file *hashfile_open_options(core_options *opts, const char *sysname, int is_preload, + void (*error_proc)(const char *message)) +{ + file_error filerr; + astring *fname; + hash_file *hashfile = NULL; + object_pool *pool = NULL; + + /* 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 */ + fname = astring_assemble_2(astring_alloc(), sysname, ".hsi"); + filerr = mame_fopen_options(opts, SEARCHPATH_HASH, astring_c(fname), OPEN_FLAG_READ, &hashfile->file); + astring_free(fname); + + if (filerr != FILERR_NONE) + goto error; + + if (is_preload) + hashfile_parse(hashfile, NULL, preload_use_proc, hashfile->error_proc, NULL); + + return hashfile; + +error: + if (hashfile != NULL) + hashfile_close(hashfile); + return NULL; +} + + + +/*------------------------------------------------- + hashfile_open +-------------------------------------------------*/ + +hash_file *hashfile_open(const char *sysname, int is_preload, + void (*error_proc)(const char *message)) +{ + return hashfile_open_options(mame_options(), sysname, is_preload, error_proc); +} + + + +/*------------------------------------------------- + hashfile_close +-------------------------------------------------*/ + +void hashfile_close(hash_file *hashfile) +{ + if (hashfile->file) + mame_fclose(hashfile->file); + pool_free_lib(hashfile->pool); +} + + + +/*------------------------------------------------- + singular_selector_proc +-------------------------------------------------*/ + +struct hashlookup_params +{ + const char *hash; + hash_info *hi; +}; + +static int singular_selector_proc(hash_file *hashfile, void *param, const char *name, const char *hash) +{ + struct hashlookup_params *hlparams = (struct hashlookup_params *) param; + return hash_data_is_equal(hash, hlparams->hash, + hash_data_used_functions(hash)) == 1; +} + + + +/*------------------------------------------------- + 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 char *hash) +{ + struct hashlookup_params param; + int i; + + param.hash = hash; + param.hi = NULL; + + for (i = 0; i < hashfile->preloaded_hash_count; i++) + { + if (singular_selector_proc(hashfile, ¶m, NULL, hashfile->preloaded_hashes[i]->hash)) + return hashfile->preloaded_hashes[i]; + } + + hashfile_parse(hashfile, singular_selector_proc, singular_use_proc, + hashfile->error_proc, (void *) ¶m); + return param.hi; +} + + + +/*------------------------------------------------- + hashfile_functions_used +-------------------------------------------------*/ + +unsigned int hashfile_functions_used(hash_file *hashfile, iodevice_t devtype) +{ + assert(devtype >= 0); + assert(devtype < IO_COUNT); + return hashfile->functions[devtype]; +} + + + +/*------------------------------------------------- + hashfile_verify +-------------------------------------------------*/ + +int hashfile_verify(const char *sysname, void (*my_error_proc)(const char *message)) +{ + hash_file *hashfile; + + hashfile = hashfile_open(sysname, FALSE, my_error_proc); + if (!hashfile) + return -1; + + hashfile_parse(hashfile, NULL, NULL, my_error_proc, NULL); + hashfile_close(hashfile); + return 0; +} + + + +/*************************************************************************** + EXPAT INTERFACES +***************************************************************************/ + +/*------------------------------------------------- + expat_malloc/expat_realloc/expat_free - + wrappers for memory allocation functions so + that they pass through out memory tracking + systems +-------------------------------------------------*/ + +static void *expat_malloc(size_t size) +{ + return global_alloc_array_clear(UINT8,size); +} + +static void *expat_realloc(void *ptr, size_t size) +{ + if (ptr) global_free(ptr); + return global_alloc_array_clear(UINT8,size); +} + +static void expat_free(void *ptr) +{ + global_free(ptr); +} diff --git a/src/emu/hashfile.h b/src/emu/hashfile.h new file mode 100644 index 00000000000..23467d17b5d --- /dev/null +++ b/src/emu/hashfile.h @@ -0,0 +1,62 @@ +/********************************************************************* + + hashfile.h + + Code for parsing hash info (*.hsi) files + +*********************************************************************/ + +#ifndef __HASHFILE_H__ +#define __HASHFILE_H__ + +#include "emu.h" +#include "hash.h" + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +typedef struct _hash_info hash_info; +struct _hash_info +{ + char hash[HASH_BUF_SIZE]; + const char *longname; + const char *manufacturer; + const char *year; + const char *playable; + const char *pcb; + const char *extrainfo; +}; + +typedef struct _hash_file 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(const char *sysname, int is_preload, hashfile_error_func error_proc); + +/* opens a hash file; if is_preload is non-zero, the entire file is preloaded */ +hash_file *hashfile_open_options(core_options *opts, 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 char *hash); + +/* performs a syntax check on a hash file */ +int hashfile_verify(const char *sysname, void (*error_proc)(const char *message)); + +/* returns the functions used in this hash file */ +unsigned int hashfile_functions_used(hash_file *hashfile, iodevice_t devtype); + + +#endif /* __HASHFILE_H__ */ -- cgit v1.2.3