summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/hashfile.c
diff options
context:
space:
mode:
author Miodrag Milanovic <mmicko@gmail.com>2010-06-17 06:57:05 +0000
committer Miodrag Milanovic <mmicko@gmail.com>2010-06-17 06:57:05 +0000
commitd2a7b5f332d42f1a7d47102cecd4dcadd3d15acd (patch)
tree5e9a339c1cbcdce22804b3f87695b2c8725ebc40 /src/emu/hashfile.c
parent861db1eb49e7d1734d07ae8aafce2b6fdd88fece (diff)
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)mame0138u2
Diffstat (limited to 'src/emu/hashfile.c')
-rw-r--r--src/emu/hashfile.c591
1 files changed, 591 insertions, 0 deletions
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, &param, NULL, hashfile->preloaded_hashes[i]->hash))
+ return hashfile->preloaded_hashes[i];
+ }
+
+ hashfile_parse(hashfile, singular_selector_proc, singular_use_proc,
+ hashfile->error_proc, (void *) &param);
+ 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);
+}